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)
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