From db2ba611bd38745c006c2223c0d3b5d164b0562d Mon Sep 17 00:00:00 2001 From: xiongjj Date: Tue, 12 Aug 2025 16:50:18 +0800 Subject: [PATCH 01/13] =?UTF-8?q?=E3=80=90feature=E3=80=91=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=BA=95=E5=9B=BE=E5=88=87=E6=8D=A2api;=20review=20by?= =?UTF-8?q?=20chenxh?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/mapping/MapBase.js | 4 + src/common/mapping/WebMapBase.js | 16 + .../mapping/utils/AppreciableLayerBase.js | 130 ++++- src/common/mapping/utils/SourceListModelV2.js | 15 + src/common/mapping/utils/SourceListModelV3.js | 131 ++++- .../mapping/utils/SourceListModelV2Spec.js | 474 +++++++++++++++++- .../mapping/utils/SourceListModelV3Spec.js | 378 ++++++++++++-- 7 files changed, 1085 insertions(+), 63 deletions(-) diff --git a/src/common/mapping/MapBase.js b/src/common/mapping/MapBase.js index 22d3512f87..d4a221adc1 100644 --- a/src/common/mapping/MapBase.js +++ b/src/common/mapping/MapBase.js @@ -57,6 +57,10 @@ export function createMapClassExtending(SuperClass = class {}) { return exsitLayers; } + changeBaseLayer() { + this._sourceListModel && this._sourceListModel.changeBaseLayer(...arguments); + } + echartsLayerResize() {} updateOverlayLayer() {} diff --git a/src/common/mapping/WebMapBase.js b/src/common/mapping/WebMapBase.js index 335d6b87b4..607f134ee4 100644 --- a/src/common/mapping/WebMapBase.js +++ b/src/common/mapping/WebMapBase.js @@ -486,6 +486,22 @@ export function createWebMapBaseExtending(SuperClass, { mapRepo }) { this.clean(false); } + /** + * @version 12.0.0 + * @function WebMapBase.prototype.changeBaseLayer + * @description 切换底图 + * @param {BaseLayerConfig} layer - 图层配置对象 + * @typedef {Object} BaseLayerConfig + * @property {string} id - 唯一标识 + * @property {string} title - 显示名称 + * @property {Array} layers - 上图的图层 + * @property {Object} sources - 图层对应的source + * @returns {Object} 当前底图信息 + */ + changeBaseLayer() { + return this._handler && this._handler.changeBaseLayer(...arguments); + } + _readyForInitializingWebMap() { this._initWebMap(!this.map); } diff --git a/src/common/mapping/utils/AppreciableLayerBase.js b/src/common/mapping/utils/AppreciableLayerBase.js index 45bb6aa851..ec088a003a 100644 --- a/src/common/mapping/utils/AppreciableLayerBase.js +++ b/src/common/mapping/utils/AppreciableLayerBase.js @@ -1,12 +1,12 @@ import { Events } from '../../commontypes'; import SourceModel from './SourceModel'; import { createAppreciableLayerId, getLayerInfosFromCatalogs } from './util'; +import cloneDeep from 'lodash.clonedeep'; export class AppreciableLayerBase extends Events { constructor(options = {}) { super(); this.map = options.map; - this.layers = options.layers || []; this.appendLayers = options.appendLayers || false; this.unexpectedSourceNames = [ 'tdt-search-', @@ -21,12 +21,23 @@ export class AppreciableLayerBase extends Events { this.layersVisibleMap = new Map(); this.eventTypes = ['layerupdatechanged']; this._styleDataUpdatedHandler = this._styleDataUpdatedHandler.bind(this); + this.baseLayerInfoOnMap = null; + this.setLayers(options.layers); + this._initBaseLayerInfo(options.layers); } - setLayers(layers) { + setLayers(layers = []) { this.layers = layers; } + setDefaultBaseLayerInfo(baseLayerInfo) { + this.baseLayerInfoOnMap = baseLayerInfo; + } + + setBaseLayer() { + throw new Error('setBaseLayer is not implemented'); + } + createLayerCatalogs() { throw new Error('createLayerCatalogs is not implemented'); } @@ -39,6 +50,14 @@ export class AppreciableLayerBase extends Events { throw new Error('initLayers is not implemented'); } + changeBaseLayer(layer) { + if (this.map) { + this._removeBaseLayer(); + this._addBaseLayer(layer); + return cloneDeep(this.baseLayerInfoOnMap); + } + } + createAppreciableLayers() { const detailLayers = this.initLayers(); return this._initAppreciableLayers(detailLayers); @@ -335,4 +354,111 @@ export class AppreciableLayerBase extends Events { } return topLayers.concat(autoLayers, bottomLayers); } + + _addBaseLayer(layerItem) { + const { layers, sources } = layerItem; + const renderSources = {}; + Object.keys(sources).forEach(sourceId => { + let nextSourceId = sourceId; + if (this.map.getSource(sourceId)) { + renderSources[sourceId] = `${sourceId}_${+new Date()}`; + nextSourceId = renderSources[sourceId]; + } + this.map.addSource(nextSourceId, sources[sourceId]); + }); + const layersToAdd = []; + layers.forEach(layer => { + let { beforeId } = layer; + if (!beforeId) { + const styles = this.map.getStyle(); + beforeId = styles.layers[0] && styles.layers[0].id; + } + const layerToAdd = Object.assign({}, layer); + delete layerToAdd.beforeId; + const sourceId = layerToAdd.source; + if (renderSources[sourceId]) { + layerToAdd.source = renderSources[sourceId]; + } + if (this.map.getLayer(layerToAdd.id)) { + const nextLayerId = `${layerToAdd.id}_${layerToAdd.source || +new Date()}`; + layerToAdd.id = nextLayerId; + } + layersToAdd.push({ + layer: layerToAdd, + beforeId + }); + }); + this.baseLayerInfoOnMap = { + ...layerItem, + layers: layersToAdd.map(item => Object.assign({}, item.layer)), + sources: Object.keys(layerItem.sources).reduce((sources, sourceId) => { + let source = sourceId; + if (renderSources[source]) { + source = renderSources[source]; + } + sources[source] = renderSources[sourceId]; + return sources; + }, {}) + }; + this.setBaseLayer({ ...this.baseLayerInfoOnMap }); + layersToAdd.forEach(({ layer, beforeId }) => { + this.map.addLayer(layer, beforeId); + }) + } + + _removeBaseLayer() { + if (this.baseLayerInfoOnMap) { + const { layers, sources } = this.baseLayerInfoOnMap; + const layersIds = layers.map(item => item.id); + const sourceIds = Object.keys(sources); + layersIds.forEach(layerId => { + if (this.map.getLayer(layerId)) { + this.map.removeLayer(layerId); + } + }); + sourceIds.forEach(sourceId => { + if (this.map.getSource(sourceId)) { + this.map.removeSource(sourceId); + } + }); + } + } + + _initBaseLayerInfo(layers) { + if (layers && layers.length && !this.baseLayerInfoOnMap) { + const firstLayer = this.layers[0]; + const baseLayer = firstLayer; + const layerList = this.map.getStyle().layers; + const baseLayersOnMap = baseLayer.renderLayers.map((layerId) => { + const nextLayer = layerList.find(item => item.id === layerId); + if (nextLayer) { + const layerIndex = layerList.findIndex(item => item.id === layerId); + const nextLayerIndex = layerIndex + 1; + if (layerList[nextLayerIndex]) { + nextLayer.beforeId = layerList[nextLayerIndex].id; + } + if (!nextLayer.metadata || !nextLayer.metadata.SM_Layer_Title) { + nextLayer.metadata = { + ...nextLayer.metadata, + SM_Layer_Title: baseLayer.title + }; + } + } + return nextLayer; + }).filter(Boolean); + const sourcesMap = this.map.getStyle().sources; + this.setDefaultBaseLayerInfo({ + id: `__default__${baseLayer.id}`, + title: baseLayer.title, + layers: baseLayersOnMap, + sources: baseLayersOnMap.reduce((sources, layer) => { + const sourceId = layer.source; + if (sourceId && !sources[sourceId]) { + sources[sourceId] = sourcesMap[sourceId]; + } + return sources; + }, {}) + }); + } + } } diff --git a/src/common/mapping/utils/SourceListModelV2.js b/src/common/mapping/utils/SourceListModelV2.js index 2cbcb71966..e10d7ae28c 100644 --- a/src/common/mapping/utils/SourceListModelV2.js +++ b/src/common/mapping/utils/SourceListModelV2.js @@ -47,6 +47,21 @@ export class SourceListModelV2 extends AppreciableLayerBase { return this.concatExpectLayers(selfLayers, selfLayerIds, nextLayers); } + setBaseLayer(layerItem) { + const nextLayers = this.layers.slice(1); + const firstLayer = layerItem.layers[0] || {}; + const defaultId = firstLayer.id || ''; + const baseLayer = { + id: layerItem.id || defaultId, + visible: true, + name: layerItem.title || defaultId, + title: layerItem.title || defaultId, + renderLayers: layerItem.layers.map(item => item.id) + } + nextLayers.unshift(baseLayer); + this.setLayers(nextLayers); + } + _isBelongToMapJSON(layerFromMapJSON, layerOnMap) { return ( layerFromMapJSON.renderLayers && layerFromMapJSON.renderLayers.some((subLayerId) => subLayerId === layerOnMap.id) diff --git a/src/common/mapping/utils/SourceListModelV3.js b/src/common/mapping/utils/SourceListModelV3.js index 82b1ca0cdf..b982531949 100644 --- a/src/common/mapping/utils/SourceListModelV3.js +++ b/src/common/mapping/utils/SourceListModelV3.js @@ -1,4 +1,3 @@ - import { AppreciableLayerBase } from './AppreciableLayerBase'; import { getLayerCatalogRenderLayers, getLayerInfosFromCatalogs, getMainLayerFromCatalog } from './util'; @@ -6,17 +5,23 @@ export class SourceListModelV3 extends AppreciableLayerBase { constructor(options = {}) { super(options); this._mapInfo = options.mapInfo; - this._layerCatalog = options.mapInfo.metadata.layerCatalog; this._mapResourceInfo = options.mapResourceInfo; this._l7LayerUtil = options.l7LayerUtil; this._legendList = options.legendList; // chart 统计图表 point-extrusion 柱状图 this._immutableTopOrderLayers = ['chart', 'point-extrusion']; + const layerCatalogs = options.mapInfo.metadata.layerCatalog; + this.setLayerCatalog(layerCatalogs); const layers = this._generateLayers(); this.setLayers(layers); + this.setDefaultBaseLayerInfo(this._generateBaseLayerInfo(layerCatalogs, layers)); this.initDatas(); } + setLayerCatalog(catalogs) { + this._layerCatalog = catalogs; + } + createLayerCatalogs() { const appreciableLayers = this.getLayers(false); const sourceList = this._createSourceCatalogs(this._layerCatalog, appreciableLayers); @@ -47,6 +52,47 @@ export class SourceListModelV3 extends AppreciableLayerBase { return this.concatExpectLayers(selfLayers, selfLayerIds, nextLayers); } + setBaseLayer(layerItem) { + const nextLayers = this.layers.slice(); + const nextLayerCatalog = this._layerCatalog.slice(); + const originBaseLayerCatalog = nextLayerCatalog.pop(); + this._removeBaseLayerRenderLayers(originBaseLayerCatalog, nextLayers); + const baseLayers = layerItem.layers.map((layer) => { + return { + ...layer, + layerInfo: { + id: layer.id, + title: layer.id, + renderLayers: [layer.id] + } + }; + }); + nextLayers.unshift(...baseLayers); + const firstLayer = layerItem.layers[0] || {}; + const defaultId = firstLayer.id || ''; + const baseLayerCatalog = { + id: defaultId, + title: layerItem.title || defaultId, + type: 'basic', + visible: true + }; + if (layerItem.layers.length > 1) { + baseLayerCatalog.id = layerItem.id || defaultId; + baseLayerCatalog.type = 'group'; + baseLayerCatalog.children = layerItem.layers.map((layer) => { + return { + id: layer.id, + title: layer.id, + type: 'basic', + visible: true + }; + }); + } + nextLayerCatalog.push(baseLayerCatalog); + this.setLayerCatalog(nextLayerCatalog); + this.setLayers(nextLayers); + } + _createSourceCatalogs(catalogs, appreciableLayers) { const formatCatalogs = catalogs.map((catalog) => { let formatItem; @@ -60,7 +106,7 @@ export class SourceListModelV3 extends AppreciableLayerBase { visible }; } else { - const renderLayers = getLayerCatalogRenderLayers(parts, id, this._mapInfo.layers); + const renderLayers = getLayerCatalogRenderLayers(parts, id, this.layers); const matchLayer = appreciableLayers.find((layer) => layer.id === renderLayers[0]); this.removeLayerExtralFields([matchLayer]); formatItem = Object.assign({}, matchLayer); @@ -75,10 +121,15 @@ export class SourceListModelV3 extends AppreciableLayerBase { const projectCataglogs = getLayerInfosFromCatalogs(catalogs, 'catalogType'); const metadataCatalogs = getLayerInfosFromCatalogs(this._mapInfo.metadata.layerCatalog); const l7MarkerLayers = this._l7LayerUtil.getL7MarkerLayers(); - const layerDatas = metadataCatalogs.map(layerCatalog => { + const layerDatas = metadataCatalogs.map((layerCatalog) => { const renderLayers = getLayerCatalogRenderLayers(layerCatalog.parts, layerCatalog.id, this._mapInfo.layers); const layer = getMainLayerFromCatalog(layerCatalog.parts, layerCatalog.id, this._mapInfo.layers); - const layerInfo = { id: layer.id, title: layerCatalog.title, renderLayers, reused: layer.metadata && layer.metadata.reused }; + const layerInfo = { + id: layer.id, + title: layerCatalog.title, + renderLayers, + reused: layer.metadata && layer.metadata.reused + }; const matchProjectCatalog = projectCataglogs.find((item) => item.id === layerCatalog.id) || {}; const { msDatasetId } = matchProjectCatalog; let dataSource = {}; @@ -89,7 +140,7 @@ export class SourceListModelV3 extends AppreciableLayerBase { dataSource = { serverId: matchData.datasetId, type: data.sourceType - } + }; if (data.sourceType === 'REST_DATA') { const [serverUrl, datasourceName] = data.url.split('/rest/data/datasources/'); dataSource.url = `${serverUrl}/rest/data`; @@ -127,7 +178,7 @@ export class SourceListModelV3 extends AppreciableLayerBase { if (validThemeFields.length > 0) { layerInfo.themeSetting = { themeField: validThemeFields }; } - if (this._immutableTopOrderLayers.some(type => type === layer.type)) { + if (this._immutableTopOrderLayers.some((type) => type === layer.type)) { layerInfo.metadata = Object.assign({}, layer.metadata, { SM_Layer_Order: 'top' }); } return Object.assign({}, layer, { layerInfo }); @@ -135,4 +186,70 @@ export class SourceListModelV3 extends AppreciableLayerBase { layerDatas.reverse(); return layerDatas; } + + _generateBaseLayerInfo(layerCatalog, layers) { + const nextLayerCatalog = layerCatalog.slice(); + const originBaseLayerCatalog = nextLayerCatalog.pop(); + if (!originBaseLayerCatalog) { + return; + } + const renderLayers = this._getBaseLayerRenderLayers(originBaseLayerCatalog, layers); + const baseLayersOnMap = renderLayers.map((layer) => { + const nextLayer = { ...layer }; + delete nextLayer.layerInfo; + const layerIndex = layers.findIndex((item) => item.id === layer.id); + const nextLayerIndex = layerIndex + 1; + if (layers[nextLayerIndex]) { + nextLayer.beforeId = layers[nextLayerIndex].id; + } + return nextLayer; + }); + const sourcesMap = this.map.getStyle().sources; + return { + id: `__default__${originBaseLayerCatalog.id}`, + title: originBaseLayerCatalog.title, + layers: baseLayersOnMap, + sources: baseLayersOnMap.reduce((sources, layer) => { + const sourceId = layer.source; + if (sourceId && !sources[sourceId]) { + sources[sourceId] = sourcesMap[sourceId]; + } + return sources; + }, {}) + }; + } + + _getBaseLayerRenderLayers(layerCatalog, layersOnMap) { + const uniqueSet = new Set(); + const collectIds = (node) => { + if (node.children) { + node.children.forEach((child) => collectIds(child)); + } + const parts = node.parts || [node.id]; + parts.forEach(part => uniqueSet.add(part)); + }; + collectIds(layerCatalog); + + return layersOnMap.filter(layer => uniqueSet.has(layer.id)); + } + + _removeBaseLayerRenderLayers(layerCatalog, layersOnMap) { + const deleteSet = new Set(); + const collectIds = (node) => { + if (node.children) { + node.children.forEach((child) => collectIds(child)); + } + const parts = node.parts || [node.id]; + parts.forEach(part => deleteSet.add(part)); + }; + collectIds(layerCatalog); + + let writeIndex = 0; + for (let i = 0; i < layersOnMap.length; i++) { + if (!deleteSet.has(layersOnMap[i].id)) { + layersOnMap[writeIndex++] = layersOnMap[i]; + } + } + layersOnMap.length = writeIndex; + } } diff --git a/test/common/mapping/utils/SourceListModelV2Spec.js b/test/common/mapping/utils/SourceListModelV2Spec.js index e6927c0763..48cf5fa202 100644 --- a/test/common/mapping/utils/SourceListModelV2Spec.js +++ b/test/common/mapping/utils/SourceListModelV2Spec.js @@ -1,7 +1,32 @@ import { SourceListModelV2 } from '../../../../src/common/mapping/utils/SourceListModelV2'; describe('SourceListV2', () => { - let layers, map, mockEvents; + let layers, sources, map, mockEvents, overlayLayersManager; + const baseLayerInfo = { + id: 'wmts100', + title: 'wmts100', + layers: [ + { + id: 'wmts100', + type: 'raster', + source: 'wmts100', + minzoom: 0, + maxzoom: 12 + } + ], + sources: { + wmts100: { + type: 'raster', + tiles: [ + 'http:/localhost:8195/portalproxy/97d2edb85b0cb5d4/iserver/services/map-China100-2/wmts100?service=WMTS&request=GetTile&version=1.0.0&style=default&layer=China&tilematrixSet=Custom_China&format=image%2Fpng&tilematrix={z}&tilerow={y}&tilecol={x}' + ], + maxzoom: 12, + tileSize: 256, + bounds: [-180, -85.05112877980652, 180, 85.05112877980648], + minzoom: 0 + } + } + }; beforeEach(() => { mockEvents = {}; @@ -170,34 +195,51 @@ describe('SourceListV2', () => { } } ]; + sources = { + graticuleLayer_1723443238046_line: { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [] + } + } + }; + overlayLayersManager = { + graticuleLayer_1723443238046: { + id: 'graticuleLayer_1723443238046', + overlay: true, + renderingMode: '3d', + type: 'custom', + visible: true, + sourceId: 'graticuleLayer_1723443238046_line' + } + }; map = { + addLayer: function (layer) { + layers.push(layer); + }, + addSource(sourceId, source) { + sources[sourceId] = source; + }, getStyle() { return { - layers + layers, + sources }; }, - getSource() { - return { - type: 'geojson', - data: { - type: 'FeatureCollection', - features: [] - } - }; + getSource(id) { + return sources[id]; }, getLayer(id) { return layers.find((layer) => layer.id === id); }, - overlayLayersManager: { - graticuleLayer_1723443238046: { - id: 'graticuleLayer_1723443238046', - overlay: true, - renderingMode: '3d', - type: 'custom', - visible: true, - sourceId: 'graticuleLayer_1723443238046_line' - } + removeLayer(id) { + return layers.splice(layers.findIndex((layer) => layer.id === id), 1); + }, + removeSource(id) { + delete sources[id]; }, + overlayLayersManager, on(type, callback) { mockEvents[type] = callback; }, @@ -561,4 +603,398 @@ describe('SourceListV2', () => { expect(mockEvents.styledata).not.toBeUndefined(); mockEvents.styledata(); }); + + it('changeBaseLayer not complicit', (done) => { + const layersInfo = [ + { + layerType: 'TIANDITU_IMG_3857', + labelLayerVisible: true, + tk: '50599c913367188e6c94e872032f4cf1', + name: '天地图影像', + title: '天地图影像', + renderLayers: ['天地图影像', '天地图影像-tdt-label'], + metadata: { + SM_Layer_Id: '天地图影像' + }, + id: '天地图影像', + visible: true, + reused: false + }, + { + layerType: 'UNIQUE', + visible: true, + themeSetting: { + themeField: 'parent', + customSettings: { + '{"adcode":110000}': { + strokeWidth: 1, + fillColor: '#D53E4F', + fillOpacity: 0.9, + lineDash: 'solid', + strokeColor: '#ffffff', + type: 'POLYGON', + strokeOpacity: 1 + } + }, + colors: ['#D53E4F', '#FC8D59', '#FEE08B', '#FFFFBF', '#E6F598', '#99D594', '#3288BD'] + }, + name: '北京市(3)', + featureType: 'POLYGON', + style: { + strokeWidth: 1, + fillColor: '#D53E4F', + fillOpacity: 0.9, + lineDash: 'solid', + strokeColor: '#ffffff', + type: 'POLYGON', + strokeOpacity: 1 + }, + projection: 'EPSG:4326', + enableFields: [ + 'parent', + 'adcode', + 'level', + 'childrenNum', + 'smpid', + 'centroid', + 'center', + 'subFeatureIndex', + 'name', + 'acroutes' + ], + dataSource: { + accessType: 'DIRECT', + type: 'PORTAL_DATA', + serverId: '1371715657' + }, + layerID: '北京市(3)', + renderLayers: ['北京市(3)', '北京市(3)-strokeLine'], + metadata: { + SM_Layer_Id: '北京市(3)' + }, + id: '北京市(3)', + reused: false + } + ]; + layers = [ + { + id: '天地图影像', + type: 'raster', + source: '天地图影像', + metadata: { + SM_Layer_Id: '天地图影像' + }, + minzoom: 0, + maxzoom: 22, + layout: { + visibility: 'visible' + } + }, + { + id: '天地图影像-tdt-label', + type: 'raster', + source: '天地图影像-tdt-label', + metadata: { + SM_Layer_Id: '天地图影像' + }, + minzoom: 0, + maxzoom: 22, + layout: { + visibility: 'visible' + } + }, + { + id: '北京市(3)', + type: 'fill', + source: '北京市(3)', + metadata: { + SM_Layer_Id: '北京市(3)' + }, + minzoom: 0, + maxzoom: 22, + layout: { + visibility: 'visible' + }, + paint: { + 'fill-color': '#D53E4F', + 'fill-opacity': 0.9 + } + }, + { + id: '北京市(3)-strokeLine', + type: 'line', + source: '北京市(3)', + metadata: { + SM_Layer_Id: '北京市(3)' + }, + minzoom: 0, + maxzoom: 22, + filter: ['all'], + layout: { + visibility: 'visible' + }, + paint: { + 'line-width': 1, + 'line-color': '#ffffff', + 'line-opacity': 1 + } + } + ]; + sources = { + '北京市(3)': { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [] + } + }, + '天地图影像': { + type: 'raster', + tiles: [ + 'https://t0.tianditu.gov.cn/img_w/wmts?tk=50599c913367188e6c94e872032f4cf1&service=WMTS&request=GetTile&style=default&version=1.0.0&layer=img&tilematrixSet=w&format=tiles&width=256&height=256&tilematrix={z}&tilerow={y}&tilecol={x}' + ], + minzoom: 0, + maxzoom: 22, + tileSize: 256, + rasterSource: '', + prjCoordSys: '', + proxy: null, + bounds: [-180, -90, 180, 90] + }, + '天地图影像-tdt-label': { + type: 'raster', + tiles: [ + 'https://t0.tianditu.gov.cn/cia_w/wmts?tk=50599c913367188e6c94e872032f4cf1&service=WMTS&request=GetTile&style=default&version=1.0.0&layer=cia&tilematrixSet=w&format=tiles&width=256&height=256&tilematrix={z}&tilerow={y}&tilecol={x}' + ], + minzoom: 0, + maxzoom: 22, + tileSize: 256, + rasterSource: '', + prjCoordSys: '', + proxy: null, + bounds: [-180, -90, 180, 90] + } + }; + overlayLayersManager = {}; + + const sourceListModel = new SourceListModelV2({ map, layers: layersInfo }); + expect(map.getStyle().layers.some(item => ['天地图影像', '天地图影像-tdt-label'].includes(item.id))).toBeTruthy(); + const layerList = sourceListModel.getLayerCatalog(); + const appreciableLayers = sourceListModel.getLayers(); + expect(layerList.length).toBe(2); + expect(appreciableLayers.length).toBe(2); + const nextBaseLayerInfo = sourceListModel.changeBaseLayer(baseLayerInfo); + expect(nextBaseLayerInfo).toBeTruthy(); + expect(nextBaseLayerInfo.layers.length).toBe(1); + expect(nextBaseLayerInfo.layers).toEqual(baseLayerInfo.layers); + expect(map.getStyle().layers.some(item => ['天地图影像', '天地图影像-tdt-label'].includes(item.id))).toBeFalsy(); + done(); + }); + + it('changeBaseLayer complicit', (done) => { + const layersInfo = [ + { + layerType: 'raster', + name: 'wmts100', + title: 'wmts100', + renderLayers: ['wmts100'], + metadata: { + SM_Layer_Id: 'wmts100' + }, + id: 'wmts100', + visible: true, + reused: false + }, + { + layerType: 'TIANDITU_IMG_3857', + labelLayerVisible: true, + tk: '50599c913367188e6c94e872032f4cf1', + name: '天地图影像', + title: '天地图影像', + renderLayers: ['天地图影像', '天地图影像-tdt-label'], + metadata: { + SM_Layer_Id: '天地图影像' + }, + id: '天地图影像', + visible: true, + reused: false + }, + { + layerType: 'UNIQUE', + visible: true, + themeSetting: { + themeField: 'parent', + customSettings: { + '{"adcode":110000}': { + strokeWidth: 1, + fillColor: '#D53E4F', + fillOpacity: 0.9, + lineDash: 'solid', + strokeColor: '#ffffff', + type: 'POLYGON', + strokeOpacity: 1 + } + }, + colors: ['#D53E4F', '#FC8D59', '#FEE08B', '#FFFFBF', '#E6F598', '#99D594', '#3288BD'] + }, + name: '北京市(3)', + featureType: 'POLYGON', + style: { + strokeWidth: 1, + fillColor: '#D53E4F', + fillOpacity: 0.9, + lineDash: 'solid', + strokeColor: '#ffffff', + type: 'POLYGON', + strokeOpacity: 1 + }, + projection: 'EPSG:4326', + enableFields: [ + 'parent', + 'adcode', + 'level', + 'childrenNum', + 'smpid', + 'centroid', + 'center', + 'subFeatureIndex', + 'name', + 'acroutes' + ], + dataSource: { + accessType: 'DIRECT', + type: 'PORTAL_DATA', + serverId: '1371715657' + }, + layerID: '北京市(3)', + renderLayers: ['北京市(3)', '北京市(3)-strokeLine'], + metadata: { + SM_Layer_Id: '北京市(3)' + }, + id: '北京市(3)', + reused: false + } + ]; + layers = [ + ...baseLayerInfo.layers, + { + id: '天地图影像', + type: 'raster', + source: '天地图影像', + metadata: { + SM_Layer_Id: '天地图影像' + }, + minzoom: 0, + maxzoom: 22, + layout: { + visibility: 'visible' + } + }, + { + id: '天地图影像-tdt-label', + type: 'raster', + source: '天地图影像-tdt-label', + metadata: { + SM_Layer_Id: '天地图影像' + }, + minzoom: 0, + maxzoom: 22, + layout: { + visibility: 'visible' + } + }, + { + id: '北京市(3)-strokeLine', + type: 'line', + source: '北京市(3)', + metadata: { + SM_Layer_Id: '北京市(3)' + }, + minzoom: 0, + maxzoom: 22, + filter: ['all'], + layout: { + visibility: 'visible' + }, + paint: { + 'line-width': 1, + 'line-color': '#ffffff', + 'line-opacity': 1 + } + } + ]; + sources = { + '北京市(3)': { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [] + } + }, + '天地图影像': { + type: 'raster', + tiles: [ + 'https://t0.tianditu.gov.cn/img_w/wmts?tk=50599c913367188e6c94e872032f4cf1&service=WMTS&request=GetTile&style=default&version=1.0.0&layer=img&tilematrixSet=w&format=tiles&width=256&height=256&tilematrix={z}&tilerow={y}&tilecol={x}' + ], + minzoom: 0, + maxzoom: 22, + tileSize: 256, + rasterSource: '', + prjCoordSys: '', + proxy: null, + bounds: [-180, -90, 180, 90] + }, + '天地图影像-tdt-label': { + type: 'raster', + tiles: [ + 'https://t0.tianditu.gov.cn/cia_w/wmts?tk=50599c913367188e6c94e872032f4cf1&service=WMTS&request=GetTile&style=default&version=1.0.0&layer=cia&tilematrixSet=w&format=tiles&width=256&height=256&tilematrix={z}&tilerow={y}&tilecol={x}' + ], + minzoom: 0, + maxzoom: 22, + tileSize: 256, + rasterSource: '', + prjCoordSys: '', + proxy: null, + bounds: [-180, -90, 180, 90] + }, + ...baseLayerInfo.sources + }; + overlayLayersManager = {}; + + const sourceListModel = new SourceListModelV2({ map, layers: layersInfo }); + expect(map.getStyle().layers.some(item => ['天地图影像', '天地图影像-tdt-label'].includes(item.id))).toBeTruthy(); + expect(map.getStyle().layers.some(item => ['wmts100'].includes(item.id))).toBeTruthy(); + let layerList = sourceListModel.getLayerCatalog(); + let appreciableLayers = sourceListModel.getLayers(); + expect(layerList.length).toBe(3); + expect(layerList[layerList.length - 1].id).toBe('wmts100'); + expect(appreciableLayers.length).toBe(3); + expect(appreciableLayers[0].id).toBe('wmts100'); + const sameBaseLayer = { + id: 'sameBaseLayer', + layers: layers.slice(1, 3).map(item => { + const nextItem = Object.assign({}, item); + nextItem.metadata = { SM_Layer_Id: 'sameBaseLayer' }; + return nextItem; + }), + sources: { + '天地图影像': sources['天地图影像'], + '天地图影像-tdt-label': sources['天地图影像-tdt-label'] + } + } + const nextBaseLayerInfo = sourceListModel.changeBaseLayer(sameBaseLayer); + expect(nextBaseLayerInfo).toBeTruthy(); + expect(nextBaseLayerInfo.layers.length).toBe(2); + expect(nextBaseLayerInfo.layers).not.toEqual(sameBaseLayer.layers); + expect(map.getStyle().layers.some(item => ['天地图影像', '天地图影像-tdt-label'].includes(item.id))).toBeTruthy(); + expect(map.getStyle().layers.some(item => [/天地图影像_\d+$/, /天地图影像-tdt-label_\d+$/].some(reg => reg.test(item.id)))).toBeTruthy(); + expect(map.getStyle().layers.some(item => ['wmts100'].includes(item.id))).toBeFalsy(); + layerList = sourceListModel.getLayerCatalog(); + appreciableLayers = sourceListModel.getLayers(); + expect(layerList.length).toBe(3); + expect(layerList[layerList.length - 1].id).toBe('sameBaseLayer'); + expect(appreciableLayers.length).toBe(3); + expect(appreciableLayers[0].id).toBe('sameBaseLayer'); + done(); + }); }); diff --git a/test/common/mapping/utils/SourceListModelV3Spec.js b/test/common/mapping/utils/SourceListModelV3Spec.js index c5d801c8b5..3a81d0102b 100644 --- a/test/common/mapping/utils/SourceListModelV3Spec.js +++ b/test/common/mapping/utils/SourceListModelV3Spec.js @@ -1,9 +1,140 @@ import { SourceListModelV3 } from '../../../../src/common/mapping/utils/SourceListModelV3'; import { isL7Layer } from '../../../../src/common/mapping/utils/L7LayerUtil'; import '../../../resources/WebMapV3.js'; +import cloneDeep from 'lodash.clonedeep'; describe('SourceListV3', () => { - let map, layers, mockEvents; + let map, layers, sources, mockEvents, overlayLayersManager; + const baseLayerInfo = { + id: 'wmts100', + title: 'wmts100', + layers: [ + { + id: 'wmts100', + type: 'raster', + source: 'wmts100', + minzoom: 0, + maxzoom: 12 + } + ], + sources: { + wmts100: { + type: 'raster', + tiles: [ + 'http:/localhost:8195/portalproxy/97d2edb85b0cb5d4/iserver/services/map-China100-2/wmts100?service=WMTS&request=GetTile&version=1.0.0&style=default&layer=China&tilematrixSet=Custom_China&format=image%2Fpng&tilematrix={z}&tilerow={y}&tilecol={x}' + ], + maxzoom: 12, + tileSize: 256, + bounds: [-180, -85.05112877980652, 180, 85.05112877980648], + minzoom: 0 + } + } + }; + const changeBaseLayerMapInfo = { + metadata: { + layerCatalog: [ + { + visible: true, + parts: ['北京市住宅小区'], + id: 'layer_北京市住宅小区_1754359974753_24', + title: '北京市住宅小区', + type: 'composite' + }, + { + visible: true, + children: [ + { + visible: true, + id: 'ms_TIANDITU_IMG_3857_label', + title: 'ms_TIANDITU_IMG_3857_label', + type: 'basic' + }, + { + visible: true, + id: 'TIANDITU_IMG_3857', + title: 'TIANDITU_IMG_3857', + type: 'basic' + } + ], + id: 'group_tianditu_img_3857_1754377584218_382', + title: 'tianditu_img_3857', + type: 'group' + } + ] + }, + sources: { + ms_TIANDITU_IMG_3857_label: { + tiles: [ + 'https://t0.tianditu.gov.cn/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=50599c913367188e6c94e872032f4cf1&host=172.16.14.44:8190' + ], + tileSize: 256, + attribution: '', + bounds: [-180, -90, 180, 90], + type: 'raster' + }, + ms_1750973565_1754359974753_23: { + tiles: [ + 'http://localhost:8190/iportal/web/datas/1750973565/structureddata/tiles/{z}/{x}/{y}.mvt?epsgCode=3857&returnedFieldNames=%5B%22smpid%22%2C%22%E5%B0%8F%E5%8C%BA%E5%90%8D%22%2C%22SmGeometrySize%22%2C%22%E5%B9%B4%E4%BB%A3%22%2C%22%E5%8D%95%E4%BB%B7%22%2C%22%E6%A5%BC%E5%B1%82%22%2C%22SmID%22%2C%22%E6%80%BB%E4%BB%B7%22%2C%22SmUserID%22%2C%22%E6%88%B7%E5%9E%8B%22%2C%22%E6%9C%9D%E5%90%91%22%2C%22%E5%9C%B0%E5%9D%80%22%2C%22SmY%22%2C%22SmX%22%2C%22SmLibTileID%22%2C%22%E9%9D%A2%E7%A7%AF%22%5D&geometryFieldName=geometry' + ], + bounds: [115.89763001613301, 39.40606, 117.48732001635402, 40.6500100064203], + type: 'vector' + }, + TIANDITU_IMG_3857: { + tiles: [ + 'https://t0.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=50599c913367188e6c94e872032f4cf1&host=172.16.14.44:8190' + ], + tileSize: 256, + attribution: '', + bounds: [-180, -90, 180, 90], + type: 'raster' + } + }, + crs: 'EPSG:3857', + center: [116.22715983919534, 39.878220196575874], + zoom: 8.79189646012174, + glyphs: {}, + version: '3.3.2', + maxzoom: 19, + name: '无标题地图-tianditu', + layers: [ + { + maxzoom: 19, + id: 'TIANDITU_IMG_3857', + source: 'TIANDITU_IMG_3857', + type: 'raster', + minzoom: 0 + }, + { + layout: { + visibility: 'visible' + }, + maxzoom: 19, + id: 'ms_TIANDITU_IMG_3857_label', + source: 'ms_TIANDITU_IMG_3857_label', + type: 'raster', + minzoom: 0 + }, + { + metadata: {}, + maxzoom: 24, + paint: { + 'circle-color': '#EE4D5A', + 'circle-opacity': 0.9, + 'circle-translate-anchor': 'map', + 'circle-radius': 4, + 'circle-translate': [0, 0] + }, + id: '北京市住宅小区', + source: 'ms_1750973565_1754359974753_23', + 'source-layer': '1750973565$geometry', + type: 'circle', + minzoom: 0 + } + ], + sprite: 'http://localhost:8190/iportal/web/maps/1874751978/sprites/sprite', + pitch: 0, + minzoom: 0 + }; beforeEach(() => { mockEvents = {}; @@ -111,7 +242,7 @@ describe('SourceListV3', () => { 'line-opacity': 0.8 } }, - + { id: 'mapbox-gl-draw', type: 'line', @@ -172,34 +303,104 @@ describe('SourceListV3', () => { } } ]; + sources = { + CHINA_DARK: { + type: 'raster', + tiles: [] + }, + 'test-source': { + type: 'raster', + tiles: [] + }, + 'tracklayer-1-line': { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [] + } + }, + graticuleLayer_1_line: { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [] + } + }, + 'tdt-search-line': { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [] + } + }, + 'tdt-route-line': { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [] + } + }, + smmeasure: { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [] + } + }, + 'mapbox-gl-draw': { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [] + } + }, + graticuleLayer_1723443238046_line: { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [] + } + } + }; + overlayLayersManager = { + graticuleLayer_1723443238046: { + id: 'graticuleLayer_1723443238046', + overlay: true, + renderingMode: '3d', + type: 'custom', + visible: true, + sourceId: 'graticuleLayer_1723443238046_line' + } + }; map = { + addLayer: function (layer) { + layers.push(layer); + }, + addSource(sourceId, source) { + sources[sourceId] = source; + }, getStyle() { return { - layers + layers, + sources }; }, - getSource() { - return { - type: 'geojson', - data: { - type: 'FeatureCollection', - features: [] - } - }; + getSource(id) { + return sources[id]; }, getLayer(id) { return layers.find((layer) => layer.id === id); }, - overlayLayersManager: { - graticuleLayer_1723443238046: { - id: 'graticuleLayer_1723443238046', - overlay: true, - renderingMode: '3d', - type: 'custom', - visible: true, - sourceId: 'graticuleLayer_1723443238046_line' - } + removeLayer(id) { + return layers.splice( + layers.findIndex((layer) => layer.id === id), + 1 + ); }, + removeSource(id) { + delete sources[id]; + }, + overlayLayersManager, on(type, callback) { mockEvents[type] = callback; }, @@ -298,9 +499,9 @@ describe('SourceListV3', () => { }); const layerList = sourceListModel.getLayerCatalog(); expect(layerList.length).toBe(mapInfo.metadata.layerCatalog.length + 3); - const selfIds = mapInfo.metadata.layerCatalog.map(item => item.id); - const selfLayerCatalogs = layerList.filter(layer => selfIds.includes(layer.id)); - expect(selfLayerCatalogs.some(layer => !layer.renderLayers.includes(layer.id))).toBe(false); + const selfIds = mapInfo.metadata.layerCatalog.map((item) => item.id); + const selfLayerCatalogs = layerList.filter((layer) => selfIds.includes(layer.id)); + expect(selfLayerCatalogs.some((layer) => !layer.renderLayers.includes(layer.id))).toBe(false); done(); }); @@ -318,9 +519,9 @@ describe('SourceListV3', () => { }); const layerList = sourceListModel.getLayerCatalog(); expect(layerList.length).toBe(mapInfo.metadata.layerCatalog.length + 2); - const selfIds = mapInfo.metadata.layerCatalog.map(item => item.id); - const selfLayerCatalogs = layerList.filter(layer => selfIds.includes(layer.id)); - expect(selfLayerCatalogs.some(layer => !layer.renderLayers.includes(layer.id))).toBe(false); + const selfIds = mapInfo.metadata.layerCatalog.map((item) => item.id); + const selfLayerCatalogs = layerList.filter((layer) => selfIds.includes(layer.id)); + expect(selfLayerCatalogs.some((layer) => !layer.renderLayers.includes(layer.id))).toBe(false); done(); }); @@ -338,9 +539,9 @@ describe('SourceListV3', () => { }); const layerList = sourceListModel.getLayerCatalog(); expect(layerList.length).toBe(mapInfo.metadata.layerCatalog.length + 3); - const selfIds = mapInfo.metadata.layerCatalog.filter(item => item.parts).map(item => item.id); - const selfLayerCatalogs = layerList.filter(layer => selfIds.includes(layer.id)); - expect(selfLayerCatalogs.some(layer => layer.renderLayers.includes(layer.id))).toBe(false); + const selfIds = mapInfo.metadata.layerCatalog.filter((item) => item.parts).map((item) => item.id); + const selfLayerCatalogs = layerList.filter((layer) => selfIds.includes(layer.id)); + expect(selfLayerCatalogs.some((layer) => layer.renderLayers.includes(layer.id))).toBe(false); done(); }); @@ -367,9 +568,9 @@ describe('SourceListV3', () => { const markerList = { ['中国金牌个人获奖者(1)']: { show: jasmine.createSpy('show').and.callFake(() => {}), - hide: jasmine.createSpy('hide').and.callFake(() => {}), + hide: jasmine.createSpy('hide').and.callFake(() => {}) } - } + }; const sourceListModel = new SourceListModelV3({ map, mapInfo, @@ -401,9 +602,9 @@ describe('SourceListV3', () => { const markerList = { ['中国金牌个人获奖者(1)']: { show: jasmine.createSpy('show').and.callFake(() => {}), - hide: jasmine.createSpy('hide').and.callFake(() => {}), + hide: jasmine.createSpy('hide').and.callFake(() => {}) } - } + }; const sourceListModel = new SourceListModelV3({ map, mapInfo, @@ -435,9 +636,9 @@ describe('SourceListV3', () => { const markerList = { ['中国金牌个人获奖者(1)']: { show: jasmine.createSpy('show').and.callFake(() => {}), - hide: jasmine.createSpy('hide').and.callFake(() => {}), + hide: jasmine.createSpy('hide').and.callFake(() => {}) } - } + }; const sourceListModel = new SourceListModelV3({ map, mapInfo, @@ -487,4 +688,111 @@ describe('SourceListV3', () => { expect(mockEvents.styledata).not.toBeUndefined(); mockEvents.styledata(); }); + + it('changeBaseLayer not complicit', (done) => { + const nextBaseLayerMapInfo = cloneDeep(changeBaseLayerMapInfo); + layers = nextBaseLayerMapInfo.layers; + sources = nextBaseLayerMapInfo.sources; + + overlayLayersManager = {}; + + const sourceListModel = new SourceListModelV3({ + map, + mapInfo: cloneDeep(nextBaseLayerMapInfo), + mapResourceInfo: {}, + legendList: [], + l7LayerUtil: { + isL7Layer, + getL7MarkerLayers: () => [] + } + }); + expect(map.getStyle().layers.some((item) => ['TIANDITU_IMG_3857', 'ms_TIANDITU_IMG_3857_label'].includes(item.id))).toBeTruthy(); + const layerList = sourceListModel.getLayerCatalog(); + const appreciableLayers = sourceListModel.getLayers(); + expect(layerList.length).toBe(2); + expect(appreciableLayers.length).toBe(3); + const nextBaseLayerInfo = sourceListModel.changeBaseLayer(baseLayerInfo); + expect(nextBaseLayerInfo).toBeTruthy(); + expect(nextBaseLayerInfo.layers.length).toBe(1); + expect(nextBaseLayerInfo.layers).toEqual(baseLayerInfo.layers); + expect(map.getStyle().layers.some((item) => ['TIANDITU_IMG_3857', 'ms_TIANDITU_IMG_3857_label'].includes(item.id))).toBeFalsy(); + done(); + }); + + it('changeBaseLayer complicit', (done) => { + let nextBaseLayerMapInfo = cloneDeep(changeBaseLayerMapInfo); + layers = [ + ...baseLayerInfo.layers, + ...nextBaseLayerMapInfo.layers + ]; + sources = { + ...nextBaseLayerMapInfo.sources, + ...baseLayerInfo.sources + }; + const copyMapInfo = cloneDeep(changeBaseLayerMapInfo); + nextBaseLayerMapInfo = { + ...copyMapInfo, + layers: cloneDeep(layers), + sources: cloneDeep(sources), + metadata: { + layerCatalog: copyMapInfo.metadata.layerCatalog.concat(baseLayerInfo.layers.map(item => ({ + id: item.id, + title: item.id, + type: 'basic', + visible: true + }))) + } + } + overlayLayersManager = {}; + + const sourceListModel = new SourceListModelV3({ + map, + mapInfo: nextBaseLayerMapInfo, + mapResourceInfo: {}, + legendList: [], + l7LayerUtil: { + isL7Layer, + getL7MarkerLayers: () => [] + } + }); + expect(map.getStyle().layers.some((item) => ['TIANDITU_IMG_3857', 'ms_TIANDITU_IMG_3857_label'].includes(item.id))).toBeTruthy(); + expect(map.getStyle().layers.some((item) => ['wmts100'].includes(item.id))).toBeTruthy(); + let layerList = sourceListModel.getLayerCatalog(); + let appreciableLayers = sourceListModel.getLayers(); + expect(layerList.length).toBe(3); + expect(layerList[layerList.length - 1].id).toBe('wmts100'); + expect(appreciableLayers.length).toBe(4); + expect(appreciableLayers[0].id).toBe('wmts100'); + const sameBaseLayer = { + id: 'sameBaseLayer', + layers: layers.slice(1, 3).map((item) => { + const nextItem = Object.assign({}, item); + nextItem.metadata = { SM_Layer_Id: 'sameBaseLayer' }; + return nextItem; + }), + sources: { + TIANDITU_IMG_3857: sources['TIANDITU_IMG_3857'], + 'ms_TIANDITU_IMG_3857_label': sources['ms_TIANDITU_IMG_3857_label'] + } + }; + const nextBaseLayerInfo = sourceListModel.changeBaseLayer(sameBaseLayer); + expect(nextBaseLayerInfo).toBeTruthy(); + expect(nextBaseLayerInfo.layers.length).toBe(2); + expect(nextBaseLayerInfo.layers).not.toEqual(sameBaseLayer.layers); + expect(map.getStyle().layers.some((item) => ['TIANDITU_IMG_3857', 'ms_TIANDITU_IMG_3857_label'].includes(item.id))).toBeTruthy(); + expect( + map + .getStyle() + .layers.some((item) => [/TIANDITU_IMG_3857_\d+$/, /ms_TIANDITU_IMG_3857_label_\d+$/].some((reg) => reg.test(item.id))) + ).toBeTruthy(); + expect(map.getStyle().layers.some((item) => ['wmts100'].includes(item.id))).toBeFalsy(); + layerList = sourceListModel.getLayerCatalog(); + appreciableLayers = sourceListModel.getLayers(); + expect(layerList.length).toBe(3); + expect(layerList[layerList.length - 1].id).toBe('sameBaseLayer'); + expect(appreciableLayers.length).toBe(5); + expect(appreciableLayers[0].id.match(/TIANDITU_IMG_3857_TIANDITU_IMG_3857_\d+$/)).toBeTruthy(); + expect(appreciableLayers[1].id.match(/ms_TIANDITU_IMG_3857_label_ms_TIANDITU_IMG_3857_label_\d+$/)).toBeTruthy(); + done(); + }); }); From b9f33eb37fccd86fe893c426a75fcd7267058003 Mon Sep 17 00:00:00 2001 From: xiongjj Date: Wed, 13 Aug 2025 15:01:37 +0800 Subject: [PATCH 02/13] =?UTF-8?q?=E3=80=90ut=E3=80=91fix=20ut?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/maplibregl/overlay/GraticuleLayerSpec.js | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/test/maplibregl/overlay/GraticuleLayerSpec.js b/test/maplibregl/overlay/GraticuleLayerSpec.js index 36aab46ede..40c25b2ffb 100644 --- a/test/maplibregl/overlay/GraticuleLayerSpec.js +++ b/test/maplibregl/overlay/GraticuleLayerSpec.js @@ -1,6 +1,5 @@ import maplibregl from 'maplibre-gl'; import { GraticuleLayer } from '../../../src/maplibregl/overlay/GraticuleLayer'; -var url = GlobeParameter.ChinaURL + '/zxyTileImage.png?z={z}&x={x}&y={y}'; describe('maplibregl_GraticuleLayer', () => { var originalTimeout; @@ -18,22 +17,8 @@ describe('maplibregl_GraticuleLayer', () => { container: 'map', style: { version: 8, - sources: { - 'raster-tiles': { - type: 'raster', - tiles: [url], - tileSize: 256 - } - }, - layers: [ - { - id: 'simple-tiles', - type: 'raster', - source: 'raster-tiles', - minzoom: 0, - maxzoom: 22 - } - ] + sources: {}, + layers: [] }, center: [112, 37.94], zoom: 3 From 6e72c6f052d8ad7e4c667c55d49dd8664ce198ad Mon Sep 17 00:00:00 2001 From: xiongjj Date: Fri, 15 Aug 2025 20:20:22 +0800 Subject: [PATCH 03/13] =?UTF-8?q?=E3=80=90update=E3=80=91=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E5=BA=95=E5=9B=BE=EF=BC=8Ctitle=E4=BC=98=E5=8C=96;=20?= =?UTF-8?q?review=20by=20songym?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/mapping/utils/SourceListModelV3.js | 6 ++- .../mapping/utils/SourceListModelV3Spec.js | 45 ++++++++++++++++++- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/common/mapping/utils/SourceListModelV3.js b/src/common/mapping/utils/SourceListModelV3.js index b982531949..e1b912f9cb 100644 --- a/src/common/mapping/utils/SourceListModelV3.js +++ b/src/common/mapping/utils/SourceListModelV3.js @@ -58,11 +58,12 @@ export class SourceListModelV3 extends AppreciableLayerBase { const originBaseLayerCatalog = nextLayerCatalog.pop(); this._removeBaseLayerRenderLayers(originBaseLayerCatalog, nextLayers); const baseLayers = layerItem.layers.map((layer) => { + const title = layer.metadata && layer.metadata.title; return { ...layer, layerInfo: { id: layer.id, - title: layer.id, + title: title || layer.id, renderLayers: [layer.id] } }; @@ -80,9 +81,10 @@ export class SourceListModelV3 extends AppreciableLayerBase { baseLayerCatalog.id = layerItem.id || defaultId; baseLayerCatalog.type = 'group'; baseLayerCatalog.children = layerItem.layers.map((layer) => { + const title = layer.metadata && layer.metadata.title; return { id: layer.id, - title: layer.id, + title: title || layer.id, type: 'basic', visible: true }; diff --git a/test/common/mapping/utils/SourceListModelV3Spec.js b/test/common/mapping/utils/SourceListModelV3Spec.js index 3a81d0102b..4e1590dae3 100644 --- a/test/common/mapping/utils/SourceListModelV3Spec.js +++ b/test/common/mapping/utils/SourceListModelV3Spec.js @@ -767,7 +767,7 @@ describe('SourceListV3', () => { id: 'sameBaseLayer', layers: layers.slice(1, 3).map((item) => { const nextItem = Object.assign({}, item); - nextItem.metadata = { SM_Layer_Id: 'sameBaseLayer' }; + nextItem.metadata = { SM_Layer_Id: 'sameBaseLayer', title: `custom_${item.id}` }; return nextItem; }), sources: { @@ -790,9 +790,52 @@ describe('SourceListV3', () => { appreciableLayers = sourceListModel.getLayers(); expect(layerList.length).toBe(3); expect(layerList[layerList.length - 1].id).toBe('sameBaseLayer'); + expect(layerList[layerList.length - 1].children[0].title.match(/custom_TIANDITU_IMG_3857$/)).toBeTruthy(); + expect(layerList[layerList.length - 1].children[1].title.match(/custom_ms_TIANDITU_IMG_3857_label$/)).toBeTruthy(); expect(appreciableLayers.length).toBe(5); expect(appreciableLayers[0].id.match(/TIANDITU_IMG_3857_TIANDITU_IMG_3857_\d+$/)).toBeTruthy(); expect(appreciableLayers[1].id.match(/ms_TIANDITU_IMG_3857_label_ms_TIANDITU_IMG_3857_label_\d+$/)).toBeTruthy(); + expect(appreciableLayers[0].title.match(/custom_TIANDITU_IMG_3857/)).toBeTruthy(); + expect(appreciableLayers[1].title.match(/custom_ms_TIANDITU_IMG_3857_label/)).toBeTruthy(); + done(); + }); + + it('changeBaseLayer show title', (done) => { + const nextBaseLayerMapInfo = cloneDeep(changeBaseLayerMapInfo); + layers = nextBaseLayerMapInfo.layers; + sources = nextBaseLayerMapInfo.sources; + + overlayLayersManager = {}; + + const sourceListModel = new SourceListModelV3({ + map, + mapInfo: cloneDeep(nextBaseLayerMapInfo), + mapResourceInfo: {}, + legendList: [], + l7LayerUtil: { + isL7Layer, + getL7MarkerLayers: () => [] + } + }); + expect(map.getStyle().layers.some((item) => ['TIANDITU_IMG_3857', 'ms_TIANDITU_IMG_3857_label'].includes(item.id))).toBeTruthy(); + const layerList = sourceListModel.getLayerCatalog(); + const appreciableLayers = sourceListModel.getLayers(); + expect(layerList.length).toBe(2); + expect(appreciableLayers.length).toBe(3); + const baseLayerInfoCopy = { + ...baseLayerInfo, + layers: baseLayerInfo.layers.map((item) => ({ + ...item, + metadata: { title: `custom_${item.id}`} + })) + }; + const nextBaseLayerInfo = sourceListModel.changeBaseLayer(baseLayerInfoCopy); + expect(nextBaseLayerInfo).toBeTruthy(); + expect(nextBaseLayerInfo.layers.length).toBe(1); + expect(nextBaseLayerInfo.layers).toEqual(baseLayerInfoCopy.layers); + expect(map.getStyle().layers.some((item) => ['TIANDITU_IMG_3857', 'ms_TIANDITU_IMG_3857_label'].includes(item.id))).toBeFalsy(); + const nextAppreciableLayers = sourceListModel.getLayers(); + expect(nextAppreciableLayers.some(item => item.title === baseLayerInfoCopy.layers[0].metadata.title)).toBeTruthy(); done(); }); }); From 0fc857ffcfa0c1ab9707dbb23d067f7568821c57 Mon Sep 17 00:00:00 2001 From: xiongjj Date: Mon, 18 Aug 2025 16:25:40 +0800 Subject: [PATCH 04/13] =?UTF-8?q?=E3=80=90update=E3=80=91mapstyle=20transf?= =?UTF-8?q?ormRequest=20withcredentials=E7=9A=84=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E5=80=BC=E4=BC=98=E5=8C=96;review=20by=20songym?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/mapping/MapStyle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/mapping/MapStyle.js b/src/common/mapping/MapStyle.js index 555a5d0d2b..cbacf973a4 100644 --- a/src/common/mapping/MapStyle.js +++ b/src/common/mapping/MapStyle.js @@ -39,7 +39,7 @@ export function createMapStyleExtending(SuperClass, { MapManager, crsManager }) } return { url: proxy ? `${proxy}${encodeURIComponent(url)}` : url, - credentials: this.webMapService.handleWithCredentials(proxy, url, this.options.withCredentials || false) + credentials: this.webMapService.handleWithCredentials(proxy, url, false) ? 'include' : undefined, ...(this.options.tileTransformRequest && this.options.tileTransformRequest(url)) From 2a8fe12692041cb5d70c49c7e1ebf4cd07508e6b Mon Sep 17 00:00:00 2001 From: songyumeng Date: Tue, 19 Aug 2025 10:30:01 +0800 Subject: [PATCH 05/13] =?UTF-8?q?=E3=80=90update=E3=80=91antd=20=203.26.20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dist/mapboxgl/include-mapboxgl.js | 4 ++-- dist/maplibregl/include-maplibregl.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dist/mapboxgl/include-mapboxgl.js b/dist/mapboxgl/include-mapboxgl.js index d57cd65d78..32628db0a9 100644 --- a/dist/mapboxgl/include-mapboxgl.js +++ b/dist/mapboxgl/include-mapboxgl.js @@ -118,9 +118,9 @@ inputScript(libsurl + '/ant-design-vue/1.7.8/antd.min.js'); } if (inArray(includes, 'antd')) { - inputCSS(libsurl + '/antd/3.25.3/antd.min.css'); + inputCSS(libsurl + '/antd/3.26.20/antd.min.css'); inputScript(libsurl + '/moment/2.29.4/moment.min.js'); - inputScript(libsurl + '/antd/3.25.3/antd.min.js'); + inputScript(libsurl + '/antd/3.26.20/antd.min.js'); } if (inArray(includes, 'deck')) { inputScript(libsurl + '/deck.gl/5.1.3/deck.gl.min.js'); diff --git a/dist/maplibregl/include-maplibregl.js b/dist/maplibregl/include-maplibregl.js index 4703136c22..c90c019eb2 100644 --- a/dist/maplibregl/include-maplibregl.js +++ b/dist/maplibregl/include-maplibregl.js @@ -111,9 +111,9 @@ inputScript(libsurl + '/ant-design-vue/1.7.8/antd.min.js'); } if (inArray(includes, 'antd')) { - inputCSS(libsurl + '/antd/3.25.3/antd.min.css'); + inputCSS(libsurl + '/antd/3.26.20/antd.min.css'); inputScript(libsurl + '/moment/2.29.4/moment.min.js'); - inputScript(libsurl + '/antd/3.25.3/antd.min.js'); + inputScript(libsurl + '/antd/3.26.20/antd.min.js'); } if (inArray(includes, 'deck')) { inputScript(libsurl + '/deck.gl/5.1.3/deck.gl.min.js'); From 94d85ab15af7ae1932c32663f2dd9d23189a318d Mon Sep 17 00:00:00 2001 From: songyumeng Date: Wed, 3 Sep 2025 15:36:06 +0800 Subject: [PATCH 06/13] =?UTF-8?q?=E3=80=90fix=E3=80=91webmap=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E5=9B=BE=E5=B1=82=E6=97=B6=E5=9B=BE=E5=B1=82=E7=9A=84?= =?UTF-8?q?=E6=9C=80=E5=A4=A7=E7=BA=A7=E5=88=AB=E4=B8=BA=E5=9C=B0=E5=9B=BE?= =?UTF-8?q?=E6=9C=80=E5=A4=A7=E7=BA=A7=E5=88=AB+1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/mapping/WebMapV2.js | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/common/mapping/WebMapV2.js b/src/common/mapping/WebMapV2.js index 00519e4db1..782df7a812 100644 --- a/src/common/mapping/WebMapV2.js +++ b/src/common/mapping/WebMapV2.js @@ -445,7 +445,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa const { minScale, maxScale } = layer.visibleScale; const crs = this.map.getCRS(); layer.minzoom = Math.max(this._transformScaleToZoom(minScale, crs, layer.tileSize), 0); - layer.maxzoom = Math.min(24, this._transformScaleToZoom(maxScale, crs, layer.tileSize) + 0.0000001); + layer.maxzoom = Math.min(this.map.getMaxZoom()+1, this._transformScaleToZoom(maxScale, crs, layer.tileSize) + 0.0000001); } if (type === 'tile') { @@ -752,7 +752,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa return resolutions.every((item, i) => this.numberEqual(item, conversion * mapResolutions[i])); } _getMapResolutions() { - return this._getResolutionsByExtent({extent: this.map.getCRS().getExtent(), tileSize: 512}) + return this._getResolutionsByExtent({extent: this.map.getCRS().getExtent(), maxZoom: this.map.getMaxZoom() + 1, tileSize: 512}) } _getResolutionsByExtent({ extent, maxZoom = 24, tileSize }) { const width = extent[2] - extent[0]; @@ -1375,7 +1375,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa }, layout, minzoom: minzoom || 0, - maxzoom: maxzoom || 22 + maxzoom: maxzoom || this.map.getMaxZoom() + 1 }, layerInfo.layerID ); @@ -1427,7 +1427,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa visibility: layerInfo.visible }, minzoom: minzoom || 0, - maxzoom: maxzoom || 22 + maxzoom: maxzoom || this.map.getMaxZoom() + 1 }; if (filter) { layerOptions.filter = filter; @@ -1482,7 +1482,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa 'icon-rotate': iconRotateExpression || ((layerInfo.style.rotation || 0) * 180) / Math.PI }, minzoom: minzoom || 0, - maxzoom: maxzoom || 22 + maxzoom: maxzoom || this.map.getMaxZoom() + 1 }; if (filter) { layerOptions.filter = filter; @@ -1534,7 +1534,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa 'icon-color': style.fillColor }, minzoom: minzoom || 0, - maxzoom: maxzoom || 22 + maxzoom: maxzoom || this.map.getMaxZoom() + 1 }; if (filter) { layerOptions.filter = filter; @@ -1838,7 +1838,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa visibility: visible }, minzoom: minzoom || 0, - maxzoom: maxzoom || 22 + maxzoom: maxzoom || this.map.getMaxZoom() + 1 }; if (filterExpression.length > 1) { layerOptions.filter = filterExpression; @@ -1956,7 +1956,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa 'icon-rotate': symbolStyle.rotation || 0 }, minzoom: minzoom || 0, - maxzoom: maxzoom || 22, + maxzoom: maxzoom || this.map.getMaxZoom() + 1, filter: imagefilterExpression }, layerID @@ -1991,7 +1991,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa 'icon-color': symbolStyle.fillColor }, minzoom: minzoom || 0, - maxzoom: maxzoom || 22, + maxzoom: maxzoom || this.map.getMaxZoom() + 1, filter: svgfilterExpression }, layerID @@ -2162,7 +2162,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa paint: this._transformStyleToMapBoxGl(defaultStyle, geomType), layout: {}, minzoom: minzoom || 0, - maxzoom: maxzoom || 22 + maxzoom: maxzoom || this.map.getMaxZoom() + 1 }, markerLayerID ); @@ -2180,7 +2180,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa visibility: layerInfo.visible }, minzoom: minzoom || 0, - maxzoom: maxzoom || 22 + maxzoom: maxzoom || this.map.getMaxZoom() + 1 }, markerLayerID ); @@ -2284,7 +2284,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa visibility: layerInfo.visible }, minzoom: minzoom || 0, - maxzoom: maxzoom || 22 + maxzoom: maxzoom || this.map.getMaxZoom() + 1 }); if (addToMap) { this._addLayerSucceeded({ layerInfo, features }); @@ -2491,7 +2491,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa paint: layerStyle.style, layout: layerStyle.layout || {}, minzoom: minzoom || 0, - maxzoom: maxzoom || 22 + maxzoom: maxzoom || this.map.getMaxZoom() + 1 }; if (filter) { style.filter = filter; @@ -2506,7 +2506,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa parentLayerId, visibility = true, minzoom = 0, - maxzoom = 22, + maxzoom, isIserver = false, tileSize = 256, bounds @@ -2515,7 +2515,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa type: 'raster', tiles: url, minzoom: minzoom || 0, - maxzoom: maxzoom || 22, + maxzoom: maxzoom || this.map.getMaxZoom() + 1, tileSize: isIserver ? this.rasterTileSize : tileSize, rasterSource: isIserver ? 'iserver' : '', prjCoordSys: @@ -2538,7 +2538,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa type: 'raster', source: sourceId, minzoom: minzoom || 0, - maxzoom: maxzoom || 22, + maxzoom: maxzoom || this.map.getMaxZoom() + 1, layout: { visibility: this._getVisibility(visibility) } @@ -2713,7 +2713,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa visibility: layerInfo.visible ? 'visible' : 'none' }, minzoom: minzoom || 0, - maxzoom: maxzoom || 22 + maxzoom: maxzoom || this.map.getMaxZoom() + 1 }); this._addLayerSucceeded(); } From 49ca98589ddad75bba9e5267e22f874fd96f7ff5 Mon Sep 17 00:00:00 2001 From: songyumeng Date: Wed, 3 Sep 2025 16:24:51 +0800 Subject: [PATCH 07/13] =?UTF-8?q?=E3=80=90fix=E3=80=91UT?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/mapboxgl/mapping/WebMapV2Spec.js | 4 ++++ test/tool/mock_mapboxgl_map.js | 12 ++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/test/mapboxgl/mapping/WebMapV2Spec.js b/test/mapboxgl/mapping/WebMapV2Spec.js index c2ff4d4e30..b6ccdb358a 100644 --- a/test/mapboxgl/mapping/WebMapV2Spec.js +++ b/test/mapboxgl/mapping/WebMapV2Spec.js @@ -203,7 +203,11 @@ describe('mapboxgl_WebMapV2', () => { getZoom: () => { return 2; }, + getMaxZoom: () => { + return 22; + }, setZoom: jasmine.createSpy('setZoom').and.callFake(() => {}), + setMaxZoom: jasmine.createSpy('setZoom').and.callFake(() => {}), setCRS: jasmine.createSpy('setCRS').and.callFake(() => {}), getCenter: () => { return { diff --git a/test/tool/mock_mapboxgl_map.js b/test/tool/mock_mapboxgl_map.js index 5e934a333f..3afab25965 100644 --- a/test/tool/mock_mapboxgl_map.js +++ b/test/tool/mock_mapboxgl_map.js @@ -33,6 +33,7 @@ const Map = function (options) { this._sources = {}; this._collectResourceTiming = !!this.options.collectResourceTiming; this.zoom = this.options.zoom || 0; + this.maxZoom = this.options.maxZoom || 22; this._container = this.options.container || 'map'; this._layers = {}; this._layersList = []; @@ -107,7 +108,7 @@ const Map = function (options) { // Settings 'setMaxBounds', 'setMinZoom', - 'setMaxZoom', + // 'setMaxZoom', // Layer properties 'setLayoutProperty', 'setPaintProperty' @@ -142,6 +143,12 @@ const Map = function (options) { layers: this._layersList }; }; + this.getMaxZoom = function () { + return this.maxZoom; + }; + this.setMaxZoom = function (zoom) { + this.maxZoom = zoom ; + }; this.getContainer = function () { const container = { @@ -291,9 +298,6 @@ const Map = function (options) { this.getMinZoom = function () { return 0; }; - this.getMaxZoom = function () { - return 22; - }; this.doubleClickZoom = { disable: function () {}, enable: function () {} From 139934b016fc910ae6e12e36c9c8cc0bc109a6c6 Mon Sep 17 00:00:00 2001 From: songyumeng Date: Thu, 4 Sep 2025 10:09:15 +0800 Subject: [PATCH 08/13] =?UTF-8?q?=E3=80=90fix=E3=80=91UT?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/maplibregl/mapping/WebMapV2Spec.js | 4 ++++ test/tool/mock_maplibregl_map.js | 8 ++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/test/maplibregl/mapping/WebMapV2Spec.js b/test/maplibregl/mapping/WebMapV2Spec.js index 26d3d26219..78e89354a0 100644 --- a/test/maplibregl/mapping/WebMapV2Spec.js +++ b/test/maplibregl/mapping/WebMapV2Spec.js @@ -203,7 +203,11 @@ describe('maplibregl_WebMapV2', () => { getZoom: () => { return 2; }, + getMaxZoom: () => { + return 22; + }, setZoom: jasmine.createSpy('setZoom').and.callFake(() => {}), + setMaxZoom: jasmine.createSpy('setMaxZoom').and.callFake(() => {}), setCRS: jasmine.createSpy('setCRS').and.callFake(() => {}), getCenter: () => { return { diff --git a/test/tool/mock_maplibregl_map.js b/test/tool/mock_maplibregl_map.js index 3434e7129e..4456f1dd10 100644 --- a/test/tool/mock_maplibregl_map.js +++ b/test/tool/mock_maplibregl_map.js @@ -35,6 +35,7 @@ const Map = function (options) { this.zoom = this.options.zoom || 0; this._container = this.options.container || 'map'; this._layers = {}; + this.maxZoom = 22; this._layersList = []; this.getContainer = function () { return this._container; @@ -107,7 +108,7 @@ const Map = function (options) { // Settings 'setMaxBounds', 'setMinZoom', - 'setMaxZoom', + // 'setMaxZoom', // Layer properties 'setLayoutProperty', 'setPaintProperty' @@ -292,7 +293,10 @@ const Map = function (options) { return 0; }; this.getMaxZoom = function () { - return 22; + return this.maxZoom || 22; + }; + this.setMaxZoom = function (maxZoom) { + this.maxZoom = maxZoom; }; this.doubleClickZoom = { disable: function () {}, From a868fbfd8cce4383aa8b2ae2e104206ccc054169 Mon Sep 17 00:00:00 2001 From: Huzhipeng Date: Fri, 5 Sep 2025 10:42:23 +0800 Subject: [PATCH 09/13] =?UTF-8?q?[update]=20SourceListModelV3=20Webmap?= =?UTF-8?q?=E8=8E=B7=E5=8F=96layers=E6=96=B0=E5=A2=9Ewfs=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=20(review=20by=20xjj)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/mapping/utils/SourceListModelV3.js | 20 ++- .../mapping/utils/SourceListModelV3Spec.js | 140 ++++++++++++++++++ 2 files changed, 159 insertions(+), 1 deletion(-) diff --git a/src/common/mapping/utils/SourceListModelV3.js b/src/common/mapping/utils/SourceListModelV3.js index e1b912f9cb..7ce035debd 100644 --- a/src/common/mapping/utils/SourceListModelV3.js +++ b/src/common/mapping/utils/SourceListModelV3.js @@ -133,7 +133,7 @@ export class SourceListModelV3 extends AppreciableLayerBase { reused: layer.metadata && layer.metadata.reused }; const matchProjectCatalog = projectCataglogs.find((item) => item.id === layerCatalog.id) || {}; - const { msDatasetId } = matchProjectCatalog; + const { msDatasetId, relationMsDatasetId } = matchProjectCatalog; let dataSource = {}; if (msDatasetId) { for (const data of datas) { @@ -153,6 +153,24 @@ export class SourceListModelV3 extends AppreciableLayerBase { } } } + if (relationMsDatasetId) { + const currentData = datas.find(data => data.datasets.find(dataset => dataset.msDatasetId === relationMsDatasetId)); + const sourceType = currentData && currentData.sourceType; + if (sourceType === 'WFS') { + const withCredential = currentData.withCredential; + let url = currentData.url; + if (withCredential && withCredential.key && withCredential.value) { + const separator = url.includes('?') ? '&' : '?'; + url = `${url}${separator}${withCredential.key}=${withCredential.value}` + } + const dataset = currentData.datasets.find(dataset => dataset.msDatasetId === relationMsDatasetId); + Object.assign(dataSource, { + type: 'WFS', + datasetName: dataset.datasetName, + url + }); + } + } const sourceOnMap = this.map.getSource(layer.source); if (!Object.keys(dataSource).length && sourceOnMap && sourceOnMap.type === 'vector') { const matchSource = this._mapInfo.sources[layer.source] || sourceOnMap; diff --git a/test/common/mapping/utils/SourceListModelV3Spec.js b/test/common/mapping/utils/SourceListModelV3Spec.js index 4e1590dae3..3b99ac7d4a 100644 --- a/test/common/mapping/utils/SourceListModelV3Spec.js +++ b/test/common/mapping/utils/SourceListModelV3Spec.js @@ -451,6 +451,146 @@ describe('SourceListV3', () => { done(); }); + it('getLayers - wfs', (done) => { + const mapInfo = { + "metadata": { + "layerCatalog": [{ + "visible": true, + "children": [{ + "visible": true, + "parts": [ + "ProvinceCapital_P@Population#1_0.8" + ], + "id": "layer_ProvinceCapital_P@Population#1_1755679838482_95", + "title": "ProvinceCapital_P@Population#1", + "type": "composite" + }], + "id": "group_PopulationDistribution_wms111_1755679838482_96", + "title": "PopulationDistribution_wms111", + "type": "group" + }, + { + "visible": true, + "children": [{ + "visible": true, + "parts": [ + "Province_L@Population_0.3" + ], + "id": "layer_Province_L@Population_1755679795075_67", + "title": "Province_L@Population", + "type": "composite" + }], + "id": "group_PopulationDistribution_wms111_1755679795075_68", + "title": "PopulationDistribution_wms111", + "type": "group" + }, + { + "visible": true, + "id": "CHINA_DARK", + "title": "中国暗色地图", + "type": "basic" + } + ] + }, + "sources": { + "CHINA_DARK": { + "tiles": [ + "https://maptiles.supermapol.com/iserver/services/map_China/rest/maps/China_Dark/tileimage.png?scale={scale}&x={x}&y={y}&width={width}&height={height}&transparent=true&redirect=false&cacheEnabled=true" + ], + "tileSize": 256, + "attribution": "", + "bounds": [ + -180, + -90, + 180, + 90 + ], + "type": "raster" + }, + "ms_wms_1755679795073_58": { + "tiles": [ + "http://172.16.14.77:8090/iserver/services/map-Population/wms111/PopulationDistribution?service=WMS&request=GetMap&layers=0.3&styles=&format=image/png&transparent=true&version=1.1.1&width=256&height=256&srs=EPSG:3857&bbox={bbox-epsg-3857}" + ], + "tileSize": 256, + "bounds": [ + 79.00794462500004, + 20.0992050343981, + 131.29906509500006, + 53.333658559101075 + ], + "type": "raster" + }, + "ms_wms_1755679838481_90": { + "tiles": [ + "http://172.16.14.77:8090/iserver/services/map-Population/wms111/PopulationDistribution?service=WMS&request=GetMap&layers=0.8&styles=&format=image/png&transparent=true&version=1.1.1&width=256&height=256&srs=EPSG:3857&bbox={bbox-epsg-3857}" + ], + "tileSize": 256, + "bounds": [ + 87.61425523000014, + 19.997037504400623, + 126.53037681500007, + 45.803316189065896 + ], + "type": "raster" + } + }, + "crs": "EPSG:3857", + "center": [ + 99.85865648224853, + 31.86438306758635 + ], + "zoom": 3.826097678440538, + "glyphs": {}, + "version": "3.3.0", + "rootUrl": "http://172.16.15.206:8190/iportal/", + "maxzoom": 12, + "name": "无标题地图", + "viewExtent": [ + 68.52728177830532, + 12.16261318538571, + 131.1900311861916, + 48.1198896120401 + ], + "layers": [{ + "maxzoom": 12, + "id": "CHINA_DARK", + "source": "CHINA_DARK", + "type": "raster", + "minzoom": 0 + }, + { + "metadata": {}, + "id": "Province_L@Population_0.3", + "source": "ms_wms_1755679795073_58", + "type": "raster" + }, + { + "metadata": {}, + "id": "ProvinceCapital_P@Population#1_0.8", + "source": "ms_wms_1755679838481_90", + "type": "raster" + } + ], + "pitch": 0, + "minzoom": 0 + }; + const projInfo = {"catalogs":[{"visible":true,"catalogType":"group","children":[{"catalogType":"layer","relationMsDatasetId":"ms_Population:ProvinceCapital_P_1755679835391_71","serviceLayerId":"0.8","id":"layer_ProvinceCapital_P@Population#1_1755679838482_95","popupInfo":{"elements":[{"fieldName":"SmID","type":"FIELD"},{"fieldName":"SmX","type":"FIELD"},{"fieldName":"SmY","type":"FIELD"},{"fieldName":"SmLibTileID","type":"FIELD"},{"fieldName":"SmUserID","type":"FIELD"},{"fieldName":"SmGeometrySize","type":"FIELD"},{"fieldName":"SmGeoPosition","type":"FIELD"},{"fieldName":"Name","type":"FIELD"}],"title":"ProvinceCapital_P@Population#1"},"title":"ProvinceCapital_P@Population#1","layerSourceType":"WMSService","zoomRange":[0,24],"layersContent":["ProvinceCapital_P@Population#1_0.8"]}],"name":"PopulationDistribution_wms111","id":"group_PopulationDistribution_wms111_1755679838482_96"},{"visible":true,"catalogType":"group","children":[{"catalogType":"layer","relationMsDatasetId":"ms_Population:Province_L_1755679787206_46","serviceLayerId":"0.3","id":"layer_Province_L@Population_1755679795075_67","popupInfo":{"elements":[{"fieldName":"SmID","type":"FIELD"},{"fieldName":"SmLength","type":"FIELD"},{"fieldName":"SmSdriW","type":"FIELD"},{"fieldName":"SmSdriN","type":"FIELD"},{"fieldName":"SmSdriE","type":"FIELD"},{"fieldName":"SmSdriS","type":"FIELD"},{"fieldName":"SmUserID","type":"FIELD"},{"fieldName":"SmTopoError","type":"FIELD"},{"fieldName":"SmGeometrySize","type":"FIELD"},{"fieldName":"SmGeoPosition","type":"FIELD"},{"fieldName":"GB","type":"FIELD"}],"title":"Province_L@Population"},"title":"Province_L@Population","layerSourceType":"WMSService","zoomRange":[0,24],"layersContent":["Province_L@Population_0.3"]}],"name":"PopulationDistribution_wms111","id":"group_PopulationDistribution_wms111_1755679795075_68"}],"datas":[{"sourceType":"WFS","datasets":[{"datasetTitle":"Country_R","msDatasetId":"ms_Population:Country_R_1755679787206_42","datasetName":"Population:Country_R"},{"datasetTitle":"HeiHeTengChong_P","msDatasetId":"ms_Population:HeiHeTengChong_P_1755679787206_43","datasetName":"Population:HeiHeTengChong_P"},{"datasetTitle":"ProvinceCapital_P","msDatasetId":"ms_Population:ProvinceCapital_P_1755679787206_44","datasetName":"Population:ProvinceCapital_P"},{"datasetTitle":"BorderTest_L","msDatasetId":"ms_Population:BorderTest_L_1755679787206_45","datasetName":"Population:BorderTest_L"},{"datasetTitle":"Province_L","msDatasetId":"ms_Population:Province_L_1755679787206_46","datasetName":"Population:Province_L"},{"datasetTitle":"Island_R","msDatasetId":"ms_Population:Island_R_1755679787206_47","datasetName":"Population:Island_R"},{"datasetTitle":"PopDensity_R","msDatasetId":"ms_Population:PopDensity_R_1755679787206_48","datasetName":"Population:PopDensity_R"},{"datasetTitle":"Coastline_L","msDatasetId":"ms_Population:Coastline_L_1755679787206_49","datasetName":"Population:Coastline_L"},{"datasetTitle":"Buffer20000","msDatasetId":"ms_Population:Buffer20000_1755679787206_50","datasetName":"Population:Buffer20000"},{"datasetTitle":"Buffer35000","msDatasetId":"ms_Population:Buffer35000_1755679787206_51","datasetName":"Population:Buffer35000"},{"datasetTitle":"County_R","msDatasetId":"ms_Population:County_R_1755679787206_52","datasetName":"Population:County_R"},{"datasetTitle":"County_P","msDatasetId":"ms_Population:County_P_1755679787206_53","datasetName":"Population:County_P"}],"title":"示例 WFS 服务","url":"http://172.16.14.77:8090/iserver/services/data-Population-2/wfs200/gb18030"},{"sourceType":"WFS","withCredential":{"key": "token", "value": "test"},"datasets":[{"datasetTitle":"Country_R","msDatasetId":"ms_Population:Country_R_1755679835391_69","datasetName":"Population:Country_R"},{"datasetTitle":"HeiHeTengChong_P","msDatasetId":"ms_Population:HeiHeTengChong_P_1755679835391_70","datasetName":"Population:HeiHeTengChong_P"},{"datasetTitle":"ProvinceCapital_P","msDatasetId":"ms_Population:ProvinceCapital_P_1755679835391_71","datasetName":"Population:ProvinceCapital_P"},{"datasetTitle":"BorderTest_L","msDatasetId":"ms_Population:BorderTest_L_1755679835391_72","datasetName":"Population:BorderTest_L"},{"datasetTitle":"Province_L","msDatasetId":"ms_Population:Province_L_1755679835391_73","datasetName":"Population:Province_L"},{"datasetTitle":"Island_R","msDatasetId":"ms_Population:Island_R_1755679835391_74","datasetName":"Population:Island_R"},{"datasetTitle":"PopDensity_R","msDatasetId":"ms_Population:PopDensity_R_1755679835391_75","datasetName":"Population:PopDensity_R"},{"datasetTitle":"Coastline_L","msDatasetId":"ms_Population:Coastline_L_1755679835391_76","datasetName":"Population:Coastline_L"},{"datasetTitle":"Buffer20000","msDatasetId":"ms_Population:Buffer20000_1755679835391_77","datasetName":"Population:Buffer20000"},{"datasetTitle":"Buffer35000","msDatasetId":"ms_Population:Buffer35000_1755679835391_78","datasetName":"Population:Buffer35000"},{"datasetTitle":"County_R","msDatasetId":"ms_Population:County_R_1755679835391_79","datasetName":"Population:County_R"},{"datasetTitle":"County_P","msDatasetId":"ms_Population:County_P_1755679835391_80","datasetName":"Population:County_P"}],"title":"示例 WFS 服务","url":"http://172.16.14.77:8090/iserver/services/data-Population-2/wfs200/gb18030"}],"baseLayer":{"internetMapName":"CHINA_DARK","type":"INTERNET_MAP"},"version":"3.1.2"}; + + const sourceListModel = new SourceListModelV3({ + map, + mapInfo, + mapResourceInfo: projInfo, + legendList: [], + l7LayerUtil: { + isL7Layer, + getL7MarkerLayers: () => ({}) + } + }); + const appreciableLayers = sourceListModel.getLayers(); + expect(appreciableLayers.find(l=>l.dataSource.type === 'WFS')).toBeTruthy(); + done(); + }); + it('getLayerCatalog without group', (done) => { const mapInfo = JSON.parse(apstudioWebMap_layerData); const sourceListModel = new SourceListModelV3({ From 8c2aad98edf861d8d940c1d33abb1f1d4d30a9b9 Mon Sep 17 00:00:00 2001 From: chenxianhui Date: Mon, 15 Sep 2025 10:13:47 +0800 Subject: [PATCH 10/13] =?UTF-8?q?[fix]=E4=BF=AE=E6=94=B9sidebariconfont?= =?UTF-8?q?=E7=9A=84unicode=EF=BC=8C=E8=A7=A3=E5=86=B3=E5=92=8C=E7=A4=BA?= =?UTF-8?q?=E4=BE=8Bicon=E5=86=B2=E7=AA=81=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/css/sidebariconfont/iconfont.css | 50 ++++++++++---------- examples/css/sidebariconfont/iconfont.ttf | Bin 9292 -> 9228 bytes examples/css/sidebariconfont/iconfont.woff | Bin 6084 -> 6060 bytes examples/css/sidebariconfont/iconfont.woff2 | Bin 5216 -> 5212 bytes 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/examples/css/sidebariconfont/iconfont.css b/examples/css/sidebariconfont/iconfont.css index 304c2a7306..55c8e54cba 100644 --- a/examples/css/sidebariconfont/iconfont.css +++ b/examples/css/sidebariconfont/iconfont.css @@ -1,8 +1,8 @@ @font-face { font-family: "iconfont"; /* Project id 4848754 */ - src: url('iconfont.woff2?t=1741260044249') format('woff2'), - url('iconfont.woff?t=1741260044249') format('woff'), - url('iconfont.ttf?t=1741260044249') format('truetype'); + src: url('iconfont.woff2?t=1757901504792') format('woff2'), + url('iconfont.woff?t=1757901504792') format('woff'), + url('iconfont.ttf?t=1757901504792') format('truetype'); } .iconfont { @@ -14,90 +14,90 @@ } .icon-control:before { - content: "\e61f"; + content: "\e161f"; } .icon-components:before { - content: "\e626"; + content: "\e1626"; } .icon-Online:before { - content: "\e625"; + content: "\e1625"; } .icon-OGC:before { - content: "\e624"; + content: "\e1624"; } .icon-analysis:before { - content: "\e620"; + content: "\e1620"; } .icon-Elasticsearch:before { - content: "\e621"; + content: "\e1621"; } .icon-multiCoordSys:before { - content: "\e618"; + content: "\e1618"; } .icon-mapping:before { - content: "\e619"; + content: "\e1619"; } .icon-MapboxGL:before { - content: "\e61a"; + content: "\e161a"; } .icon-map:before { - content: "\e61b"; + content: "\e161b"; } .icon-dynamicPlot:before { - content: "\e61c"; + content: "\e161c"; } .icon-others:before { - content: "\e61d"; + content: "\e161d"; } .icon-iServer:before { - content: "\e61e"; + content: "\e161e"; } .icon-clientSpatialAnalyst:before { - content: "\e622"; + content: "\e1622"; } .icon-overlay:before { - content: "\e60f"; + content: "\e160f"; } .icon-Leaflet:before { - content: "\e60e"; + content: "\e160e"; } .icon-iPortal:before { - content: "\e611"; + content: "\e1611"; } .icon-theme:before { - content: "\e613"; + content: "\e1613"; } .icon-popup:before { - content: "\e614"; + content: "\e1614"; } .icon-iManager:before { - content: "\e615"; + content: "\e1615"; } .icon-viz:before { - content: "\e616"; + content: "\e1616"; } .icon-query:before { - content: "\e617"; + content: "\e1617"; } diff --git a/examples/css/sidebariconfont/iconfont.ttf b/examples/css/sidebariconfont/iconfont.ttf index 08f715f76b7aef02cc077764447fa9cc6da0ac22..fa7dde7a3b2af85d3dfda94927f0a92d22840db7 100644 GIT binary patch delta 762 zcmXw#KTH!*9LK+}_lMH!JLn(FozOy0?^=;Ik|Gl!ZQ{@nB2|o=(Ta*Os6=#ds)B<7 zVyL${po61{iJItSTr>_woiH{eL}KFPVl*)ZT7U1MclWu^yYKzp-*@HZ@=D*(aeJx& zuw?+JrY=@z-@n#B1A#JedV1#ix%n;QA)u}U-OtXSt)9s*F5avk8wid&M;nwss^9L7 ztWfdv?B%(u{WFhG0M76FivvCLZ{`{&J4SxNP-$%7>-Rmy|Mpe(R&CMce`HGs$H2r7 z9D*WS1LP2`X$&eX$^&%M)oMv(Ez|ukfu{e8Y5s=NSu+zR1VAUbLjnj#B!F;C0z}Di z2_Ujv5K#MmMJrckmCnZ3boRR>X+$*7- zlKUipMovoro$N>evBA9(I(4!u0Uec@IO5UEqeaMbBHv>=`>BMLRb^9spcS=Ey`neT z#)IMDmEd~&ozRoeAL9}q=6896CPC|^`a?NPXPw3f%BbRkKdSX7Q!H+>{mf*Jmq|O` z&~PC=%DNnr#Z#={-_SC(TbUAPA0n0&X%6zzM3FZ?MJ+4J_VHpiV%v^oean{knh`VT zSu=|hCBD5ODgtR<%Iw7S*{o!XJaA2nv%SPc)q*Hmpc={?+kT$&NNz6Y(wJUuQe=+B l2Jh!xBc6yEZa(jdg8ZcXq$XSam*hnk`mxjHX+_^k{snY6fO-G` delta 851 zcmX|;F-%iY6o&u%+V?2MwzNP?3kWT3d8rI7qA>(qObO~{7=&n)2*Lo7L}TLA6=P#) zY6x*qM`Mf(ET*fAgHZYJFgI+`T*t zs4{@tcUIIn z(q&)^5M7I~8A!~)wjk8fut7*E&KF^?kc5FaXm8X9e9zVhopX0}DWABpOSOL_3|qWKgBDL&;Qj^!(Z6 zMHNd`Lw3Ms-!H$6R8FO diff --git a/examples/css/sidebariconfont/iconfont.woff b/examples/css/sidebariconfont/iconfont.woff index 642846f9350bdbfc46f1cf7a6116ed34a85b042c..faedbf47b8b102b651959e551ead113d4997417f 100644 GIT binary patch delta 5282 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 delta 5306 zcmV;r6h-T-FT^htcTYw}00961000-n01E&B001ORkrX$7L;wH)U_2;ET4QZtZ~y=S zhyVZp)c^njt|$4PiDztiW&i*JU;qFTX8-^js2|?Ck!WRMWB>pZ$N&HUF#rGnHY|>> z8E9x_VE_OW`~Uy|AOHXWBnfZ@V`y!3cmMzu8~^|SJpcdzTx9?M*=%oPVE_OXTmS$7 zFaQ7mFiYSvQkZRFcyIs!6^sA?03QGV03ZP@0aI>aZDjxe6|4XN0YCr%0%s7TJg{(Y zb94Xz7VMGya(|xjJyTIx!pJvaaW0C=30SqW?$ z*Li+#&VQY~XXo1GlDj*5bC)}N?~)Y7LljSuT1nI{MTyic#d37mv8~u~W7AHfI8hv@ zvePs++9bYOla5=oNCLPi=eWNovqqoO$!! zoB#du{{Q{|_y7M2aR}Y`7VDrdATQEUKN>}g=zk1Cv4X1U1y$xEx)X=v2|XMyRf_r` z*20{u7AmE<1QbO=k;cD=0^hc;pudhiC^vhyp!*k$DF6ltcRw!i4}RM!k)1fA z5HZ8?otTJNs0`s!JdHQTB~#`upemAeypu{}MK2eL4$`N1zX)ngMX@2 z2eE+@=9R`=JYi6guoHJ-P301CC)EX?0d`I*PH4)Ys%jCI0CS0OtyU88EROSB0=U7L zdVQ)8Z9ul%K!GBKK7y4MIMqB$1^puWNG1cLTPgaAJ-euuwr>t1I zbM(NuVFB|~z5Tl`_7<+h8H%P^igk%|mcrrCXc51ay7tnO2OHCq2M#_3JHxH|tdU7R zQycYrTpY`~VpGrL@5s!~P1tA06Zt!+hjIri4q<+mh3P!n>#7_N@{}N|5`U*n)COIQ z%UYen9;Y$W(|4j`6QmA`_7=wC_Sh~jFUxKV!-tPooFjKlS{%FYjYOH|N3p5d+Nf7_ zu@ud+2~71Q;gb72nLzHBZEU^0`& z@d)tMR9K-Z#B~VUGO;jr{WAt}7fYkX6TI$Q%vki3!Qy?rg|M~uhRpL z()i>KUEeV|UV^b4?{vF6<1#%U*78aqkO~Bva&kBv9oaV`N;o=#?|*W7Mb&L%I7xDM z+2n9gV_1$+9g^%E61|E?2y{*F>z=~XwusjuaBeZ2kkp{9OV#31W<(Sdkr=)^HJ(b1 zA0*A%=WXEGonDvM?%*W)8|`oYTl+yTM+avn3Zh($HlL0Z6noF`^hl3gEri`&F@-v- z#Jb!@@7j+7=>S~#M}P5&h4Ew}9PQ3bB^kOyw7V%9+imJh3UiDGTXs-R*(=USL7ukM z#Tj1 zfI$C{dL3|J2ps|&(bOP#;t;ODfol?RSU40o44#WuCDTb=n18NTikoynOaol-gbGfT zRlxw9IE#7G#0f!x5USXa=T2HJXGZLM?zY%*8Fz}G`a#3tIQ!y5q92A<%h>Ee$&l(J z;@nBQFgxd+X>=IkXwE)#kHda?-w=LRz}7DbKH>6$pjjChTqJ}0tbXb`WWLVnts;mw|-8* z!r22B%rjQMa8|IKy=29p9^TZ^b?Q2DAqi>7kAf(I5)d)l0RWr_qF_N)Xk7u%YTvPK zefqlOSiA0!BnLh0kcOL}^{pFUZw;F_x`B=p8fuudt$*Xoc$i$v%Qp~t!ai>N25{R- ze-Wk80NR7*(I?P7=;3x`0w)4T1UK2S5uWt6Q^C&6kh4CD1==ne&H_XaQYsu1ImkgA zClj2uzL>;qK(Jg+gSwdv`LqyL;`rU9!VP5Bp;=|FBUr z;A(v-ntw<{Ut*o?ONChE=0U!3AunUy?WHSr>a=_h}=C z7ry56?Hte;h4W2B+h6nee0bF^tFpZ?QAm#M-<`C{nrw@gV#dBB`;0$|9zA;$zQw+j zyK?1ZG=35IhaPw!ICn5C0Pk5XVIpr(n;l?1fXyS&WD@c>PoxX$@jJ5~)bkcZ4w# zw0|9q;@U@(IO`KRy;p~8xHE~ny9{H0pN+c8KG-+0ytV=yQg)(DyXf=11`oTbR(g5s z6Olq|HJa(3NCo=RUNxXZ`XiRY>A8x4jpm9)^y$63di7*qcVeuk`R}UowsVR4$^C+Lqg^@l)zUX(#Q(G0qi=#F5FDu0tO&xJ`Y5HFc|fEFfj0s%u)3nb|%5oF;v zt(=4#l3tONf&`0dxnuwzu+<<|Ij~RY#Q}H-{=f|MR0`d3Z1F3JWHRxU#ba-8b?^A} z+0*?41O2DZ{$itZVC?c3T<^J*-IvD;2lL<0?l02$gE9tKgPg@~$udk{o%n}IN zW`lV&d%Nu^tXkB}kW19$q-4-;F<=H@(3J~Ea769ejuaJBqmZR@08-m*3;&D7VoQ|4 zm>w}^dwOP#ltvb{-l=} zq_OwNUISxa*q55@anOxizqjvXANVZ}4~!3laXyMjP12Ta2S~Obyz4MJ3KD{3I!Fjo z5*fD=4MpEdI3i;EnKr50H3{)VPz8^d)6-&JY<`5OLq>u)l62LD&BR=d?_ zDiEJ1Kd#SUQi~Cd=(lw~hJQ!2P6yNJo#`|l4W!cp>rWVe45M#dBMWc7+O-J8G**LJ zqyTm36sn^mfU9?-`%Otz^5?{)OyI*Hu?w6*kx3;2b(lutSOk*S!FFLn;+2_6R!RM# z!D`Hds^V4NWMh^Uq(6vbz)Gves}Z6xcvmI$PP|Hb2BsDpwb_1~+keJ~#oP@(9r0*T-^LBn}_kZ!-dKCL5v4h4V_g?$zy`f7-kCZE|-29v0Ieq4p(CV; z3yt45Hg?}tf~{w&i>G6kJ#yc~JD;|(;okQk>Uf&pAuR!sW}Pgf0FUa;I#pj^boIWm z8>mq4cI!2JTzSH^_{k?~;fbM4^AtoFGsxK1{bkwA(R37p8YqK`s0x@egvLNBg=A@B zQQ0WniEKM?*?*LdSW~&GL^ki35-CCY3O#-O2BQlCh}JQ|w>oUpM7veI+FYR;xSkGK z>*l}a3iQ8Q$Ebl(eKnM)ah-Yx=vymw6J#l}ex9g+W?@4w3Cx`u}Y#}rGKi$6B@yZA@Vy+aXoE^q#Ocf zQLWO%33w>#!D#}pRwb^Kh?$O&fczbbbo%???}4>zq@}xKZg=jUianNGGMt4wiZk@Z zaCq%nV}4$W)neFgrE?3Rp-F+2?EJY=mwnIWm}q4#&9ZDN`hxqpqF)e1??Zf-U*P{B zU#vt+V}Gr?nS81vPBGpt-kRD)FK>S9Vj$f-O;h=-Kq+3Eo%OH|=@}ezP>tpTiq^q7 z!1!zq+Bsdl^qge1V@pD?WURDa9ow=mdxYah2y3 zE`SLjlN64?Ov(INh4ACziAoIW;dbGaAS+dlH#;l<7Z-tflOGHK?coS330MWE6|cl# zOXk6uD`Rk|Dxra*8t4mz%6vgB&DUmjm|&K$8;?x3!K?&erq{FY%bi#uV0MLo*_a7t z_7E+b6Qa~GMy})8XF15+@9gjs^nGBuOc)b*4GhwT_I1Bixug6 zWxro;{qu2q&~d!=E*a2TQ^VTQ5`XqKpOgIlgx|j=w;xhxXWZ|{UoeMFjm*i^xlXD1 zhSWJJ2vdHE>X$l~T9NT_9QMae>TNBRg)e1+iG-ia0%vJS_JiIz6C+p590EKR=O8GJ zx4kw<-RiWOS&wZb4~dQ6q1L??(#UqfK;Ths7Ze+5X4A>Mga(SIN|Dr35YeHQf=Y_tOcCq#y)%7wmyOpG_RRA5 zqf15+QlWuKeC61Cl9>s;KYzbxD%ErPAk){ocogRu&MI1YD{Y}fnzlk3Lff1S%Q8+Y z0|P5fiUk9jK=_yF(XT&#=r zvCzLFmVbl6@*rt~V0B=P zCOSDio0%G*Q?IuRGPTG2vKyeOr)O&B(6MiJUnJnv^m4R|h{RhdkQ79+m?HTY7DI<9 zfHt+oz$+I~fD5L!sCm#5W*MKUE{jP`Q9upqa?#ug#-phs$GB_`zsylRrW~}LrdT)2 zc9?Rw+j3YUmbUnAQ-Ayp7APp%LBzLMtrjA_32Hz!Pg zG;wDO2h)&K_ChLi%dcg;nNyNdh6|ZtQ471EvH@oywf+X^=!(vuTL6!4wCXF5yIhaA zUMB6z6Qo2Gj>e2nGmj2-XRR3akqB3up~6 M4U7%cvvd_W0$kAtW&i*H diff --git a/examples/css/sidebariconfont/iconfont.woff2 b/examples/css/sidebariconfont/iconfont.woff2 index 0f01897e164db3d7c9becd1d5f238ff4ee9b9309..789e7218d76c1c1b356a4231ddb384cfe42e6a67 100644 GIT binary patch literal 5212 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 WV~Fe6v3T}SAlEnc&|IyN_mv8fZR4f@ literal 5216 zcmV-m6rbyNPew8T0RR9102E*V3jhEB03=KR02C1b0RR9100000000000000000000 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 a$9{@wmqtX#0cw=)p3eRM9m=WI0ssKOe*hl< From 5cca217767fe45d207da5e1ac2735c65f820f9e1 Mon Sep 17 00:00:00 2001 From: qiwei Date: Mon, 29 Sep 2025 16:20:24 +0800 Subject: [PATCH 11/13] =?UTF-8?q?update=20=E5=A4=84=E7=90=86=E5=AF=B9webma?= =?UTF-8?q?p=20crs=20=E7=9A=843857=204326=20=E6=8A=95=E5=BD=B1=E5=85=BC?= =?UTF-8?q?=E5=AE=B9=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mapboxgl/mapping/webmap/CRSManager.js | 10 +++++++++- test/mapboxgl/mapping/WebMapV3Spec.js | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/mapboxgl/mapping/webmap/CRSManager.js b/src/mapboxgl/mapping/webmap/CRSManager.js index f5e4bde861..6029596c8d 100644 --- a/src/mapboxgl/mapping/webmap/CRSManager.js +++ b/src/mapboxgl/mapping/webmap/CRSManager.js @@ -1,5 +1,11 @@ import mapboxgl from 'mapbox-gl'; +const equivalenceMap = { + 'EPSG:4490': 'EPSG:4326', + 'EPSG:4326': 'EPSG:4490', + 'EPSG:3857': 'EPSG:900913', + 'EPSG:900913': 'EPSG:3857' +}; export class CRSManager { constructor(proj4) { this.proj4 = proj4; @@ -7,7 +13,9 @@ export class CRSManager { } isSameProjection(map, epsgCode) { - return map.getCRS().epsgCode === epsgCode; + const mapEpsgCode = map.getCRS().epsgCode; + return mapEpsgCode === epsgCode || + (equivalenceMap[mapEpsgCode] === epsgCode && equivalenceMap[epsgCode] === mapEpsgCode); } getProj4() { diff --git a/test/mapboxgl/mapping/WebMapV3Spec.js b/test/mapboxgl/mapping/WebMapV3Spec.js index 84bb818fe6..48397fc36b 100644 --- a/test/mapboxgl/mapping/WebMapV3Spec.js +++ b/test/mapboxgl/mapping/WebMapV3Spec.js @@ -318,6 +318,8 @@ describe('mapboxgl-webmap3.0', () => { existedMap.on('load', function () { mapstudioWebmap.initializeMap(nextMapInfo, existedMap); }); + const isSameCrs = extendOptions.crsManager.isSameProjection(existedMap, 'EPSG:4326'); + expect(isSameCrs).toBe(true); mapstudioWebmap.on('mapcreatesucceeded', ({ map }) => { expect(mapstudioWebmap._appendLayers).toBe(true); expect(map).toEqual(existedMap); From 20635dfa10805d87a73686b1cd849517df6e96ce Mon Sep 17 00:00:00 2001 From: chenxianhui Date: Sat, 11 Oct 2025 11:16:19 +0800 Subject: [PATCH 12/13] =?UTF-8?q?ISVJ-10976=20=E6=94=AF=E6=8C=81dv?= =?UTF-8?q?=E9=9D=9E=E4=B8=93=E9=A2=98=E5=9B=BE=E5=B1=82=E7=9A=84=E5=9B=BE?= =?UTF-8?q?=E4=BE=8B=20review=20by=20xiongjj?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/mapping/WebMapV2.js | 12 +++++++++++- src/common/mapping/WebMapV2Base.js | 10 ++++++++++ test/mapboxgl/mapping/WebMapV2Spec.js | 23 +++++++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/common/mapping/WebMapV2.js b/src/common/mapping/WebMapV2.js index 782df7a812..8abe6c7f41 100644 --- a/src/common/mapping/WebMapV2.js +++ b/src/common/mapping/WebMapV2.js @@ -506,6 +506,8 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa features = this.handleLayerFeatures(features, layerInfo); if (layerType === 'VECTOR') { + const styleGroups = this.getVectorStyleGroup(layerInfo); + this._initLegendConfigInfo(layerInfo, styleGroups); if (featureType === 'POINT') { if (style.type === 'SYMBOL_POINT') { this._createSymbolLayer(layerInfo, features); @@ -2564,11 +2566,18 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa this._addOverlayToMap({ type: 'LINE', source, layerID, parentLayerId, layerStyle: lineStyle, minzoom, maxzoom }); } + _getThemeField(layerInfo) { + if (layerInfo.layerType === 'VECTOR') { + return '' + } + return layerInfo.layerType === 'HEAT' ? layerInfo.themeSetting.weight : layerInfo.themeSetting.themeField + } + _initLegendConfigInfo(layerInfo, style) { const legendItem = { layerId: layerInfo.layerID, layerTitle: layerInfo.layerID, - themeField: layerInfo.layerType === 'HEAT' ? layerInfo.themeSetting.weight : layerInfo.themeSetting.themeField, + themeField: this._getThemeField(layerInfo), styleGroup: style }; @@ -2585,6 +2594,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa switch (layerInfo.layerType) { case 'UNIQUE': + case 'VECTOR': legendItem.styleGroup = legendItem.styleGroup.map((styleGroup) => { return { fieldValue: styleGroup.value, diff --git a/src/common/mapping/WebMapV2Base.js b/src/common/mapping/WebMapV2Base.js index bc227cbd41..7ffe806283 100644 --- a/src/common/mapping/WebMapV2Base.js +++ b/src/common/mapping/WebMapV2Base.js @@ -722,6 +722,16 @@ export function createWebMapV2BaseExtending(SuperClass = Events, fireField = 'tr return styleGroup; } + + getVectorStyleGroup(layerInfo) { + const color = layerInfo.style.fillColor || layerInfo.style.strokeColor; + const styleGroup = [{ + color: color, + style: layerInfo.style, + value: layerInfo.name + }] + return styleGroup; + } transformFeatures(features) { features && diff --git a/test/mapboxgl/mapping/WebMapV2Spec.js b/test/mapboxgl/mapping/WebMapV2Spec.js index b6ccdb358a..328cc27715 100644 --- a/test/mapboxgl/mapping/WebMapV2Spec.js +++ b/test/mapboxgl/mapping/WebMapV2Spec.js @@ -490,6 +490,29 @@ describe('mapboxgl_WebMapV2', () => { datavizWebmap.on('mapcreatesucceeded', callback); }); + it('vectorlayer should have legends', (done) => { + spyOn(FetchRequest, 'get').and.callFake((url) => { + if (url.indexOf('map.json') > -1) { + return Promise.resolve(new Response(JSON.stringify(vectorLayer_line))); + } else if (url.indexOf('1788054202/content.json?') > -1) { + return Promise.resolve(new Response(JSON.stringify(chart_content))); + } else if (url.indexOf('13136933/content.json?') > -1) { + return Promise.resolve(new Response(JSON.stringify(layerData_geojson['POINT_GEOJSON']))); + } else if (url.indexOf('portal.json') > -1) { + return Promise.resolve(new Response(JSON.stringify(iportal_serviceProxy))); + } else if (url.indexOf('web/datas/1920557079/content.json') > -1) { + return Promise.resolve(new Response(layerData_CSV)); + } + return Promise.resolve(new Response(JSON.stringify({}))); + }); + datavizWebmap = new WebMap(id, { ...commonOption, map: commonMap }, { ...commonMapOptions }); + const callback = function (data) { + expect(datavizWebmap.getLegends().length).toBe(1); + done(); + }; + datavizWebmap.on('mapcreatesucceeded', callback); + }); + it('add heatLayer', (done) => { spyOn(FetchRequest, 'get').and.callFake((url) => { if (url.indexOf('web/datas/1920557079/content.json') > -1) { From a0195f0bc2e2e469edd2ad9835f34da17d58cb6c Mon Sep 17 00:00:00 2001 From: luoxiao Date: Wed, 15 Oct 2025 11:02:56 +0800 Subject: [PATCH 13/13] [fix]ISVJ-10807 preferServer featureService webmap --- src/common/commontypes/Util.js | 12 + src/common/iServer/CommonServiceBase.js | 1 + src/common/iServer/FeatureService.js | 27 +- .../iServer/GetFeaturesByBoundsService.js | 1 + .../iServer/GetFeaturesByBufferService.js | 1 + .../iServer/GetFeaturesByGeometryService.js | 1 + src/common/iServer/GetFeaturesByIDsService.js | 1 + src/common/iServer/GetFeaturesBySQLService.js | 1 + src/common/iServer/GetFeaturesServiceBase.js | 257 +++++++++--------- src/common/mapping/WebMapBase.js | 1 + src/common/mapping/WebMapService.js | 2 + src/common/util/FetchRequest.js | 9 +- src/mapboxgl/mapping/WebMap.js | 1 + src/mapboxgl/services/FeatureService.js | 1 + test/mapboxgl/mapping/WebMapSpec.js | 34 +++ .../services/GetFeaturesByBoundsSpec.js | 54 ++-- .../services/GetFeaturesByBufferSpec.js | 45 +++ .../services/GetFeaturesByGeometrySpec.js | 46 ++++ .../mapboxgl/services/GetFeaturesByIDsSpec.js | 68 +++-- .../mapboxgl/services/GetFeaturesBySQLSpec.js | 82 +++++- 20 files changed, 464 insertions(+), 181 deletions(-) diff --git a/src/common/commontypes/Util.js b/src/common/commontypes/Util.js index 59803646a6..f5a37e021b 100644 --- a/src/common/commontypes/Util.js +++ b/src/common/commontypes/Util.js @@ -435,6 +435,18 @@ const Util = { return paramsArray.join('&'); }, + handleUrlSuffix(url, suffix = '.json') { + if (url.indexOf('?') < 0) { + url += suffix; + } else { + var urlArrays = url.split('?'); + if (urlArrays.length === 2) { + url = urlArrays[0] + suffix + '?' + urlArrays[1]; + } + } + return url + }, + /** * @memberOf CommonUtil * @description 给 URL 追加查询参数。 diff --git a/src/common/iServer/CommonServiceBase.js b/src/common/iServer/CommonServiceBase.js index d4407251da..6f778ac364 100644 --- a/src/common/iServer/CommonServiceBase.js +++ b/src/common/iServer/CommonServiceBase.js @@ -150,6 +150,7 @@ export class CommonServiceBase { options.headers = options.headers || me.headers; options.isInTheSameDomain = me.isInTheSameDomain; options.withoutFormatSuffix = options.scope.withoutFormatSuffix || false; + options.preferServer = options.preferServer || me.preferServer; //为url添加安全认证信息片段 options.url = SecurityManager.appendCredential(options.url); diff --git a/src/common/iServer/FeatureService.js b/src/common/iServer/FeatureService.js index 6f180b3519..9541acb7a6 100644 --- a/src/common/iServer/FeatureService.js +++ b/src/common/iServer/FeatureService.js @@ -17,7 +17,7 @@ const FEATURE_SERVICE_MAP = { bounds: GetFeaturesByBoundsService, buffer: GetFeaturesByBufferService, geometry: GetFeaturesByGeometryService -} +}; /** * @class FeatureService @@ -34,11 +34,11 @@ const FEATURE_SERVICE_MAP = { * @param {boolean} [options.withCredentials=false] - 请求是否携带 cookie。 * @param {boolean} [options.crossOrigin] - 是否允许跨域请求。 * @param {Object} [options.headers] - 请求头。 + * @param {boolean} [options.preferServer=false] - 当resultFormat=DataFormat.GEOJSON时,使用服务器直接返回geojson。 * @extends {ServiceBase} * @usage */ export class FeatureService { - constructor(url, options) { this.url = url; this.options = options || {}; @@ -59,7 +59,8 @@ export class FeatureService { withCredentials: me.options.withCredentials, crossOrigin: me.options.crossOrigin, headers: me.options.headers, - format: resultFormat + format: resultFormat, + preferServer: me.options.preferServer }); return getFeaturesByIDsService.processAsync(params, callback); } @@ -79,7 +80,8 @@ export class FeatureService { withCredentials: me.options.withCredentials, crossOrigin: me.options.crossOrigin, headers: me.options.headers, - format: me._processFormat(resultFormat) + format: me._processFormat(resultFormat), + preferServer: me.options.preferServer }); return getFeaturesByBoundsService.processAsync(params, callback); } @@ -99,7 +101,8 @@ export class FeatureService { withCredentials: me.options.withCredentials, crossOrigin: me.options.crossOrigin, headers: me.options.headers, - format: me._processFormat(resultFormat) + format: me._processFormat(resultFormat), + preferServer: me.options.preferServer }); return getFeatureService.processAsync(params, callback); } @@ -119,7 +122,8 @@ export class FeatureService { withCredentials: me.options.withCredentials, crossOrigin: me.options.crossOrigin, headers: me.options.headers, - format: me._processFormat(resultFormat) + format: me._processFormat(resultFormat), + preferServer: me.options.preferServer }); return getFeatureBySQLService.processAsync(params, callback); } @@ -139,7 +143,8 @@ export class FeatureService { withCredentials: me.options.withCredentials, crossOrigin: me.options.crossOrigin, headers: me.options.headers, - format: me._processFormat(resultFormat) + format: me._processFormat(resultFormat), + preferServer: me.options.preferServer }); return getFeaturesByGeometryService.processAsync(params, callback); } @@ -159,7 +164,7 @@ export class FeatureService { url = me.url, dataSourceName = params.dataSourceName, dataSetName = params.dataSetName; - url = CommonUtil.urlPathAppend(url, "datasources/" + dataSourceName + "/datasets/" + dataSetName); + url = CommonUtil.urlPathAppend(url, 'datasources/' + dataSourceName + '/datasets/' + dataSetName); var editFeatureService = new EditFeaturesService(url, { proxy: me.options.proxy, @@ -182,7 +187,7 @@ export class FeatureService { url = me.url, dataSourceName = params.dataSourceName, dataSetName = params.dataSetName; - url = CommonUtil.urlPathAppend(url, "datasources/" + dataSourceName + "/datasets/" + dataSetName); + url = CommonUtil.urlPathAppend(url, 'datasources/' + dataSourceName + '/datasets/' + dataSetName); var editFeatureService = new EditFeaturesService(url, { proxy: me.options.proxy, withCredentials: me.options.withCredentials, @@ -207,7 +212,7 @@ export class FeatureService { url = me.url, dataSourceName = params.dataSourceName, dataSetName = params.dataSetName; - url = CommonUtil.urlPathAppend(url, "datasources/" + dataSourceName + "/datasets/" + dataSetName); + url = CommonUtil.urlPathAppend(url, 'datasources/' + dataSourceName + '/datasets/' + dataSetName); var featureAttachmentsService = new FeatureAttachmentsService(url, { proxy: me.options.proxy, withCredentials: me.options.withCredentials, @@ -233,7 +238,7 @@ export class FeatureService { url = me.url, dataSourceName = params.dataSourceName, dataSetName = params.dataSetName; - url = CommonUtil.urlPathAppend(url, "datasources/" + dataSourceName + "/datasets/" + dataSetName); + url = CommonUtil.urlPathAppend(url, 'datasources/' + dataSourceName + '/datasets/' + dataSetName); var featureAttachmentsService = new FeatureAttachmentsService(url, { proxy: me.options.proxy, withCredentials: me.options.withCredentials, diff --git a/src/common/iServer/GetFeaturesByBoundsService.js b/src/common/iServer/GetFeaturesByBoundsService.js index 39953436ae..e2e7ec15bf 100644 --- a/src/common/iServer/GetFeaturesByBoundsService.js +++ b/src/common/iServer/GetFeaturesByBoundsService.js @@ -17,6 +17,7 @@ import {GetFeaturesByBoundsParameters} from './GetFeaturesByBoundsParameters'; * @param {DataFormat} [options.format=DataFormat.GEOJSON] - 查询结果返回格式,目前支持 iServerJSON、GeoJSON、FGB 三种格式。参数格式为 "ISERVER","GEOJSON","FGB"。 * @param {boolean} [options.crossOrigin] - 是否允许跨域请求。 * @param {Object} [options.headers] - 请求头。 + * @param {boolean} [options.preferServer=false] - 当options.format=DataFormat.GEOJSON时,使用服务器直接返回geojson。 * @example * var myGetFeaturesByBoundsService = new SuperMa.GetFeaturesByBoundsService(url); * @usage diff --git a/src/common/iServer/GetFeaturesByBufferService.js b/src/common/iServer/GetFeaturesByBufferService.js index e96000e35b..9906ec99fa 100644 --- a/src/common/iServer/GetFeaturesByBufferService.js +++ b/src/common/iServer/GetFeaturesByBufferService.js @@ -16,6 +16,7 @@ import {GetFeaturesByBufferParameters} from './GetFeaturesByBufferParameters'; * @param {DataFormat} [options.format=DataFormat.GEOJSON] - 查询结果返回格式,目前支持 iServerJSON、GeoJSON、FGB 三种格式。参数格式为 "ISERVER","GEOJSON","FGB"。 * @param {boolean} [options.crossOrigin] - 是否允许跨域请求。 * @param {Object} [options.headers] - 请求头。 + * @param {boolean} [options.preferServer=false] - 当options.format=DataFormat.GEOJSON时,使用服务器直接返回geojson。 * @extends {GetFeaturesServiceBase} * @example * var myGetFeaturesByBufferService = new GetFeaturesByBufferService(url); diff --git a/src/common/iServer/GetFeaturesByGeometryService.js b/src/common/iServer/GetFeaturesByGeometryService.js index 7c1e46c6ea..cc42770789 100644 --- a/src/common/iServer/GetFeaturesByGeometryService.js +++ b/src/common/iServer/GetFeaturesByGeometryService.js @@ -16,6 +16,7 @@ import {GetFeaturesByGeometryParameters} from './GetFeaturesByGeometryParameters * @param {DataFormat} [options.format=DataFormat.GEOJSON] - 查询结果返回格式,目前支持 iServerJSON、GeoJSON、FGB 三种格式。参数格式为 "ISERVER","GEOJSON","FGB"。 * @param {boolean} [options.crossOrigin] - 是否允许跨域请求。 * @param {Object} [options.headers] - 请求头。 + * @param {boolean} [options.preferServer=false] - 当options.format=DataFormat.GEOJSON时,使用服务器直接返回geojson。 * @extends {GetFeaturesServiceBase} * @example * var myService = new GetFeaturesByGeometryService(url); diff --git a/src/common/iServer/GetFeaturesByIDsService.js b/src/common/iServer/GetFeaturesByIDsService.js index 9ac2cd86a1..bb2ffc1b13 100644 --- a/src/common/iServer/GetFeaturesByIDsService.js +++ b/src/common/iServer/GetFeaturesByIDsService.js @@ -16,6 +16,7 @@ import {GetFeaturesByIDsParameters} from './GetFeaturesByIDsParameters'; * @param {DataFormat} [options.format=DataFormat.GEOJSON] - 查询结果返回格式,目前支持 iServerJSON、GeoJSON、FGB 三种格式。参数格式为 "ISERVER","GEOJSON","FGB"。 * @param {boolean} [options.crossOrigin] - 是否允许跨域请求。 * @param {Object} [options.headers] - 请求头。 + * @param {boolean} [options.preferServer=false] - 当options.format=DataFormat.GEOJSON时,使用服务器直接返回geojson。 * @extends {GetFeaturesServiceBase} * @example * var myGetFeaturesByIDsService = new GetFeaturesByIDsService(url); diff --git a/src/common/iServer/GetFeaturesBySQLService.js b/src/common/iServer/GetFeaturesBySQLService.js index d4216034d2..d04327e138 100644 --- a/src/common/iServer/GetFeaturesBySQLService.js +++ b/src/common/iServer/GetFeaturesBySQLService.js @@ -17,6 +17,7 @@ import {GetFeaturesBySQLParameters} from './GetFeaturesBySQLParameters'; * @param {DataFormat} [options.format=DataFormat.GEOJSON] - 查询结果返回格式,目前支持 iServerJSON、GeoJSON、FGB 三种格式。参数格式为 "ISERVER","GEOJSON","FGB"。 * @param {boolean} [options.crossOrigin] - 是否允许跨域请求。 * @param {Object} [options.headers] - 请求头。 + * @param {boolean} [options.preferServer=false] - 当options.format=DataFormat.GEOJSON时,使用服务器直接返回geojson。 * @extends {GetFeaturesServiceBase} * @example * var myGetFeaturesBySQLService = new GetFeaturesBySQLService(url); diff --git a/src/common/iServer/GetFeaturesServiceBase.js b/src/common/iServer/GetFeaturesServiceBase.js index d3c3db5021..dc09bb0f1d 100644 --- a/src/common/iServer/GetFeaturesServiceBase.js +++ b/src/common/iServer/GetFeaturesServiceBase.js @@ -1,10 +1,10 @@ /* Copyright© 2000 - 2025 SuperMap Software Co.Ltd. All rights reserved. * This program are made available under the terms of the Apache License, Version 2.0 * which accompanies this distribution and is available at http://www.apache.org/licenses/LICENSE-2.0.html.*/ -import {Util} from '../commontypes/Util'; -import {DataFormat} from '../REST'; -import {CommonServiceBase} from './CommonServiceBase'; -import {GeoJSON} from '../format/GeoJSON'; +import { Util } from '../commontypes/Util'; +import { DataFormat } from '../REST'; +import { CommonServiceBase } from './CommonServiceBase'; +import { GeoJSON } from '../format/GeoJSON'; /** * @class GetFeaturesServiceBase @@ -19,65 +19,65 @@ import {GeoJSON} from '../format/GeoJSON'; * @param {DataFormat} [options.format=DataFormat.GEOJSON] - 查询结果返回格式,目前支持 iServerJSON、GeoJSON、FGB 三种格式。参数格式为 "ISERVER","GEOJSON","FGB"。 * @param {boolean} [options.crossOrigin] - 是否允许跨域请求。 * @param {Object} [options.headers] - 请求头。 + * @param {boolean} [options.preferServer=false] - 当options.format=DataFormat.GEOJSON时,使用服务器直接返回geojson。 * @example * var myService = new GetFeaturesServiceBase(url); * @usage */ export class GetFeaturesServiceBase extends CommonServiceBase { - constructor(url, options) { - super(url, options); - options = options || {}; - - /** - * @member {boolean} [GetFeaturesServiceBase.prototype.returnContent=true] - * @description 是否立即返回新创建资源的表述还是返回新资源的 URI。 - * 如果为 true,则直接返回新创建资源,即查询结果的表述。 - * 如果为 false,则返回的是查询结果资源的 URI。 - */ - this.returnContent = true; - - /** - * @member {boolean} [GetFeaturesServiceBase.prototype.returnFeaturesOnly=false] - * @description 是否仅返回要素信息。 - */ - this.returnFeaturesOnly = false; - - /** - * @member {number} [GetFeaturesServiceBase.prototype.fromIndex=0] - * @description 查询结果的最小索引号。如果该值大于查询结果的最大索引号,则查询结果为空。 - */ - this.fromIndex = 0; - - /** - * @member {number} [GetFeaturesServiceBase.prototype.toIndex=19] - * @description 查询结果的最大索引号。 - * 如果该值大于查询结果的最大索引号,则以查询结果的最大索引号为终止索引号。 - */ - this.toIndex = 19; - - /** - * @member {number} [GetFeaturesServiceBase.prototype.hasGeometry=true] - * @description 返回结果是否包含 Geometry。 - */ - this.hasGeometry = true; - - /** - * @member {number} [GetFeaturesServiceBase.prototype.maxFeatures=1000] - * @description 进行 SQL 查询时,用于设置服务端返回查询结果条目数量。 - */ - this.maxFeatures = null; - - /** - * @member {string} [GetFeaturesServiceBase.prototype.format=DataFormat.GEOJSON] - * @description 查询结果返回格式,目前支持 iServerJSON、GeoJSON、FGB 三种格式。 - * 参数格式为 "ISERVER","GEOJSON","FGB"。 - */ - this.format = DataFormat.GEOJSON; - - Util.extend(this, options); - this.url = Util.urlPathAppend(this.url, 'featureResults'); - this.CLASS_NAME = "SuperMap.GetFeaturesServiceBase"; + super(url, options); + options = options || {}; + + /** + * @member {boolean} [GetFeaturesServiceBase.prototype.returnContent=true] + * @description 是否立即返回新创建资源的表述还是返回新资源的 URI。 + * 如果为 true,则直接返回新创建资源,即查询结果的表述。 + * 如果为 false,则返回的是查询结果资源的 URI。 + */ + this.returnContent = true; + + /** + * @member {boolean} [GetFeaturesServiceBase.prototype.returnFeaturesOnly=false] + * @description 是否仅返回要素信息。 + */ + this.returnFeaturesOnly = false; + + /** + * @member {number} [GetFeaturesServiceBase.prototype.fromIndex=0] + * @description 查询结果的最小索引号。如果该值大于查询结果的最大索引号,则查询结果为空。 + */ + this.fromIndex = 0; + + /** + * @member {number} [GetFeaturesServiceBase.prototype.toIndex=19] + * @description 查询结果的最大索引号。 + * 如果该值大于查询结果的最大索引号,则以查询结果的最大索引号为终止索引号。 + */ + this.toIndex = 19; + + /** + * @member {number} [GetFeaturesServiceBase.prototype.hasGeometry=true] + * @description 返回结果是否包含 Geometry。 + */ + this.hasGeometry = true; + + /** + * @member {number} [GetFeaturesServiceBase.prototype.maxFeatures=1000] + * @description 进行 SQL 查询时,用于设置服务端返回查询结果条目数量。 + */ + this.maxFeatures = null; + + /** + * @member {string} [GetFeaturesServiceBase.prototype.format=DataFormat.GEOJSON] + * @description 查询结果返回格式,目前支持 iServerJSON、GeoJSON、FGB 三种格式。 + * 参数格式为 "ISERVER","GEOJSON","FGB"。 + */ + this.format = DataFormat.GEOJSON; + + Util.extend(this, options); + this.url = Util.urlPathAppend(this.url, 'featureResults'); + this.CLASS_NAME = 'SuperMap.GetFeaturesServiceBase'; } /** @@ -85,14 +85,14 @@ export class GetFeaturesServiceBase extends CommonServiceBase { * @description 释放资源,将引用资源的属性置空。 */ destroy() { - super.destroy(); - var me = this; - me.returnContent = null; - me.fromIndex = null; - me.toIndex = null; - me.maxFeatures = null; - me.format = null; - me.hasGeometry = null; + super.destroy(); + var me = this; + me.returnContent = null; + me.fromIndex = null; + me.toIndex = null; + me.maxFeatures = null; + me.format = null; + me.hasGeometry = null; } /** @@ -103,52 +103,57 @@ export class GetFeaturesServiceBase extends CommonServiceBase { * @returns {Promise} Promise 对象。 */ processAsync(params, callback) { - if (!params) { - return; - } - var me = this, - jsonParameters = null, - firstPara = true; - - me.returnContent = params.returnContent; - me.returnFeaturesOnly = params.returnFeaturesOnly; - me.fromIndex = params.fromIndex; - me.toIndex = params.toIndex; - me.maxFeatures = params.maxFeatures; - me.hasGeometry = params.hasGeometry; - if (me.returnContent) { - firstPara = false; + if (!params) { + return; + } + var me = this, + jsonParameters = null, + firstPara = true; + me.returnContent = params.returnContent; + me.returnFeaturesOnly = params.returnFeaturesOnly; + me.fromIndex = params.fromIndex; + me.toIndex = params.toIndex; + me.maxFeatures = params.maxFeatures; + me.hasGeometry = params.hasGeometry; + if (me.returnContent) { + firstPara = false; + } + var isValidNumber = me.fromIndex != null && me.toIndex != null && !isNaN(me.fromIndex) && !isNaN(me.toIndex); + if (isValidNumber && me.fromIndex >= 0 && me.toIndex >= 0 && !firstPara) { + me.url = Util.urlAppend(me.url, `fromIndex=${me.fromIndex}&toIndex=${me.toIndex}`); + } + + if (me.returnContent) { + if (!params.returnCountOnly && !params.returnDatasetInfoOnly && !params.returnFeaturesOnly) { + console.warn( + 'recommend set returnFeaturesOnly config to true to imporve performance. if need get Total amount and Dataset information. FeatureService provide getFeaturesCount and getFeaturesDatasetInfo method' + ); } - var isValidNumber = me.fromIndex != null && me.toIndex != null && !isNaN(me.fromIndex) && !isNaN(me.toIndex); - if (isValidNumber && me.fromIndex >= 0 && me.toIndex >= 0 && !firstPara) { - me.url = Util.urlAppend(me.url, `fromIndex=${me.fromIndex}&toIndex=${me.toIndex}`); + if (params.returnCountOnly) { + me.url = Util.urlAppend(me.url, 'returnCountOnly=' + params.returnCountOnly); } - if (me.returnContent) { - if (!params.returnCountOnly && !params.returnDatasetInfoOnly && !params.returnFeaturesOnly) { - console.warn('recommend set returnFeaturesOnly config to true to imporve performance. if need get Total amount and Dataset information. FeatureService provide getFeaturesCount and getFeaturesDatasetInfo method'); - } - if (params.returnCountOnly) { - me.url = Util.urlAppend(me.url, "returnCountOnly=" + params.returnCountOnly) - } - - if (params.returnDatasetInfoOnly) { - me.url = Util.urlAppend(me.url, "returnDatasetInfoOnly=" + params.returnDatasetInfoOnly) - } - - if (params.returnFeaturesOnly) { - me.url = Util.urlAppend(me.url, "returnFeaturesOnly=" + params.returnFeaturesOnly) - } - } - - jsonParameters = me.getJsonParameters(params); - return me.request({ - method: "POST", - data: jsonParameters, - scope: me, - success: callback, - failure: callback - }); + if (params.returnDatasetInfoOnly) { + me.url = Util.urlAppend(me.url, 'returnDatasetInfoOnly=' + params.returnDatasetInfoOnly); + } + if (params.returnFeaturesOnly) { + me.url = Util.urlAppend(me.url, 'returnFeaturesOnly=' + params.returnFeaturesOnly); + } + } + + if (me.preferServer && me.format === DataFormat.GEOJSON) { + me.url = Util.handleUrlSuffix(me.url, '.geojson'); + me.withoutFormatSuffix = true; + } + + jsonParameters = me.getJsonParameters(params); + return me.request({ + method: 'POST', + data: jsonParameters, + scope: me, + success: callback, + failure: callback + }); } /** @@ -159,25 +164,29 @@ export class GetFeaturesServiceBase extends CommonServiceBase { * @return {Object} 转换结果。 */ transformResult(result, options) { - var me = this; - result = Util.transformResult(result); - var geoJSONFormat = new GeoJSON(); - if (me.format === DataFormat.GEOJSON && result.features) { - result.features = geoJSONFormat.toGeoJSON(result.features); - } - if (me.returnFeaturesOnly && Array.isArray(result)) { - let succeed = result.succeed; - let features = geoJSONFormat.toGeoJSON(result); - result = { - succeed, - features - }; - } - return { result, options }; + var me = this; + result = Util.transformResult(result); + var geoJSONFormat = new GeoJSON(); + if (me.preferServer && me.format === DataFormat.GEOJSON) { + const succeed = result.succeed; + delete result.succeed; + return { result: { succeed, features: result }, options }; + } + if (me.format === DataFormat.GEOJSON && result.features) { + result.features = geoJSONFormat.toGeoJSON(result.features); + } + if (me.returnFeaturesOnly && Array.isArray(result)) { + let succeed = result.succeed; + let features = geoJSONFormat.toGeoJSON(result); + result = { + succeed, + features + }; + } + return { result, options }; } dataFormat() { return [DataFormat.GEOJSON, DataFormat.ISERVER, DataFormat.FGB]; } - } diff --git a/src/common/mapping/WebMapBase.js b/src/common/mapping/WebMapBase.js index 607f134ee4..ff2a18d3ab 100644 --- a/src/common/mapping/WebMapBase.js +++ b/src/common/mapping/WebMapBase.js @@ -28,6 +28,7 @@ const WORLD_WIDTH = 360; * @param {boolean} [options.isSuperMapOnline] - 是否是 SuperMap Online 地图。 * @param {string} [options.iportalServiceProxyUrlPrefix] - iportal的代理服务地址前缀。 * @param {string|boolean} [options.proxy] - HTTP 请求代理地址 。布尔值表示使用 iPortal 默认代理地址。 + * @param {boolean} [options.preferServer=false] - iServer rest/data服务, 使用服务器直接返回geojson。 * @param {Object} mapOptions - 地图参数。 * @param {Array} [mapOptions.center] - 中心点。 * @param {number} [mapOptions.zoom] - 缩放级别。 diff --git a/src/common/mapping/WebMapService.js b/src/common/mapping/WebMapService.js index ed10a9524c..a92f3fca66 100644 --- a/src/common/mapping/WebMapService.js +++ b/src/common/mapping/WebMapService.js @@ -42,6 +42,7 @@ export class WebMapService { this.excludePortalProxyUrl = options.excludePortalProxyUrl; this.iportalServiceProxyUrl = options.iportalServiceProxyUrlPrefix; this.proxy = options.proxy; + this.preferServer = options.preferServer || false; this.proxyOptions = { data: 'apps/viewer/getUrlResource.json?url=', image: 'apps/viewer/getUrlResource.png?url=' @@ -1222,6 +1223,7 @@ export class WebMapService { let options = { proxy, withCredentials: this.handleWithCredentials(proxy, url, false), + preferServer: this.preferServer, eventListeners: { processCompleted: getFeaturesEventArgs => { let result = getFeaturesEventArgs.result; diff --git a/src/common/util/FetchRequest.js b/src/common/util/FetchRequest.js index ef4c3db091..703d11eeb4 100644 --- a/src/common/util/FetchRequest.js +++ b/src/common/util/FetchRequest.js @@ -514,14 +514,7 @@ export var FetchRequest = { } if (url.indexOf('.json') === -1 && !options.withoutFormatSuffix) { - if (url.indexOf('?') < 0) { - url += '.json'; - } else { - var urlArrays = url.split('?'); - if (urlArrays.length === 2) { - url = urlArrays[0] + '.json?' + urlArrays[1]; - } - } + url = Util.handleUrlSuffix(url); } if (options && options.proxy) { if (typeof options.proxy === 'function') { diff --git a/src/mapboxgl/mapping/WebMap.js b/src/mapboxgl/mapping/WebMap.js index 9f6bfc9d59..2dc2a2a4a0 100644 --- a/src/mapboxgl/mapping/WebMap.js +++ b/src/mapboxgl/mapping/WebMap.js @@ -49,6 +49,7 @@ import { GraticuleLayer } from '../overlay/GraticuleLayer'; * @param {boolean} [options.isSuperMapOnline] - 是否是 SuperMap Online 地图。 * @param {string} [options.iportalServiceProxyUrlPrefix] - iportal的代理服务地址前缀。 * @param {string|boolean} [options.proxy] - HTTP 请求代理地址 。布尔值表示使用 iPortal 默认代理地址。 + * @param {boolean} [options.preferServer=false] - 当图层数据来源为SuperMap iServer RestData服务, 使用服务器直接返回geojson。 * @param {Object} mapOptions - 地图参数。 * @param {Array} [mapOptions.center] - 中心点。 * @param {number} [mapOptions.zoom] - 缩放级别。 diff --git a/src/mapboxgl/services/FeatureService.js b/src/mapboxgl/services/FeatureService.js index 6b957d5ac7..d2f9461ffe 100644 --- a/src/mapboxgl/services/FeatureService.js +++ b/src/mapboxgl/services/FeatureService.js @@ -27,6 +27,7 @@ import { FeatureService as CommonFeatureService } from '@supermapgis/iclient-com * @param {boolean} [options.withCredentials=false] - 请求是否携带 cookie。 * @param {boolean} [options.crossOrigin] - 是否允许跨域请求。 * @param {Object} [options.headers] - 请求头。 + * @param {boolean} [options.preferServer] - 当resultFormat=DataFormat.GEOJSON时,使用服务器直接返回geojson。 * @usage */ export class FeatureService extends ServiceBase { diff --git a/test/mapboxgl/mapping/WebMapSpec.js b/test/mapboxgl/mapping/WebMapSpec.js index 32a74957ca..1d38969303 100644 --- a/test/mapboxgl/mapping/WebMapSpec.js +++ b/test/mapboxgl/mapping/WebMapSpec.js @@ -732,6 +732,40 @@ describe('mapboxgl_WebMap', () => { }); }); + it('createThemeLayer_SUPERMAPREST_DATA preferServer', (done) => { + let options = { + server: server, + preferServer: true + }; + spyOn(FetchRequest, 'get').and.callFake((url) => { + if (url.indexOf('web/config/portal.json') > -1) { + return Promise.resolve(new Response(JSON.stringify(iportal_serviceProxy))); + } + if (url.indexOf('map.json') > -1) { + var mapJson = datavizWebMap_RestData; + return Promise.resolve(new Response(mapJson)); + } + return Promise.resolve(); + }); + spyOn(FetchRequest, 'post').and.callFake((url) => { + expect(url).toBe('http://fakeiserver/iserver/services/data-jingjin/rest/data/featureResults.geojson?returnFeaturesOnly=true&returnContent=true'); + return Promise.resolve(new Response(JSON.stringify(JSON.parse(markerData2.content)))); + }); + var datavizWebmap = new WebMap(id, options); + + datavizWebmap.on('mapcreatesucceeded', function () { + expect(datavizWebmap.credentialKey).toBeUndefined(); + expect(datavizWebmap.credentialValue).toBeUndefined(); + + var map = datavizWebmap.map; + expect(map.getZoom()).toBeCloseTo(9, 0.001); + expect(map.getCenter()).toEqual(new mapboxgl.LngLat(116.8995771532053, 39.700527641334965)); + expect(datavizWebmap.mapParams.title).toBe('RestData'); + expect(datavizWebmap.mapParams.description).toBe(''); + done(); + }); + }); + it('WMS', (done) => { let options = { server: server diff --git a/test/mapboxgl/services/GetFeaturesByBoundsSpec.js b/test/mapboxgl/services/GetFeaturesByBoundsSpec.js index c88acc9bab..d8e7ae708a 100644 --- a/test/mapboxgl/services/GetFeaturesByBoundsSpec.js +++ b/test/mapboxgl/services/GetFeaturesByBoundsSpec.js @@ -63,26 +63,40 @@ describe('mapboxgl_FeatureService_getFeaturesByBounds', () => { done(); }); }); - it('GetFeaturesByBoundsParameters:targetEpsgCode', done => { - var sw = new mapboxgl.LngLat(-20, -20); - var ne = new mapboxgl.LngLat(20, 20); - var lngLatBounds = new mapboxgl.LngLatBounds(sw, ne); - var boundsParam = new GetFeaturesByBoundsParameters({ - datasetNames: ['World:Capitals'], - bounds: lngLatBounds, - targetEpsgCode: 4326 - }); - var service = new FeatureService(url); - spyOn(FetchRequest, 'commit').and.callFake((method, testUrl, params, options) => { - var paramsObj = JSON.parse(params.replace(/'/g, '"')); - expect(paramsObj.targetEpsgCode).toEqual(4326); - return Promise.resolve(new Response(JSON.stringify(getFeaturesResultJson))); - }); - service.getFeaturesByBounds(boundsParam, result => { - serviceResult = result; - boundsParam.destroy(); - done(); - }); + it('getFeaturesByBounds preferServer', done => { + var sw = new mapboxgl.LngLat(-20, -20); + var ne = new mapboxgl.LngLat(20, 20); + var lngLatBounds = new mapboxgl.LngLatBounds(sw, ne); + var boundsParam = new GetFeaturesByBoundsParameters({ + datasetNames: ['World:Capitals'], + bounds: lngLatBounds, + fromIndex: 1, + toIndex: 3 + }); + var service = new FeatureService(url, { preferServer: true }); + spyOn(FetchRequest, 'commit').and.callFake((method, testUrl, params, options) => { + expect(method).toBe('POST'); + expect(testUrl).toBe(url + '/featureResults.geojson?fromIndex=1&toIndex=3&returnContent=true'); + var paramsObj = JSON.parse(params.replace(/'/g, '"')); + expect(paramsObj.datasetNames[0]).toBe('World:Capitals'); + expect(paramsObj.getFeatureMode).toBe('BOUNDS'); + expect(paramsObj.spatialQueryMode).toBe('CONTAIN'); + expect(options).not.toBeNull(); + expect(options.withoutFormatSuffix).toBe(true); + return Promise.resolve(new Response(JSON.stringify(getFeaturesBySQLService.result.features))); + }); + service.getFeaturesByBounds(boundsParam, testResult => { + serviceResult = testResult; + expect(service).not.toBeNull(); + expect(serviceResult.type).toBe('processCompleted'); + expect(serviceResult.object.format).toBe('GEOJSON'); + var result = serviceResult.result; + expect(result.succeed).toBe(true); + expect(result.features.type).toEqual('FeatureCollection'); + expect(serviceResult.object.preferServer).toBe(true); + boundsParam.destroy(); + done(); + }); }); it('GetFeaturesByBoundsParameters:targetPrj', done => { var sw = new mapboxgl.LngLat(-20, -20); diff --git a/test/mapboxgl/services/GetFeaturesByBufferSpec.js b/test/mapboxgl/services/GetFeaturesByBufferSpec.js index 8dce24e577..5965e44ccd 100644 --- a/test/mapboxgl/services/GetFeaturesByBufferSpec.js +++ b/test/mapboxgl/services/GetFeaturesByBufferSpec.js @@ -72,6 +72,51 @@ describe('mapboxgl_FeatureService_getFeaturesByBuffer', () => { done(); }); }); + it('getFeaturesByBuffer_geometry preferServer', done => { + var queryBufferGeometry = { + type: 'Polygon', + coordinates: [ + [ + [-20, 20], + [-20, -20], + [20, -20], + [20, 20], + [-20, 20] + ] + ] + }; + var bufferParam = new GetFeaturesByBufferParameters({ + datasetNames: ['World:Capitals'], + bufferDistance: 10, + geometry: queryBufferGeometry, + fromIndex: 1, + toIndex: 3 + }); + var service = new FeatureService(url, { preferServer: true }); + spyOn(FetchRequest, 'commit').and.callFake((method, testUrl, params, options) => { + expect(method).toBe('POST'); + expect(testUrl).toBe(url + '/featureResults.geojson?fromIndex=1&toIndex=3&returnContent=true'); + var paramsObj = JSON.parse(params.replace(/'/g, '"')); + expect(paramsObj.datasetNames[0]).toBe('World:Capitals'); + expect(paramsObj.bufferDistance).toEqual(10); + expect(paramsObj.getFeatureMode).toBe('BUFFER'); + expect(options.withoutFormatSuffix).toBe(true); + expect(options).not.toBeNull(); + return Promise.resolve(new Response(JSON.stringify(getFeaturesBySQLService.result.features))); + }); + service.getFeaturesByBuffer(bufferParam, testResult => { + serviceResult = testResult; + expect(service).not.toBeNull(); + expect(serviceResult.type).toBe('processCompleted'); + expect(serviceResult.object.format).toBe('GEOJSON'); + var result = serviceResult.result; + expect(result.succeed).toBe(true); + expect(serviceResult.result.features.type).toEqual('FeatureCollection'); + expect(serviceResult.object.preferServer).toBe(true); + bufferParam.destroy(); + done(); + }); + }); it('GetFeaturesByBufferParameters:targetEpsgCode', done => { var queryBufferGeometry = { type: 'Polygon', diff --git a/test/mapboxgl/services/GetFeaturesByGeometrySpec.js b/test/mapboxgl/services/GetFeaturesByGeometrySpec.js index d052d64bfb..755b73f37c 100644 --- a/test/mapboxgl/services/GetFeaturesByGeometrySpec.js +++ b/test/mapboxgl/services/GetFeaturesByGeometrySpec.js @@ -73,6 +73,52 @@ describe('mapboxgl_FeatureService_getFeaturesByGeometry', () => { } }); }); + it('getFeaturesByGeometry preferServer', done => { + var queryPolygonGeometry = { + type: 'Polygon', + coordinates: [ + [ + [0, 0], + [-10, 30], + [-30, 0], + [0, 0] + ] + ] + }; + var geometryParam = new GetFeaturesByGeometryParameters({ + datasetNames: ['World:Countries'], + geometry: queryPolygonGeometry, + spatialQueryMode: 'INTERSECT' + }); + var service = new FeatureService(url, { preferServer: true }); + spyOn(FetchRequest, 'commit').and.callFake((method, testUrl, params, options) => { + expect(method).toBe('POST'); + expect(testUrl).toBe(url + '/featureResults.geojson?fromIndex=0&toIndex=19&returnContent=true'); + var paramsObj = JSON.parse(params.replace(/'/g, '"')); + expect(paramsObj.datasetNames[0]).toBe('World:Countries'); + expect(paramsObj.spatialQueryMode).toBe('INTERSECT'); + expect(options.withoutFormatSuffix).toBe(true); + expect(options).not.toBeNull(); + return Promise.resolve(new Response(JSON.stringify(getFeaturesBySQLService.result.features))); + }); + service.getFeaturesByGeometry(geometryParam, result => { + serviceResult = result; + try { + expect(service).not.toBeNull(); + expect(serviceResult).not.toBeNull(); + expect(serviceResult.type).toBe('processCompleted'); + expect(serviceResult.result.succeed).toBe(true); + expect(serviceResult.options.data).toContain('World:Countries'); + expect(serviceResult.object.preferServer).toBe(true); + expect(serviceResult.result.features.type).toBe('FeatureCollection'); + done(); + } catch (e) { + console.log("'getFeaturesByGeometry preferServer'案例失败" + e.name + ':' + e.message); + expect(false).toBeTruthy(); + done(); + } + }); + }); it('GetFeaturesByGeometryParameters:targetEpsgCode', done => { var queryPolygonGeometry = { type: 'Polygon', diff --git a/test/mapboxgl/services/GetFeaturesByIDsSpec.js b/test/mapboxgl/services/GetFeaturesByIDsSpec.js index 34e691e884..7d3eeeb2dc 100644 --- a/test/mapboxgl/services/GetFeaturesByIDsSpec.js +++ b/test/mapboxgl/services/GetFeaturesByIDsSpec.js @@ -20,19 +20,65 @@ describe('mapboxgl_FeatureService_getFeaturesByIDs', () => { //数据集ID查询服务 it('getFeaturesByIDs', done => { + var idsParam = new GetFeaturesByIDsParameters({ + IDs: [247], + datasetNames: ['World:Countries'] + }); + var service = new FeatureService(url); + spyOn(FetchRequest, 'commit').and.callFake((method, testUrl, params, options) => { + expect(method).toBe('POST'); + expect(testUrl).toBe(url + '/featureResults?fromIndex=0&toIndex=19&returnContent=true'); + var paramsObj = JSON.parse(params.replace(/'/g, '"')); + expect(paramsObj.datasetNames[0]).toBe('World:Countries'); + expect(paramsObj.getFeatureMode).toBe('ID'); + expect(options).not.toBeNull(); + return Promise.resolve(new Response(JSON.stringify(getFeaturesResultJson))); + }); + service.getFeaturesByIDs(idsParam, result => { + serviceResult = result; + try { + expect(service).not.toBeNull(); + expect(serviceResult).not.toBeNull(); + expect(serviceResult.type).toBe('processCompleted'); + expect(serviceResult.result.succeed).toBe(true); + expect(serviceResult.options.data).toContain('World:Countries'); + expect(serviceResult.result.featureCount).toEqual(1); + expect(serviceResult.result.totalCount).toEqual(serviceResult.result.featureCount); + expect(serviceResult.result.features.type).toEqual('FeatureCollection'); + expect(serviceResult.result.features.features[0].id).toEqual(127); + expect(serviceResult.result.features.features[0].type).toEqual('Feature'); + expect(serviceResult.result.features.features[0].geometry.type).toEqual('MultiPolygon'); + var coordinates = serviceResult.result.features.features[0].geometry.coordinates; + expect(coordinates.length).toBeGreaterThan(0); + for (var i = 0; i < coordinates.length; i++) { + expect(coordinates[i][0].length).toBeGreaterThan(0); + for (var j = 0; j < coordinates[i][0].length; j++) { + expect(coordinates[i][0][j].length).toEqual(2); + } + } + done(); + } catch (e) { + console.log("'getFeaturesByIDs'案例失败" + e.name + ':' + e.message); + expect(false).toBeTruthy(); + done(); + } + }); + }); + it('getFeaturesByIDs preferServer', done => { var idsParam = new GetFeaturesByIDsParameters({ IDs: [247], datasetNames: ['World:Countries'] }); - var service = new FeatureService(url); + var service = new FeatureService(url, { preferServer: true }); spyOn(FetchRequest, 'commit').and.callFake((method, testUrl, params, options) => { expect(method).toBe('POST'); - expect(testUrl).toBe(url + '/featureResults?fromIndex=0&toIndex=19&returnContent=true'); + expect(testUrl).toBe(url + '/featureResults.geojson?fromIndex=0&toIndex=19&returnContent=true'); var paramsObj = JSON.parse(params.replace(/'/g, '"')); expect(paramsObj.datasetNames[0]).toBe('World:Countries'); expect(paramsObj.getFeatureMode).toBe('ID'); expect(options).not.toBeNull(); - return Promise.resolve(new Response(JSON.stringify(getFeaturesResultJson))); + expect(options.withoutFormatSuffix).toBe(true); + return Promise.resolve(new Response(JSON.stringify(getFeaturesBySQLService.result.features))); }); service.getFeaturesByIDs(idsParam, result => { serviceResult = result; @@ -41,24 +87,12 @@ describe('mapboxgl_FeatureService_getFeaturesByIDs', () => { expect(serviceResult).not.toBeNull(); expect(serviceResult.type).toBe('processCompleted'); expect(serviceResult.result.succeed).toBe(true); + expect(serviceResult.object.preferServer).toBe(true); expect(serviceResult.options.data).toContain('World:Countries'); - expect(serviceResult.result.featureCount).toEqual(1); - expect(serviceResult.result.totalCount).toEqual(serviceResult.result.featureCount); expect(serviceResult.result.features.type).toEqual('FeatureCollection'); - expect(serviceResult.result.features.features[0].id).toEqual(127); - expect(serviceResult.result.features.features[0].type).toEqual('Feature'); - expect(serviceResult.result.features.features[0].geometry.type).toEqual('MultiPolygon'); - var coordinates = serviceResult.result.features.features[0].geometry.coordinates; - expect(coordinates.length).toBeGreaterThan(0); - for (var i = 0; i < coordinates.length; i++) { - expect(coordinates[i][0].length).toBeGreaterThan(0); - for (var j = 0; j < coordinates[i][0].length; j++) { - expect(coordinates[i][0][j].length).toEqual(2); - } - } done(); } catch (e) { - console.log("'getFeaturesByIDs'案例失败" + e.name + ':' + e.message); + console.log("'getFeaturesByIDs preferServer'案例失败" + e.name + ':' + e.message); expect(false).toBeTruthy(); done(); } diff --git a/test/mapboxgl/services/GetFeaturesBySQLSpec.js b/test/mapboxgl/services/GetFeaturesBySQLSpec.js index 048320f797..0531fbc8bc 100644 --- a/test/mapboxgl/services/GetFeaturesBySQLSpec.js +++ b/test/mapboxgl/services/GetFeaturesBySQLSpec.js @@ -26,7 +26,87 @@ describe('mapboxgl_FeatureService_getFeaturesBySQL', () => { expect(getFeaturesBySQLService.options.headers).not.toBeNull(); }); - //数据集SQL查询服务 + it('getFeaturesBySQL geojson preferServer true', done => { + var sqlParam = new GetFeaturesBySQLParameters({ + queryParameter: { + name: 'Countries@World', + attributeFilter: 'SMID = 247' + }, + datasetNames: ['World:Countries'] + }); + var service = new FeatureService(url, { preferServer: true }); + spyOn(FetchRequest, 'commit').and.callFake((method, testUrl, params, options) => { + expect(method).toBe('POST'); + expect(testUrl).toBe(url + '/featureResults.geojson?fromIndex=0&toIndex=19&returnContent=true'); + var paramsObj = JSON.parse(params.replace(/'/g, '"')); + expect(paramsObj.datasetNames[0]).toBe('World:Countries'); + expect(paramsObj.getFeatureMode).toBe('SQL'); + expect(options).not.toBeNull(); + expect(options.withoutFormatSuffix).toBe(true); + return Promise.resolve(new Response(JSON.stringify(getFeaturesBySQLService.result.features))); + }); + service.getFeaturesBySQL(sqlParam, result => { + serviceResult = result; + + try { + expect(service).not.toBeNull(); + expect(serviceResult).not.toBeNull(); + expect(serviceResult.type).toBe('processCompleted'); + expect(serviceResult.result.succeed).toBe(true); + expect(serviceResult.object.preferServer).toBe(true); + expect(serviceResult.result.features.type).toBe('FeatureCollection'); + expect(serviceResult.options.data).toContain('Countries@World'); + expect(serviceResult.options.data).toContain('SMID = 247'); + done(); + } catch (e) { + console.log("'getFeaturesBySQL prefreServer'案例失败" + e.name + ':' + e.message); + expect(false).toBeTruthy(); + done(); + } + }); + }); + + it('getFeaturesBySQL iserver preferServer true', done => { + var sqlParam = new GetFeaturesBySQLParameters({ + queryParameter: { + name: 'Countries@World', + attributeFilter: 'SMID = 247' + }, + datasetNames: ['World:Countries'] + }); + var service = new FeatureService(url, { preferServer: true }); + spyOn(FetchRequest, 'commit').and.callFake((method, testUrl, params, options) => { + expect(method).toBe('POST'); + expect(testUrl).toBe(url + '/featureResults?fromIndex=0&toIndex=19&returnContent=true'); + var paramsObj = JSON.parse(params.replace(/'/g, '"')); + expect(paramsObj.datasetNames[0]).toBe('World:Countries'); + expect(paramsObj.getFeatureMode).toBe('SQL'); + expect(options).not.toBeNull(); + expect(options.withoutFormatSuffix).toBe(false); + return Promise.resolve(new Response(JSON.stringify(getFeaturesResultJson))); + }); + service.getFeaturesBySQL(sqlParam, result => { + serviceResult = result; + try { + expect(service).not.toBeNull(); + expect(serviceResult).not.toBeNull(); + expect(serviceResult.type).toBe('processCompleted'); + expect(serviceResult.result.succeed).toBe(true); + expect(serviceResult.object.preferServer).toBe(true); + expect(serviceResult.result.features).not.toBeNull(); + expect(serviceResult.options.data).toContain('Countries@World'); + expect(serviceResult.options.data).toContain('SMID = 247'); + expect(serviceResult.result.featureCount).toEqual(1); + expect(serviceResult.result.totalCount).toEqual(1); + done(); + } catch (e) { + console.log("'getFeaturesBySQL prefreServer'案例失败" + e.name + ':' + e.message); + expect(false).toBeTruthy(); + done(); + } + }, 'ISERVER'); + }); + it('getFeaturesBySQL', done => { var sqlParam = new GetFeaturesBySQLParameters({ queryParameter: {