From b64b2116409dc9880013ef9199e42b831ef1fdaf Mon Sep 17 00:00:00 2001 From: chenxianhui Date: Mon, 8 Apr 2024 09:40:18 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=9B=BE=E5=B1=82=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E3=80=81=E5=9B=BE=E5=B1=82=E9=A2=9C=E8=89=B2=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E6=94=AF=E6=8C=81webmap3.0=20review=20by=20xiongjj?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/_utils/iPortalDataService.js | 11 +- src/mapboxgl/_types/map-event.js | 14 +- .../attributes/AttributesViewModel.ts | 2 +- src/mapboxgl/layer-select/LayerSelect.vue | 112 +++------------ .../layer-select/LayerSelectViewModel.ts | 9 +- src/mapboxgl/web-map/GroupUtil.js | 48 +++++++ src/mapboxgl/web-map/LayerGroup.vue | 105 ++++++++++++++ src/mapboxgl/web-map/LayerListModel.js | 38 +++++ src/mapboxgl/web-map/SourceListModel.js | 27 ++-- src/mapboxgl/web-map/SourceModel.js | 31 ++-- src/mapboxgl/web-map/WebMapViewModel.ts | 82 ++++++++++- .../control/layer-color/LayerColor.vue | 7 +- .../web-map/control/layer-list/LayerList.vue | 133 +++--------------- .../control/layer-list/LayerListViewModel.ts | 53 +++---- .../layer-list/__tests__/LayerList.spec.js | 4 +- .../control/layer-list/style/layer-list.scss | 2 +- 16 files changed, 389 insertions(+), 289 deletions(-) create mode 100644 src/mapboxgl/web-map/GroupUtil.js create mode 100644 src/mapboxgl/web-map/LayerGroup.vue create mode 100644 src/mapboxgl/web-map/LayerListModel.js diff --git a/src/common/_utils/iPortalDataService.js b/src/common/_utils/iPortalDataService.js index 517601ff..4a8310e1 100644 --- a/src/common/_utils/iPortalDataService.js +++ b/src/common/_utils/iPortalDataService.js @@ -69,15 +69,16 @@ export default class iPortalDataService extends Events { * @param {Object} [queryInfo.attributeFilter] - 属性过滤条件。 * @param {Object} [queryInfo.keyWord] - 筛选关键字。 */ - getData(queryInfo, preferContent = false) { - if (!this.url) { + getData(queryInfo = {}, preferContent = false) { + if (this.dataType === 'STRUCTUREDDATA') { + this._getStructureDatafromContent(); return; } - let datasetUrl = this.url; - if (this.dataType === 'STRUCTUREDDATA') { - this._getStructureDatafromContent(datasetUrl, queryInfo); + + if (!this.url) { return; } + let datasetUrl = this.url; if (preferContent) { this._getDatafromContent(datasetUrl, queryInfo); diff --git a/src/mapboxgl/_types/map-event.js b/src/mapboxgl/_types/map-event.js index f45a49b3..ca5674f4 100644 --- a/src/mapboxgl/_types/map-event.js +++ b/src/mapboxgl/_types/map-event.js @@ -40,14 +40,12 @@ export default new Vue({ map }); const sourceList = sourceListModel.getSourceList(); - for (let key in sourceList) { - if (key) { - let layers = sourceList[key].layers || []; - layers.forEach(item => { - if (item.source && item.type !== 'raster') { - sources.push(item.source); - } - }); + for (let item of sourceList) { + if (item) { + let layer = item.layer; + if (layer.source && layer.type !== 'raster') { + sources.push(layer.source); + } } } } diff --git a/src/mapboxgl/attributes/AttributesViewModel.ts b/src/mapboxgl/attributes/AttributesViewModel.ts index 29d622ab..a3138ee4 100644 --- a/src/mapboxgl/attributes/AttributesViewModel.ts +++ b/src/mapboxgl/attributes/AttributesViewModel.ts @@ -444,7 +444,7 @@ class FeatureTableViewModel extends mapboxgl.Evented { if (this.useDataset()) { let datas = await this._getFeaturesFromDataset(); features = datas.features; - !this.totalCount && (this.totalCount = datas.totalCount); + this.totalCount = datas.totalCount; if (this.canLazyLoad()) { if (this.dataset.url !== this.prevDatasetUrl) { let arr = this.dataset.dataName[0].split(':'); diff --git a/src/mapboxgl/layer-select/LayerSelect.vue b/src/mapboxgl/layer-select/LayerSelect.vue index c1968c0c..91c9cb7b 100644 --- a/src/mapboxgl/layer-select/LayerSelect.vue +++ b/src/mapboxgl/layer-select/LayerSelect.vue @@ -95,15 +95,15 @@ class LayerSelect extends Mixins(MapGetter, Theme) { this.$emit('changedata', { id, type }); } - handleDatas(sourceList): treeSelectDataOption[] { + createLayersTreeData(layerCatalog) { const treeData: treeSelectDataOption[] = []; - this.sourceListDataCache = {}; - Object.keys(sourceList).forEach((sourceName, sIndex) => { - let { id, type, visibility } = sourceList[sourceName]; + layerCatalog.forEach(layer => { + let { id, title, type, visible } = layer; + let layerType = layer.layer?.type; let disabled = false; let selectable = true; if (this.filter) { - let res = this.filter(sourceList[sourceName], 'source', this.map) || {}; + let res = this.filter(layerType, type, this.map) || {}; disabled = res.disabled; selectable = res.selectable; @@ -111,104 +111,32 @@ class LayerSelect extends Mixins(MapGetter, Theme) { return; } } - const sourceValue = `${sourceName}+source`; + const layerValue = `${id}+${type}`; const sourceInfo: treeSelectDataOption = { - title: sourceName, - value: sourceValue, - key: `${sIndex}`, + title: title, + value: layerValue, + key: layer.id, disabled: !!disabled, selectable: selectable }; - this.sourceListDataCache[sourceValue] = { + if(type === 'group') { + sourceInfo.children = this.createLayersTreeData(layer.children); + } + this.sourceListDataCache[layerValue] = { id, - type, - visibility + type: layerType, + visibility: visible ? 'visible' : 'none' }; - if (sourceList[sourceName].sourceLayerList) { - const sourceChildren = []; - Object.keys(sourceList[sourceName].sourceLayerList).forEach((sourceLayerName, slIndex) => { - let disabled = false; - let selectable = true; - const sourceLayerOption = { - id: null, - source: id, - sourceLayer: sourceLayerName - }; - if (this.filter) { - let res = this.filter(sourceLayerOption, 'sourceLayer', this.map) || {}; - disabled = res.disabled; - selectable = res.selectable; - - if (typeof res.show === 'boolean' && res.show === false) { - return; - } - } - const sourceLayerValue = `${sourceLayerName}+sourceLayer`; - const sourceLayerInfo: treeSelectDataOption = { - title: sourceLayerName, - value: sourceLayerValue, - key: `${sIndex}-${slIndex}`, - disabled: !!disabled, - selectable - }; - - this.sourceListDataCache[sourceLayerValue] = sourceLayerOption; - let layers: layerOption[] = sourceList[sourceName].sourceLayerList[sourceLayerName]; - const sourceLayerChildren = this.handleLayers(layers, `${sIndex}-${slIndex}`); - if (sourceLayerChildren.length) { - sourceLayerInfo.children = sourceLayerChildren; - } - sourceChildren.push(sourceLayerInfo); - }); - if (sourceChildren.length) { - sourceInfo.children = sourceChildren; - } - } else { - let layers: layerOption[] = sourceList[sourceName].layers; - const layerChildren = this.handleLayers(layers, sIndex); - if (layerChildren.length) { - sourceInfo.children = layerChildren; - } - } treeData.push(sourceInfo); }); return treeData; } - handleLayers(layers: layerOption[], keyString: number | string): treeSelectDataOption[] { - const layerChildren = []; - layers.forEach((layerInfo, lIndex) => { - let { id, maxzoom, minzoom, source, sourceLayer, type, visibility } = layerInfo; - let disabled = false; - let selectable = true; - if (this.filter) { - let res = this.filter(layerInfo, 'layer', this.map) || {}; - disabled = res.disabled; - selectable = res.selectable; - - if (typeof res.show === 'boolean' && res.show === false) { - return; - } - } - const layerValue = `${layerInfo.id}+layer`; - layerChildren.push({ - title: layerInfo.id, - value: layerValue, - key: `${keyString}-${lIndex}`, - disabled: !!disabled, - selectable - }); - this.sourceListDataCache[layerValue] = { - id, - maxzoom, - minzoom, - source, - sourceLayer, - type, - visibility - }; - }); - return layerChildren; + handleDatas(sourceList): treeSelectDataOption[] { + let treeData: treeSelectDataOption[] = []; + this.sourceListDataCache = {}; + treeData = this.createLayersTreeData(sourceList); + return treeData; } getPopupContainer(triggerNode) { diff --git a/src/mapboxgl/layer-select/LayerSelectViewModel.ts b/src/mapboxgl/layer-select/LayerSelectViewModel.ts index 2a6519d7..72f55c2f 100644 --- a/src/mapboxgl/layer-select/LayerSelectViewModel.ts +++ b/src/mapboxgl/layer-select/LayerSelectViewModel.ts @@ -1,5 +1,4 @@ import mapboxgl from 'vue-iclient/static/libs/mapboxgl/mapbox-gl-enhance'; -import SourceListModel from 'vue-iclient/src/mapboxgl/web-map/SourceListModel'; /** * @class LayerSelectViewModel @@ -18,16 +17,14 @@ class LayerSelectViewModel extends mapboxgl.Evented { } _updateLayers() { - const sourceListModel = new SourceListModel({ - map: this.map - }); - const sourceList = sourceListModel.getSourceList(); + const sourceList = this.webmap.getLayerList(); this.fire('layersupdated', { sourceList }); } setMap(mapInfo: mapInfoType) { - const { map } = mapInfo; + const { map, webmap } = mapInfo; this.map = map; + this.webmap = webmap; this.map.on('styledata', this.updateFn); this._updateLayers(); } diff --git a/src/mapboxgl/web-map/GroupUtil.js b/src/mapboxgl/web-map/GroupUtil.js new file mode 100644 index 00000000..f1121c8a --- /dev/null +++ b/src/mapboxgl/web-map/GroupUtil.js @@ -0,0 +1,48 @@ +class GroupUtil { + getGroupVisible(catalogs, item) { + const rootGroup = this.getRootGroup(catalogs, item); + if (!rootGroup) return true; + + const { visible, children } = rootGroup; + if (!visible) return false; + + return this.getGroupVisible(children, item); + } + + getRootGroup(catalogs, item) { + const isRootItem = catalogs.find(c => (c.id === item.id)); + if (isRootItem) return; // 说明是顶层,不存在父图层组 + + // 图层组中的图层/图层组 + const groups = catalogs.filter(catalog => catalog.type === 'group'); + return groups.find((g) => this.isChild(g, item)); + } + + // 是否是当前图层组的 子图层/子图层组 + isChild(group, child) { + const { children } = group; + const target = children.find((c) => c.id === child.id); + if (target) return true; + + const childrenGroup = children.filter(catalog => catalog.type === 'group'); + return !!childrenGroup.find((c) => this.isChild(c, child)); + } + + getGroupChildrenLayers(layerGroup) { + const targetItems = []; + for (const item of layerGroup) { + // 图层组和图层都只选择可见的 + if (item.visible === false) continue; + + if (item.type !== 'group') { + targetItems.push(item); + continue; + } + // 图层组 + const group = item; + targetItems.push(...this.getGroupChildrenLayers(group.children)); + } + return targetItems; + } +} +export default GroupUtil; diff --git a/src/mapboxgl/web-map/LayerGroup.vue b/src/mapboxgl/web-map/LayerGroup.vue new file mode 100644 index 00000000..65971081 --- /dev/null +++ b/src/mapboxgl/web-map/LayerGroup.vue @@ -0,0 +1,105 @@ + + + + + diff --git a/src/mapboxgl/web-map/LayerListModel.js b/src/mapboxgl/web-map/LayerListModel.js new file mode 100644 index 00000000..38f60ca7 --- /dev/null +++ b/src/mapboxgl/web-map/LayerListModel.js @@ -0,0 +1,38 @@ +import GroupUtil from 'vue-iclient/src/mapboxgl/web-map/GroupUtil'; +import LayerModel from 'vue-iclient/src/mapboxgl/web-map/LayerModel'; + +class LayerListModel extends GroupUtil { + constructor(options) { + super(); + this.map = options.map; + this.layerCatalog = options.layerCatalog; + } + + getLayerCatalog() { + if(!this.layerCatalog) return; + const baseLayer = this.map.getStyle().layers[0]; + const baseLayerCatalog = { + id: baseLayer.id, + title: baseLayer.id, + type: 'basic', + layer: baseLayer, + visible: true + }; + this.addInfoToCatalog(this.layerCatalog); + return [baseLayerCatalog].concat(this.layerCatalog); + } + + addInfoToCatalog(layerCatalog) { + layerCatalog.forEach(catalog => { + if(catalog.children) { + this.addInfoToCatalog(catalog.children); + } + // 获取layer + if(catalog.type === 'basic') { + const detailLayer = this.map.getLayer(catalog.id); + catalog.layer = new LayerModel(detailLayer); + } + }); + } +} +export default LayerListModel; diff --git a/src/mapboxgl/web-map/SourceListModel.js b/src/mapboxgl/web-map/SourceListModel.js index f12b1455..9cf841ee 100644 --- a/src/mapboxgl/web-map/SourceListModel.js +++ b/src/mapboxgl/web-map/SourceListModel.js @@ -1,14 +1,16 @@ import SourceModel from 'vue-iclient/src/mapboxgl/web-map/SourceModel'; import LayerModel from 'vue-iclient/src/mapboxgl/web-map/LayerModel'; +import GroupUtil from 'vue-iclient/src/mapboxgl/web-map/GroupUtil'; -class SourceListModel { +class SourceListModel extends GroupUtil { constructor(options) { + super(); this.map = options.map; this.style = this.map.getStyle(); this.layers = this.map.getStyle().layers; this.overlayLayers = this.map.overlayLayersManager; this.detailLayers = null; - this.sourceList = {}; + this.sourceList = []; this.sourceNames = []; this._initLayers(); this._initSource(); @@ -16,10 +18,10 @@ class SourceListModel { } getSourceList() { - let sourceList = {}; - for (let key in this.sourceList) { - if (key && this.excludeSource(key)) { - sourceList[key] = this.sourceList[key]; + let sourceList = []; + for (let item of this.sourceList) { + if (item && this.excludeSource(item.id)) { + sourceList.push(item); } } return sourceList; @@ -91,15 +93,16 @@ class SourceListModel { _initSource() { this.detailLayers && this.detailLayers.forEach(layer => { - if (!this.sourceList[layer.source]) { - const source = this.map.getSource(layer.source); - this.sourceList[layer.source] = new SourceModel({ - source: layer.source, - type: source && source.type + let matchItem = this.sourceList.find(item => item.id === layer.source); + if (!matchItem) { + const sourceListItem = new SourceModel({ + source: layer.source }); + this.sourceList.unshift(sourceListItem); this.sourceNames.push(layer.source); + matchItem = sourceListItem; } - this.sourceList[layer.source].addLayer(new LayerModel(layer), layer.sourceLayer); + matchItem.addLayer(new LayerModel(layer), layer.sourceLayer); }); } } diff --git a/src/mapboxgl/web-map/SourceModel.js b/src/mapboxgl/web-map/SourceModel.js index f89e912e..d660f494 100644 --- a/src/mapboxgl/web-map/SourceModel.js +++ b/src/mapboxgl/web-map/SourceModel.js @@ -1,25 +1,26 @@ class SourceModel { constructor(options) { this.id = options.source; - this.sourceLayerList = {}; - this.layers = []; + this.title = options.source; + this.children = []; + this.sourceType = options.sourceType; this.type = options.type; } - addLayer(layer, sourceLayer) { - if (sourceLayer) { - if (!this.sourceLayerList[sourceLayer]) { - this.sourceLayerList[sourceLayer] = []; - } - this.sourceLayerList[sourceLayer].push(layer); + addLayer(layer) { + this.children.push({ + id: layer.id, + title: layer.id, + visible: layer.visibility === 'visible', + type: 'basic', + layer: layer + }); + this.type = this.children?.length > 1 ? 'group' : 'basic'; + this.layer = this.type === 'basic' ? layer : undefined; + if (layer.visibility === 'visible' || this.visible) { + this.visible = true; } else { - this.sourceLayerList = undefined; - } - this.layers.push(layer); - if ([layer.visibility, this.visibility].includes('visible')) { - this.visibility = 'visible'; - } else { - this.visibility = 'none'; + this.visible = false; } } } diff --git a/src/mapboxgl/web-map/WebMapViewModel.ts b/src/mapboxgl/web-map/WebMapViewModel.ts index 6eea5c4c..94614611 100644 --- a/src/mapboxgl/web-map/WebMapViewModel.ts +++ b/src/mapboxgl/web-map/WebMapViewModel.ts @@ -4,12 +4,14 @@ import { Events } from 'vue-iclient/src/common/_types/event/Events'; import mapboxgl from 'vue-iclient/static/libs/mapboxgl/mapbox-gl-enhance'; import SourceListModel from 'vue-iclient/src/mapboxgl/web-map/SourceListModel'; +import LayerListModel from 'vue-iclient/src/mapboxgl/web-map/LayerListModel'; import 'vue-iclient/static/libs/iclient-mapboxgl/iclient-mapboxgl.min'; import 'vue-iclient/static/libs/geostats/geostats'; import 'vue-iclient/static/libs/json-sql/jsonsql'; import { toEpsgCode } from 'vue-iclient/src/common/_utils/epsg-define'; import WebMapService from '../../common/_utils/WebMapService'; import WebMapV2 from './WebMapV2'; +import iPortalDataService from 'vue-iclient/src/common/_utils/iPortalDataService'; const WORLD_WIDTH = 360; // 迁徙图最大支持要素数量 @@ -107,6 +109,8 @@ export default class WebMapViewModel extends Events { private _sourceListModel: SourceListModel; + private _layerListModel: LayerListModel; + private _cacheLayerId: Array = []; private _appreciableLayers: Array = []; @@ -291,6 +295,75 @@ export default class WebMapViewModel extends Events { this._cacheLayerId = []; } + public getLayerDatas(layerName) { + if(this._layerListModel) { + const dataId = this.getDatasetIdByLayerId(layerName); + if(!dataId) return []; + let promise = new Promise((resolve, reject) => { + const dataService = new iPortalDataService('', this.withCredentials, { dataId, dataType: 'STRUCTUREDDATA' }); + dataService.on({ + getdatafailed: (e) => { + reject(e); + }, + getdatasucceeded: (e) => { + resolve(e.features); + } + }); + dataService.getData({}); + }); + return promise; + } else { + // @ts-ignore + return Promise.resolve(this.map.getSource(layerName).getData().features); + } + } + + public getDatasetIdByLayerId(layerName) { + const matchLayer = this._appreciableLayers.find(layer => layer.layerID === layerName); + return matchLayer?.dataSource?.serverId; + } + + public getLayerList() { + return this._layerListModel ? this._layerListModel.getLayerCatalog() : this._sourceListModel.getSourceList(); + } + + public getFlatLayers(layers) { + if(!layers) { + layers = this.getLayerList(); + } + let flatLayers = []; + layers.forEach(layer => { + if (layer.children) { + flatLayers = flatLayers.concat(this.getFlatLayers(layer.children)); + } else { + flatLayers.push(layer); + } + }); + return flatLayers; + } + + public changeItemVisible(item) { + const model = this._layerListModel || this._sourceListModel; + // 当前操作的图层/图层组的上级图层组为显示状态,才修改其显隐 + const parentVisible = model.getGroupVisible(this.getLayerList(), item); + if(!parentVisible) { + return; + } + const visibility = item.visible ? 'none' : 'visible'; + if(item.type === 'group') { + const targetLayers = model.getGroupChildrenLayers(item.children); + this.updateLayersVisible(targetLayers, visibility); + } else { + this.updateLayersVisible([item], visibility); + } + } + + updateLayersVisible(layers, visibility) { + layers.forEach(layer => { + this.map.setLayoutProperty(layer.id, 'visibility', visibility); + }); + } + protected initWebMap() { this.cleanWebMap(); this.serverUrl = this.serverUrl && this.webMapService.handleServerUrl(this.serverUrl); @@ -447,7 +520,7 @@ export default class WebMapViewModel extends Events { withCredentials: this.withCredentials, target: this.target }, this.mapOptions); - this._registerV3Events(webMapHandler); + this._registerV3Events(webMapHandler, mapInfo); webMapHandler.createWebMap({ ...mapInfo, layers: typeof this.layerFilter === 'function' ? mapInfo.layers.filter(this.layerFilter) : mapInfo.layers @@ -481,7 +554,7 @@ export default class WebMapViewModel extends Events { }); } - _registerV3Events(webMapHandler): void { + _registerV3Events(webMapHandler, mapInfo): void { if (!webMapHandler) { return; } @@ -492,8 +565,9 @@ export default class WebMapViewModel extends Events { webMapHandler.on('addlayerssucceeded', ({ mapparams, layers }) => { this.mapParams = mapparams; this._appreciableLayers = layers; - this._sourceListModel = new SourceListModel({ - map: this.map + this._layerListModel = new LayerListModel({ + map: this.map, + layerCatalog: mapInfo.metadata.layerCatalog }); this._cacheLayerId.push(...layers.map(layer => layer.id)); this.triggerEvent('addlayerssucceeded', { diff --git a/src/mapboxgl/web-map/control/layer-color/LayerColor.vue b/src/mapboxgl/web-map/control/layer-color/LayerColor.vue index f30c13ae..c2b5724b 100644 --- a/src/mapboxgl/web-map/control/layer-color/LayerColor.vue +++ b/src/mapboxgl/web-map/control/layer-color/LayerColor.vue @@ -72,6 +72,7 @@ const TYPE_MAP = { circle: ['circle-color', 'circle-stroke-color'], line: ['line-color'], fill: ['fill-color', 'fill-outline-color'], + background: ['background-color'], symbol: ['icon-color', 'icon-halo-color', 'text-color', 'text-halo-color'] }; @@ -144,13 +145,13 @@ class SmLayerColor extends Mixins(MapGetter, Control, Theme, BaseCard) { return ''; } - filtercb(item, type) { - if (item.type === 'raster') { + filtercb(layerType, type) { + if (layerType === 'raster' || layerType === 'heatmap') { return { show: false }; } - if (type === 'sourceLayer' || type === 'source') { + if (type === 'group') { return { disabled: true }; diff --git a/src/mapboxgl/web-map/control/layer-list/LayerList.vue b/src/mapboxgl/web-map/control/layer-list/LayerList.vue index 2721ca76..d7b93784 100644 --- a/src/mapboxgl/web-map/control/layer-list/LayerList.vue +++ b/src/mapboxgl/web-map/control/layer-list/LayerList.vue @@ -13,97 +13,13 @@ >
- - - -
- -
- {{ sourcelayerKey }} -
-
-
- -
-
- -
{{ name }}
-
-
- -
-
-
+ +
= []; - sourceList: Object; + sourceList: Array = []; layerList: Array = []; attributesProps: Object = {}; layerUpdateFn: Function; @@ -246,12 +164,6 @@ class SmLayerList extends Mixins(MapGetter, Control, Theme, BaseCard) { return intersection(this.sourceNames, this.sourceList && Object.keys(this.sourceList)); } - get layerName() { - return function (source) { - return source.layers[0].id; - }; - } - get attributesStyle() { let attributesStyle; let position; @@ -294,8 +206,12 @@ class SmLayerList extends Mixins(MapGetter, Control, Theme, BaseCard) { this.viewModel = new LayerListViewModel(); } - toggleVisibility(sourceLayer, sourceName, visibility: string) { - this.viewModel && this.viewModel.changeLayerVisible(sourceLayer, sourceName, visibility); + checkAttributesEnabled(item) { + return this.viewModel.checkAttributesEnabled(item); + } + + toggleItemVisibility(item) { + this.viewModel && this.viewModel.changeItemVisible(item); } addNewLayer() { @@ -306,11 +222,7 @@ class SmLayerList extends Mixins(MapGetter, Control, Theme, BaseCard) { this.viewModel.deleteLayer(); } - toggleLayerGroupVisibility(sourceName, visibility: string) { - this.viewModel && this.viewModel.changeLayerGroupVisibility(sourceName, visibility); - } - - toggleAttributesVisibility(e, layerName: string) { + toggleAttributesVisibility(e, layerName: string, title: string) { if (e.target.className.indexOf('sm-components-icon-attribute-open') !== -1) { e.target.setAttribute('class', this.attributesIconClass); this.displayAttributes = !this.displayAttributes; @@ -318,21 +230,22 @@ class SmLayerList extends Mixins(MapGetter, Control, Theme, BaseCard) { } this.closeAttributesIconClass(); this.removeAttributes(); - this.handleAttributesProps(layerName); + this.handleAttributesProps(layerName, title); e.target.setAttribute('class', `${this.attributesIconClass} sm-components-icon-attribute-open`); // @ts-ignore this.attributesContainer.appendChild(this.$refs.attributes.$el); this.displayAttributes = !this.displayAttributes; } - handleAttributesProps(layerName: string) { + async handleAttributesProps(layerName: string, title: string) { const props = Object.assign({}, this.attributes); for (const key in props) { if (ATTRIBUTES_NEEDED_PROPS.indexOf(key) === -1) { delete props[key]; } } - this.attributesProps = { layerName, title: layerName, ...props }; + const dataset = await this.viewModel.getLayerDatas(layerName); + this.attributesProps = { dataset: Object.freeze(dataset), title, ...props }; } layerUpdate() { diff --git a/src/mapboxgl/web-map/control/layer-list/LayerListViewModel.ts b/src/mapboxgl/web-map/control/layer-list/LayerListViewModel.ts index 42f4372a..6c10d497 100644 --- a/src/mapboxgl/web-map/control/layer-list/LayerListViewModel.ts +++ b/src/mapboxgl/web-map/control/layer-list/LayerListViewModel.ts @@ -1,5 +1,4 @@ import mapboxgl from 'vue-iclient/static/libs/mapboxgl/mapbox-gl-enhance'; -import SourceListModel from 'vue-iclient/src/mapboxgl/web-map/SourceListModel'; /** * @class LayerListViewModel @@ -14,7 +13,7 @@ interface MapEventCallBack { class LayerListViewModel extends mapboxgl.Evented { map: mapboxglTypes.Map; - sourceList: Object; + sourceList: Array; sourceNames: Array; @@ -22,11 +21,9 @@ class LayerListViewModel extends mapboxgl.Evented { updateFn: MapEventCallBack; - sourceListModel: SourceListModel; - constructor() { super(); - this.sourceList = {}; + this.sourceList = []; this.sourceNames = []; } @@ -35,18 +32,15 @@ class LayerListViewModel extends mapboxgl.Evented { } setMap(mapInfo) { - const { map } = mapInfo; + const { map, webmap } = mapInfo; this.map = map; + this.webmap = webmap; this.updateFn = this._updateLayers.bind(this); this.map.on('styledata', this.updateFn); } initLayerList() { - this.sourceListModel = new SourceListModel({ - map: this.map - }); - this.sourceList = this.sourceListModel.getSourceList(); - this.sourceNames = this.sourceListModel.getSourceNames().reverse(); + this.sourceList = this.webmap.getLayerList(); return this.sourceList; } @@ -54,33 +48,32 @@ class LayerListViewModel extends mapboxgl.Evented { return this.sourceNames; } - changeLayerVisible(sourcelayer, sourceName: string, visibility: string) { - this.sourceListModel.getLayersBySourceLayer(sourceName, sourcelayer).forEach(layer => { - this.map.setLayoutProperty(layer.id, 'visibility', this.changeVisibility(visibility)); - }); + checkAttributesEnabled(item) { + const source = this.map.getSource(item.layer.source); + const hasDatasetId = this.webmap.getDatasetIdByLayerId(item.id); + return source.type === 'geojson' || hasDatasetId; } - changeVisibility(visibility: string) { - return visibility === 'visible' ? 'none' : 'visible'; + async getLayerDatas(layerName) { + const features = await this.webmap.getLayerDatas(layerName); + return this.setDataset(features); } - changeLayerGroupVisibility(sourceName: string, visibility: string) { - let sourceLayers = this.sourceListModel.getSourceLayersBySource(sourceName); - if (sourceLayers) { - for (let sourcelayer in sourceLayers) { - sourceLayers[sourcelayer].forEach(layer => { - this.map.setLayoutProperty(layer.id, 'visibility', this.changeVisibility(visibility)); - }); - } - } else { - for (let layer of this.sourceList[sourceName].layers) { - this.map.setLayoutProperty(layer.id, 'visibility', this.changeVisibility(visibility)); - } + // 将features转换成属性表dataset所需的GeoJSONParameter形式 + setDataset(features) { + let dataset = { type: 'geoJSON', geoJSON: null }; + if (features) { + dataset.geoJSON = { type: 'FeatureCollection', features }; } + return dataset; + } + + changeItemVisible(item) { + this.webmap.changeItemVisible(item); } removed() { - this.sourceList = {}; + this.sourceList = []; this.sourceNames = []; this.map.off('styledata', this.updateFn); } diff --git a/src/mapboxgl/web-map/control/layer-list/__tests__/LayerList.spec.js b/src/mapboxgl/web-map/control/layer-list/__tests__/LayerList.spec.js index f3de0062..2a849074 100644 --- a/src/mapboxgl/web-map/control/layer-list/__tests__/LayerList.spec.js +++ b/src/mapboxgl/web-map/control/layer-list/__tests__/LayerList.spec.js @@ -56,7 +56,7 @@ describe('LayerList.vue', () => { await mapWrapperLoaded(mapWrapper); await flushPromises(); expect(callback.mock.called).toBeTruthy; - let spylayerVisibility = jest.spyOn(wrapper.vm, 'toggleLayerGroupVisibility'); + let spylayerVisibility = jest.spyOn(wrapper.vm, 'toggleItemVisibility'); wrapper.findAll('.sm-components-icon-hidden').at(0).trigger('click'); expect(spylayerVisibility).toHaveBeenCalledTimes(1); wrapper.vm.$nextTick(); @@ -127,7 +127,7 @@ describe('LayerList.vue', () => { mapTarget: 'map' } }); - let spyProperty = jest.spyOn(wrapper.vm.viewModel, 'changeLayerGroupVisibility'); + let spyProperty = jest.spyOn(wrapper.vm.viewModel, 'changeItemVisible'); const callback = jest.fn(); wrapper.vm.$on('loaded', callback); await mapWrapperLoaded(mapWrapper); diff --git a/src/mapboxgl/web-map/control/layer-list/style/layer-list.scss b/src/mapboxgl/web-map/control/layer-list/style/layer-list.scss index f43c28c6..ac568571 100644 --- a/src/mapboxgl/web-map/control/layer-list/style/layer-list.scss +++ b/src/mapboxgl/web-map/control/layer-list/style/layer-list.scss @@ -38,7 +38,7 @@ .#{$iconfont-class-prefix}-solid-triangle-down { display: none; } - &.#{$collapse-prefix}-item-active { + &.#{$collapse-prefix}-item-active > .#{$collapse-prefix}-header{ .#{$iconfont-class-prefix}-solid-triangle-right { display: none; }