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)