Skip to content

Commit 158b5c3

Browse files
【update】ol 支持加载包含相对地址的style review by luox
1 parent 5a1da9a commit 158b5c3

File tree

7 files changed

+215
-8
lines changed

7 files changed

+215
-8
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: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5168,10 +5168,16 @@ export class WebMap extends Observable {
51685168
const envelope = this.getEnvelope(indexbounds, layerInfo.bounds);
51695169
const styleResolutions = this.getStyleResolutions(envelope);
51705170
// const origin = [envelope.left, envelope.top];
5171-
let withCredentials = this.isIportalProxyServiceUrl(styles.sprite);
5172-
const requestParameters = this.tileRequestParameters && this.tileRequestParameters(styles.sprite);
5171+
let baseUrl = layerInfo.url && layerInfo.url.split('?')[0];
5172+
let spriteUrl = styles.sprite;
5173+
if (!CommonUtil.isAbsoluteURL(styles.sprite)) {
5174+
spriteUrl = CommonUtil.relative2absolute(styles.sprite, baseUrl);
5175+
}
5176+
let withCredentials = this.isIportalProxyServiceUrl(spriteUrl);
5177+
const requestParameters = this.tileRequestParameters && this.tileRequestParameters(spriteUrl);
51735178
// 创建MapBoxStyle样式
51745179
let mapboxStyles = new MapboxStyles({
5180+
baseUrl,
51755181
style: styles,
51765182
source: styles.name,
51775183
resolutions: styleResolutions,
@@ -5187,6 +5193,7 @@ export class WebMap extends Observable {
51875193
//设置避让参数
51885194
declutter: true,
51895195
source: new VectorTileSuperMapRest({
5196+
baseUrl,
51905197
style: styles,
51915198
withCredentials,
51925199
projection: layerInfo.projection,

src/openlayers/overlay/VectorTileSuperMapRest.js

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import decryptTileUtil from '@supermapgis/tile-decryptor';
2929
* @modulecategory Overlay
3030
* @param {Object} options - 参数。
3131
* @param {(string|undefined)} options.url - 服务地址。
32+
* @param {string} [options.baseUrl] - 当传入 style 对象且 style 中包含了相对路径时,需要传入 baseUrl 来拼接资源路径。
3233
* @param {(string|Object|undefined)} options.style - Mapbox Style JSON 对象或获取 Mapbox Style JSON 对象的 URL。当 `options.format` 为 {@link ol.format.MVT} 且 `options.source` 不为空时有效,优先级高于 `options.url`。
3334
* @param {(string|undefined)} options.source - Mapbox Style JSON 对象中的 source 名称。当 `options.style` 设置时有效。当不配置时,默认为 Mapbox Style JSON 的 `sources` 对象中的第一个。
3435
* @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>'] - 版权描述信息。
@@ -80,6 +81,7 @@ export class VectorTileSuperMapRest extends VectorTile {
8081
me.withCredentials = options.withCredentials;
8182
me.headers = options.headers || {};
8283
me._tileType = options.tileType || 'ScaleXY';
84+
me.baseUrl = options.baseUrl;
8385
this.vectorTileStyles = new VectorTileStyles();
8486
this._initialized(options);
8587

@@ -317,7 +319,7 @@ export class VectorTileSuperMapRest extends VectorTile {
317319
});
318320
style = await response.json();
319321
}
320-
this._fillByStyleJSON(style, options.source);
322+
await this._fillByStyleJSON(style, options.source);
321323
} else {
322324
this._fillByRestMapOptions(options.url, options);
323325
}
@@ -329,13 +331,32 @@ export class VectorTileSuperMapRest extends VectorTile {
329331
}
330332
}
331333

332-
_fillByStyleJSON(style, source) {
334+
async _fillByStyleJSON(style, source) {
333335
if (!source) {
334336
source = Object.keys(style.sources)[0];
335337
}
338+
//ToDo 支持多个tiles地址
336339
if (style.sources && style.sources[source]) {
337-
//ToDo 支持多个tiles地址
338-
this._tileUrl = SecurityManager.appendCredential(style.sources[source].tiles[0]);
340+
let newUrl;
341+
if (style.sources[source].tiles) {
342+
newUrl = style.sources[source].tiles[0];
343+
if (!CommonUtil.isAbsoluteURL(newUrl)) {
344+
newUrl = CommonUtil.relative2absolute(newUrl, this.baseUrl);
345+
}
346+
} else if (style.sources[source].url) {
347+
let tiles = style.sources[source].url;
348+
if (!CommonUtil.isAbsoluteURL(tiles)) {
349+
tiles = CommonUtil.relative2absolute(tiles, this.baseUrl);
350+
}
351+
const response = await FetchRequest.get(tiles, {}, { withoutFormatSuffix: true });
352+
const sourceInfo = await response.json();
353+
let tileUrl = sourceInfo.tiles[0];
354+
if (!CommonUtil.isAbsoluteURL(tileUrl)) {
355+
tileUrl = CommonUtil.relative2absolute(tileUrl, tiles);
356+
}
357+
newUrl = SecurityManager.appendCredential(tileUrl);
358+
}
359+
this._tileUrl = SecurityManager.appendCredential(newUrl);
339360
}
340361
if (style.metadata && style.metadata.indexbounds) {
341362
const indexbounds = style.metadata.indexbounds;

src/openlayers/overlay/vectortile/MapboxStyles.js

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import Text from 'ol/style/Text';
2424
* @category Visualization VectorTile
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。
27+
* @param {string} [options.baseUrl] - 当传入 style 对象且 style 中包含了相对路径时,需要传入 baseUrl 来拼接资源路径。
2728
* @param {(Object|string|undefined)} [options.style] - Mapbox Style JSON 对象或获取 Mapbox Style JSON 对象的 URL。与 options.url 互斥,优先级高于 options.url。
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]。
@@ -103,6 +104,7 @@ export class MapboxStyles extends Observable {
103104
});
104105
};
105106
this.layersBySourceLayer = {};
107+
this.baseUrl = options.baseUrl;
106108
olExtends(this.map);
107109
this._loadStyle(this.styleTarget);
108110
}
@@ -248,6 +250,7 @@ export class MapboxStyles extends Observable {
248250
}
249251
_loadStyle(style) {
250252
if (Object.prototype.toString.call(style) == '[object Object]') {
253+
this._handleRelativeUrl(style, this.baseUrl);
251254
this._mbStyle = style;
252255
setTimeout(() => {
253256
this._resolve();
@@ -257,6 +260,7 @@ export class MapboxStyles extends Observable {
257260
FetchRequest.get(url, null, { withCredentials: this.withCredentials, headers: this.headers })
258261
.then(response => response.json())
259262
.then(mbStyle => {
263+
this._handleRelativeUrl(mbStyle, url);
260264
this._mbStyle = mbStyle;
261265
this._resolve();
262266
});
@@ -288,7 +292,7 @@ export class MapboxStyles extends Observable {
288292
xhr.responseType = 'blob';
289293
xhr.addEventListener('loadend',(e) => {
290294
var data = e.target.response;
291-
if (data !== undefined) {
295+
if (data !== undefined && data !== null) {
292296
const img = new Image();
293297
img.src = URL.createObjectURL(data);
294298
this._spriteImage = img;
@@ -392,4 +396,29 @@ export class MapboxStyles extends Observable {
392396
const parts = url.match(this.spriteRegEx);
393397
return parts ? parts[1] + extension + (parts.length > 2 ? parts[2] : '') : url + extension;
394398
}
399+
400+
_handleRelativeUrl(styles, baseUrl) {
401+
if (!baseUrl) {
402+
return styles;
403+
}
404+
Object.keys(styles).forEach((fieldName) => {
405+
if (fieldName === 'sources') {
406+
Object.keys(styles[fieldName]).forEach((sourceName) => {
407+
this._handleRelativeUrl(styles[fieldName][sourceName], baseUrl);
408+
})
409+
}
410+
if (fieldName === 'sprite' || fieldName === 'glyphs' || fieldName === 'url') {
411+
if (typeof styles[fieldName] === 'string' && !CommonUtil.isAbsoluteURL(styles[fieldName])) {
412+
styles[fieldName] = CommonUtil.relative2absolute(styles[fieldName], baseUrl);
413+
}
414+
}
415+
if (fieldName === 'tiles' && Array.isArray(styles[fieldName])) {
416+
styles[fieldName].forEach((tile) => {
417+
if (!CommonUtil.isAbsoluteURL(tile)) {
418+
tile = CommonUtil.relative2absolute(tile, baseUrl);
419+
}
420+
})
421+
}
422+
})
423+
}
395424
}

test/openlayers/overlay/VectorTileSuperMapRestSpec.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,4 +225,71 @@ describe('openlayers_VectorTileSuperMapRest', () => {
225225
});
226226
});
227227
});
228+
229+
it('handle relative url', (done) => {
230+
spyOn(FetchRequest, 'get').and.callFake((url) => {
231+
if (url.indexOf('fake') > -1) {
232+
return Promise.resolve(new Response(JSON.stringify({
233+
tiles: ['tile/{z}/{y}/{x}.pbf']
234+
})));
235+
}
236+
return Promise.resolve();
237+
});
238+
new MapService(url).getMapInfo((serviceResult) => {
239+
map = new Map({
240+
target: 'map',
241+
view: new View({
242+
center: [12957388, 4853991],
243+
zoom: 11
244+
})
245+
});
246+
vectorTileOptions = VectorTileSuperMapRest.optionsFromMapJSON(url, serviceResult.result);
247+
vectorTileOptions.tileLoadFunction = (tile) => {
248+
tile.setLoader(() => {
249+
tile.setFeatures([]);
250+
});
251+
};
252+
vectorTileOptions.format = new MVT();
253+
vectorTileOptions.baseUrl = 'http://fake/iportal/services';
254+
vectorTileOptions.style = {
255+
"version" : 8,
256+
"sprite" : "../sprites/sprite",
257+
"glyphs" : "../fonts/{fontstack}/{range}.pbf",
258+
"sources": {
259+
"esri": {
260+
"type": "vector",
261+
"url": "../../"
262+
}
263+
},
264+
"layers" : [{
265+
"id" : "Contour_11_main/0",
266+
"type" : "line",
267+
"source" : "esri",
268+
"source-layer" : "Contour",
269+
"filter" : ["all", ["==", "Index3", 1], ["==", "Index5", 1]],
270+
"minzoom" : 11,
271+
"maxzoom" : 12,
272+
"paint" : {
273+
"line-color" : "#61674a",
274+
"line-opacity" : 0.5,
275+
"line-width" : {
276+
"base" : 1.2,
277+
"stops" : [[11, 0.7], [16, 1.1]]
278+
}
279+
}
280+
}]
281+
}
282+
vectorTileSource = new VectorTileSuperMapRest(vectorTileOptions);
283+
vectorTileSource.once('tileloadend', () => {
284+
expect(vectorTileOptions).not.toBeNull();
285+
expect(vectorTileOptions.crossOrigin).toBe('anonymous');
286+
expect(vectorTileSource).not.toBeNull();
287+
done();
288+
});
289+
vectorLayer = new VectorTileLayer({
290+
source: vectorTileSource
291+
});
292+
map.addLayer(vectorLayer);
293+
});
294+
});
228295
});

test/openlayers/overlay/vectortile/MapboxStylesSpec.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,4 +279,59 @@ describe("openlayers_MapboxStyles", () => {
279279
}
280280
});
281281
});
282+
283+
it("handle relative url", done => {
284+
spyOn(XMLHttpRequest.prototype, 'send').and.callThrough();
285+
spyOn(XMLHttpRequest.prototype, 'setRequestHeader').and.callThrough();
286+
var style = {
287+
"version" : 8,
288+
"sprite" : "../sprites/sprite",
289+
"glyphs" : "../fonts/{fontstack}/{range}.pbf",
290+
"sources": {
291+
"esri": {
292+
"type": "vector",
293+
"url": "../../"
294+
}
295+
},
296+
"layers" : [{
297+
"id" : "Contour_11_main/0",
298+
"type" : "line",
299+
"source" : "esri",
300+
"source-layer" : "Contour",
301+
"filter" : ["all", ["==", "Index3", 1], ["==", "Index5", 1]],
302+
"minzoom" : 11,
303+
"maxzoom" : 12,
304+
"paint" : {
305+
"line-color" : "#61674a",
306+
"line-opacity" : 0.5,
307+
"line-width" : {
308+
"base" : 1.2,
309+
"stops" : [[11, 0.7], [16, 1.1]]
310+
}
311+
}
312+
}]
313+
}
314+
mapboxStyles = new MapboxStyles({
315+
style: style,
316+
baseUrl: 'http://localhost:9876',
317+
map: map,
318+
source: "California",
319+
headers:{'appToken':'test'}
320+
});
321+
mapboxStyles.on("styleloaded", () => {
322+
try {
323+
style = mapboxStyles.getStyleFunction();
324+
expect(style).not.toBeNull();
325+
console.log('mapboxStyles', mapboxStyles);
326+
expect(mapboxStyles._mbStyle.glyphs).toBe('http://localhost:9876/fonts/{fontstack}/{range}.pbf');
327+
expect(mapboxStyles._mbStyle.sprite).toBe('http://localhost:9876/sprites/sprite');
328+
expect(mapboxStyles._mbStyle.sources['esri']['url']).toBe('http://localhost:9876/');
329+
done();
330+
} catch (e) {
331+
console.log("'init_Style_headers'案例失败" + e.name + ":" + e.message);
332+
expect(false).toBeTruthy();
333+
done();
334+
}
335+
});
336+
});
282337
});

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)