Skip to content

Commit 6cdc2af

Browse files
【update】ol 支持加载包含相对地址的style review by luox
1 parent c2230ee commit 6cdc2af

File tree

7 files changed

+231
-22
lines changed

7 files changed

+231
-22
lines changed

src/common/commontypes/Util.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,6 +1086,34 @@ const Util = {
10861086
}
10871087
return encodeURIComponent(value);
10881088
});
1089+
},
1090+
/**
1091+
* @description 是否是绝对地址。
1092+
* @private
1093+
* @param {string} url - 验证地址。
1094+
* @returns {boolean} 是否是绝对地址。
1095+
*/
1096+
isAbsoluteURL(url) {
1097+
try {
1098+
const res = new URL(url);
1099+
return !!res;
1100+
} catch (_) {
1101+
return false;
1102+
}
1103+
},
1104+
/**
1105+
* @description 相对地址转绝对地址。
1106+
* @private
1107+
* @param {string} url - 相对地址。
1108+
* @param {string} base - 基础地址。
1109+
* @returns {string} 完整地址。
1110+
*/
1111+
relative2absolute(url, base) {
1112+
let newUrl = new URL(url, base);
1113+
if (newUrl && newUrl.href) {
1114+
return decodeURIComponent(newUrl.href);
1115+
}
1116+
return;
10891117
}
10901118
};
10911119

src/openlayers/mapping/WebMap.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4818,9 +4818,15 @@ export class WebMap extends Observable {
48184818
const envelope = this.getEnvelope(indexbounds, layerInfo.bounds);
48194819
const styleResolutions = this.getStyleResolutions(envelope);
48204820
// const origin = [envelope.left, envelope.top];
4821-
let withCredentials = this.isIportalProxyServiceUrl(styles.sprite);
4821+
let baseUrl = layerInfo.url && layerInfo.url.split('?')[0];
4822+
let spriteUrl = styles.sprite;
4823+
if (!CommonUtil.isAbsoluteURL(styles.sprite)) {
4824+
spriteUrl = CommonUtil.relative2absolute(styles.sprite, baseUrl);
4825+
}
4826+
let withCredentials = this.isIportalProxyServiceUrl(spriteUrl);
48224827
// 创建MapBoxStyle样式
48234828
let mapboxStyles = new MapboxStyles({
4829+
baseUrl,
48244830
style: styles,
48254831
source: styles.name,
48264832
resolutions: styleResolutions,
@@ -4835,6 +4841,7 @@ export class WebMap extends Observable {
48354841
//设置避让参数
48364842
declutter: true,
48374843
source: new VectorTileSuperMapRest({
4844+
baseUrl,
48384845
style: styles,
48394846
withCredentials,
48404847
projection: layerInfo.projection,

src/openlayers/overlay/VectorTileSuperMapRest.js

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import TileGrid from 'ol/tilegrid/TileGrid';
2525
* @modulecategory Overlay
2626
* @param {Object} options - 参数。
2727
* @param {(string|undefined)} options.url - 服务地址。
28+
* @param {string} [options.baseUrl] - 当传入 style 对象且 style 中包含了相对路径时,需要传入 baseUrl 来拼接资源路径。
2829
* @param {(string|Object|undefined)} options.style - Mapbox Style JSON 对象或获取 Mapbox Style JSON 对象的 URL。当 `options.format` 为 {@link ol.format.MVT} 且 `options.source` 不为空时有效,优先级高于 `options.url`。
2930
* @param {(string|undefined)} options.source - Mapbox Style JSON 对象中的source名称。当 `options.style` 设置时有效。当不配置时,默认为 Mapbox Style JSON 的 `sources` 对象中的第一个。
3031
* @param {(string|Object)} [options.attributions='Tile Data <span>© <a href='http://support.supermap.com.cn/product/iServer.aspx' target='_blank'>SuperMap iServer</a></span> with <span>© <a href='https://iclient.supermap.io' target='_blank'>SuperMap iClient</a></span>'] - 版权信息。
@@ -58,8 +59,7 @@ export class VectorTileSuperMapRest extends VectorTile {
5859
projection: options.projection,
5960
state:
6061
options.format instanceof MVT &&
61-
options.style &&
62-
Object.prototype.toString.call(options.style) == '[object String]'
62+
options.style
6363
? 'loading'
6464
: options.state,
6565
tileClass: options.tileClass,
@@ -74,22 +74,9 @@ export class VectorTileSuperMapRest extends VectorTile {
7474
var me = this;
7575
me.withCredentials = options.withCredentials;
7676
me._tileType = options.tileType || 'ScaleXY';
77+
me.baseUrl = options.baseUrl;
7778
this.vectorTileStyles = new VectorTileStyles();
78-
if (options.format instanceof MVT && options.style) {
79-
if (Object.prototype.toString.call(options.style) == '[object String]') {
80-
var url = SecurityManager.appendCredential(options.style);
81-
FetchRequest.get(url, null, { withCredentials: options.withCredentials })
82-
.then((response) => response.json())
83-
.then((mbStyle) => {
84-
this._fillByStyleJSON(mbStyle, options.source);
85-
this.setState('ready');
86-
});
87-
} else {
88-
this._fillByStyleJSON(options.style, options.source);
89-
}
90-
} else {
91-
this._fillByRestMapOptions(options.url, options);
92-
}
79+
this._initialized(options);
9380

9481
function tileUrlFunction(tileCoord, pixelRatio, projection) {
9582
if (!me.tileGrid) {
@@ -313,13 +300,48 @@ export class VectorTileSuperMapRest extends VectorTile {
313300
});
314301
}
315302
}
316-
_fillByStyleJSON(style, source) {
303+
304+
async _initialized(options) {
305+
if (options.format instanceof MVT && options.style) {
306+
let style = options.style;
307+
if (Object.prototype.toString.call(options.style) == '[object String]') {
308+
var url = SecurityManager.appendCredential(options.style);
309+
const response = await FetchRequest.get(url, null, {
310+
withCredentials: options.withCredentials
311+
});
312+
style = await response.json();
313+
}
314+
await this._fillByStyleJSON(style, options.source);
315+
} else {
316+
this._fillByRestMapOptions(options.url, options);
317+
}
318+
this.setState('ready');
319+
}
320+
async _fillByStyleJSON(style, source) {
317321
if (!source) {
318322
source = Object.keys(style.sources)[0];
319323
}
320324
if (style.sources && style.sources[source]) {
321-
//ToDo 支持多个tiles地址
322-
this._tileUrl = SecurityManager.appendCredential(style.sources[source].tiles[0]);
325+
let newUrl;
326+
if (style.sources[source].tiles) {
327+
newUrl = style.sources[source].tiles[0];
328+
if (!CommonUtil.isAbsoluteURL(newUrl)) {
329+
newUrl = CommonUtil.relative2absolute(newUrl, this.baseUrl);
330+
}
331+
} else if (style.sources[source].url) {
332+
let tiles = style.sources[source].url;
333+
if (!CommonUtil.isAbsoluteURL(tiles)) {
334+
tiles = CommonUtil.relative2absolute(tiles, this.baseUrl);
335+
}
336+
const response = await FetchRequest.get(tiles, {}, { withoutFormatSuffix: true });
337+
const sourceInfo = await response.json();
338+
let tileUrl = sourceInfo.tiles[0];
339+
if (!CommonUtil.isAbsoluteURL(tileUrl)) {
340+
tileUrl = CommonUtil.relative2absolute(tileUrl, tiles);
341+
}
342+
newUrl = SecurityManager.appendCredential(tileUrl);
343+
}
344+
this._tileUrl = SecurityManager.appendCredential(newUrl);
323345
}
324346
if (style.metadata && style.metadata.indexbounds) {
325347
const indexbounds = style.metadata.indexbounds;

src/openlayers/overlay/vectortile/MapboxStyles.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import Text from 'ol/style/Text';
2525
* @param {Object} options - 参数。
2626
* @param {(string|undefined)} [options.url] - SuperMap iServer 地图服务地址,例如'http://localhost:8090/iserver/services/map-mvt-test/rest/maps/test',与options.style互斥,优先级低于options.style。
2727
* @param {(Object|string|undefined)} [options.style] - Mapbox Style JSON 对象或获取 Mapbox Style JSON 对象的 URL。与 options.url 互斥,优先级高于 options.url。
28+
* @param {string} [options.baseUrl] - 当传入 style 对象且 style 中包含了相对路径时,需要传入 baseUrl 来拼接资源路径。
2829
* @param {Array.<number>} [options.resolutions] - 地图分辨率数组,用于映射 zoom 值。通常情況与地图的 {@link ol.View} 的分辨率一致。</br>
2930
* 默认值为:[78271.51696402048,39135.75848201024, 19567.87924100512,9783.93962050256,4891.96981025128,2445.98490512564, 1222.99245256282,611.49622628141,305.748113140705,152.8740565703525, 76.43702828517625,38.21851414258813,19.109257071294063,9.554628535647032, 4.777314267823516,2.388657133911758,1.194328566955879,0.5971642834779395, 0.29858214173896974,0.14929107086948487,0.07464553543474244]。
3031
* @param {(string|Array.<string>|undefined)} [options.source] - Mapbox Style 'source'的 key 值或者 'layer' 的 ID 数组。
@@ -101,6 +102,7 @@ export class MapboxStyles extends Observable {
101102
});
102103
};
103104
this.layersBySourceLayer = {};
105+
this.baseUrl = options.baseUrl;
104106
olExtends(this.map);
105107
this._loadStyle(this.styleTarget);
106108
}
@@ -246,13 +248,15 @@ export class MapboxStyles extends Observable {
246248
}
247249
_loadStyle(style) {
248250
if (Object.prototype.toString.call(style) == '[object Object]') {
251+
this._handleRelativeUrl(style, this.baseUrl);
249252
this._mbStyle = style;
250253
this._resolve();
251254
} else {
252255
var url = SecurityManager.appendCredential(style);
253256
FetchRequest.get(url, null, { withCredentials: this.withCredentials })
254257
.then(response => response.json())
255258
.then(mbStyle => {
259+
this._handleRelativeUrl(mbStyle, url);
256260
this._mbStyle = mbStyle;
257261
this._resolve();
258262
});
@@ -372,4 +376,29 @@ export class MapboxStyles extends Observable {
372376
const parts = url.match(this.spriteRegEx);
373377
return parts ? parts[1] + extension + (parts.length > 2 ? parts[2] : '') : url + extension;
374378
}
379+
380+
_handleRelativeUrl(styles, baseUrl) {
381+
if (!baseUrl) {
382+
return styles;
383+
}
384+
Object.keys(styles).forEach((fieldName) => {
385+
if (fieldName === 'sources') {
386+
Object.keys(styles[fieldName]).forEach((sourceName) => {
387+
this._handleRelativeUrl(styles[fieldName][sourceName], baseUrl);
388+
})
389+
}
390+
if (fieldName === 'sprite' || fieldName === 'glyphs' || fieldName === 'url') {
391+
if (typeof styles[fieldName] === 'string' && !CommonUtil.isAbsoluteURL(styles[fieldName])) {
392+
styles[fieldName] = CommonUtil.relative2absolute(styles[fieldName], baseUrl);
393+
}
394+
}
395+
if (fieldName === 'tiles' && Array.isArray(styles[fieldName])) {
396+
styles[fieldName].forEach((tile) => {
397+
if (!CommonUtil.isAbsoluteURL(tile)) {
398+
tile = CommonUtil.relative2absolute(tile, baseUrl);
399+
}
400+
})
401+
}
402+
})
403+
}
375404
}

test/openlayers/overlay/VectorTileSuperMapRestSpec.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,74 @@ describe('openlayers_VectorTileSuperMapRest', () => {
113113
});
114114

115115
});
116+
117+
it('handle relative url', (done) => {
118+
spyOn(FetchRequest, 'get').and.callFake((url) => {
119+
if (url.indexOf('fake') > -1) {
120+
return Promise.resolve(new Response(JSON.stringify({
121+
tiles: ['tile/{z}/{y}/{x}.pbf']
122+
})));
123+
}
124+
return Promise.resolve();
125+
});
126+
new MapService(url).getMapInfo((serviceResult) => {
127+
map = new Map({
128+
target: 'map',
129+
view: new View({
130+
center: [12957388, 4853991],
131+
zoom: 11
132+
})
133+
});
134+
vectorTileOptions = VectorTileSuperMapRest.optionsFromMapJSON(url, serviceResult.result);
135+
vectorTileOptions.tileLoadFunction = (tile) => {
136+
tile.setLoader(() => {
137+
tile.setFeatures([]);
138+
});
139+
};
140+
vectorTileOptions.format = new MVT();
141+
vectorTileOptions.baseUrl = 'http://fake/iportal/services';
142+
vectorTileOptions.style = {
143+
"version" : 8,
144+
"sprite" : "../sprites/sprite",
145+
"glyphs" : "../fonts/{fontstack}/{range}.pbf",
146+
"sources": {
147+
"esri": {
148+
"type": "vector",
149+
"url": "../../"
150+
}
151+
},
152+
"layers" : [{
153+
"id" : "Contour_11_main/0",
154+
"type" : "line",
155+
"source" : "esri",
156+
"source-layer" : "Contour",
157+
"filter" : ["all", ["==", "Index3", 1], ["==", "Index5", 1]],
158+
"minzoom" : 11,
159+
"maxzoom" : 12,
160+
"paint" : {
161+
"line-color" : "#61674a",
162+
"line-opacity" : 0.5,
163+
"line-width" : {
164+
"base" : 1.2,
165+
"stops" : [[11, 0.7], [16, 1.1]]
166+
}
167+
}
168+
}]
169+
}
170+
vectorTileSource = new VectorTileSuperMapRest(vectorTileOptions);
171+
vectorTileSource.once('tileloadend', () => {
172+
expect(vectorTileOptions).not.toBeNull();
173+
expect(vectorTileOptions.crossOrigin).toBe('anonymous');
174+
expect(vectorTileSource).not.toBeNull();
175+
done();
176+
});
177+
vectorLayer = new VectorTileLayer({
178+
source: vectorTileSource
179+
});
180+
map.addLayer(vectorLayer);
181+
});
182+
});
183+
116184
it('custom_tileLoadFunction', (done) => {
117185
var spy = jasmine.createSpy('test')
118186
var tileLoadFunction = (tile) => {

test/openlayers/overlay/vectortile/MapboxStylesSpec.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,4 +254,59 @@ describe("openlayers_MapboxStyles", () => {
254254
}
255255
});
256256
});
257+
258+
it("handle relative url", done => {
259+
spyOn(XMLHttpRequest.prototype, 'send').and.callThrough();
260+
spyOn(XMLHttpRequest.prototype, 'setRequestHeader').and.callThrough();
261+
var style = {
262+
"version" : 8,
263+
"sprite" : "../sprites/sprite",
264+
"glyphs" : "../fonts/{fontstack}/{range}.pbf",
265+
"sources": {
266+
"esri": {
267+
"type": "vector",
268+
"url": "../../"
269+
}
270+
},
271+
"layers" : [{
272+
"id" : "Contour_11_main/0",
273+
"type" : "line",
274+
"source" : "esri",
275+
"source-layer" : "Contour",
276+
"filter" : ["all", ["==", "Index3", 1], ["==", "Index5", 1]],
277+
"minzoom" : 11,
278+
"maxzoom" : 12,
279+
"paint" : {
280+
"line-color" : "#61674a",
281+
"line-opacity" : 0.5,
282+
"line-width" : {
283+
"base" : 1.2,
284+
"stops" : [[11, 0.7], [16, 1.1]]
285+
}
286+
}
287+
}]
288+
}
289+
mapboxStyles = new MapboxStyles({
290+
style: style,
291+
baseUrl: 'http://localhost:9876',
292+
map: map,
293+
source: "California",
294+
headers:{'appToken':'test'}
295+
});
296+
mapboxStyles.on("styleloaded", () => {
297+
try {
298+
style = mapboxStyles.getStyleFunction();
299+
expect(style).not.toBeNull();
300+
console.log('mapboxStyles', mapboxStyles);
301+
expect(mapboxStyles._mbStyle.glyphs).toBe('http://localhost:9876/fonts/{fontstack}/{range}.pbf');
302+
expect(mapboxStyles._mbStyle.sprite).toBe('http://localhost:9876/sprites/sprite');
303+
expect(mapboxStyles._mbStyle.sources['esri']['url']).toBe('http://localhost:9876/');
304+
done();
305+
} catch (e) {
306+
console.log("'init_Style_headers'案例失败" + e.name + ":" + e.message);
307+
expect(false).toBeTruthy();
308+
done();
309+
}
310+
});
311+
});
257312
});

test/resources/MapboxStyles.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ var vectorstylesEscapedJson={
88
}
99
},
1010
"name": "California",
11-
"sprite": "../../base/resources/img/sprite@2x",
11+
"sprite": "http://localhost:9876/base/resources/img/sprite@2x",
1212
"layers": [
1313
{
1414
"paint": {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy