From 6a71c216a24a6623e4aa0b45d7c3240562c09c96 Mon Sep 17 00:00:00 2001 From: wujingjing <gersonwu@qq.com> Date: 星期一, 17 二月 2025 10:38:17 +0800 Subject: [PATCH] 定位高亮 --- src/model/map/OLMap.ts | 378 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 338 insertions(+), 40 deletions(-) diff --git a/src/model/map/OLMap.ts b/src/model/map/OLMap.ts index 783d561..a586b7c 100644 --- a/src/model/map/OLMap.ts +++ b/src/model/map/OLMap.ts @@ -18,13 +18,16 @@ import VectorSource from 'ol/source/Vector'; import VectorTileSource from 'ol/source/VectorTile'; import WMTS from 'ol/source/WMTS'; -import { Circle, Fill, Stroke, Style } from 'ol/style'; +import { Circle, Fill, Stroke, Style, Text } from 'ol/style'; import WMTSTileGrid from 'ol/tilegrid/WMTS'; import type { ViewOptions } from 'ol/View'; import type { Ref, ShallowRef } from 'vue'; import { markRaw, ref } from 'vue'; import { MarkerOverlay } from './overlay/marker'; -import { Text } from 'ol/style'; +import { Logger } from '../logger/Logger'; +import axios from 'axios'; +import WKT from 'ol/format/WKT'; +import { getCurrentPosition } from '/@/utils/brower'; export type LangType = 'zh_cn' | 'en'; export const enum GaoDeSourceType { @@ -61,7 +64,6 @@ }; type MapConfig = { sourceType: GaoDeSourceType; - markerIsVisible: boolean; }; type OLEventType = 'blackClick' | 'featureChange' | 'featureHoverChange'; @@ -91,9 +93,8 @@ themeInfo = ref([] as any[]); activeSourceType: Ref<GaoDeSourceType> = ref(GaoDeSourceType.Vector); - markerIsVisible: Ref<boolean> = ref(true); interactLayer: VectorLayer<VectorSource<Feature<Geometry>>, Feature<Geometry>> = null; - + searchHighlightLayer: VectorLayer<VectorSource<Feature<Geometry>>, Feature<Geometry>> = null; /** @description 褰撳墠婵�娲荤姸鎬� feature */ activeFeature: ShallowRef<FeatureLike> = ref(null); private emit(eventName: OLEventType, ...args: any[]) { @@ -126,13 +127,12 @@ } constructor(options: OLMapOptions) { - const { container, view, sourceType, markerIsVisible } = defaultsDeep(options, { + const { container, view, sourceType } = defaultsDeep(options, { view: { center: [13247019.404399557, 4721671.572580107], zoom: 8, }, sourceType: GaoDeSourceType.Vector, - markerIsVisible: true, } as OLMapOptions) as OLMapOptions; this.source = new XYZ({ crossOrigin: 'anonymous', @@ -152,11 +152,107 @@ view: new View(view), interactions: olDefaults({ doubleClickZoom: false }), }); + this.activeSourceType.value = sourceType; - this.markerIsVisible.value = markerIsVisible; this.applySourceType(this.activeSourceType.value); this.listenMapClick(); this.addBasicControl(); + this.initEvent(); + } + + gaodeApiKey = 'eea6302da02576fe3f3dd3ba1fbe0a04'; + + async locationCurrent() { + const position = await getCurrentPosition(); + if (!position) return; + const { latitude, longitude } = position; + + return; + const url = `https://restapi.amap.com/v5/ip/location?key=${this.gaodeApiKey}`; + const response = await axios.get(url); + } + + async gaodeAddressSearch(address) { + this.gaodeApiKey = 'eea6302da02576fe3f3dd3ba1fbe0a04'; + // const url = `https://restapi.amap.com/v3/assistant/inputtips?output=json&city=010&keywords=${address}=${this.gaodeApiKey}`; + // 鎼滅储 POI + const url = `https://restapi.amap.com/v3/place/text?keywords=${address}&city=fuzhou&offset=20&page=1&key=${this.gaodeApiKey}&extensions=all `; + // 鎼滅储 POI 2.0 + // const url = `https://restapi.amap.com/v5/place/text?keywords=${address}&city=beijing&offset=20&page=1&key=${this.gaodeApiKey}&extensions=all + + const response = await axios.get(url); + return response.data; + } + + readWKT(wktStr) { + const srid = wktStr.match(/SRID=(\d+);/)?.[1]; + const standardWktStr = wktStr.replace(/SRID=\d+;/, ''); + const feature = new WKT().readFeature(standardWktStr, { + dataProjection: `EPSG:${srid}`, + }); + return feature; + } + + clearObjectSearch() { + this.highlightSearch([]); + } + + displaySearchResult(searchItem) { + if (!searchItem?.WKT) return; + const feature = this.readWKT(searchItem.WKT); + this.highlightSearch(feature); + const geometry = feature.getGeometry(); + + const center = geometry.getCoordinates(); + this.map.getView().setCenter(center); + this.map.getView().setZoom(16); + } + + initEvent() { + const that = this; + this.map.on('moveend', function (e) { + const zoom = that.map.getView().getZoom(); //鑾峰彇褰撳墠鍦板浘鐨勭缉鏀剧骇鍒� + Logger.info('褰撳墠鍦板浘缂╂斁绾у埆涓猴細' + zoom); + }); + } + + hightLightColor: '0000FFFF'; + sizeRate: 0; + + getPointHighLightStyle(feature) { + if (!feature) return null; + let pSize = feature.get('psize') ?? 15; + pSize += pSize * 2; + + const pcolor = '0000FFFF'; + const pstyle = feature.get('pstyle'); + return this.getPointStyles({ color: pcolor, size: pSize, style: pstyle }); + } + + getLineHighLightStyle(feature) { + if (!feature) return null; + + const lcolor = this.hightLightColor; + let lsize = feature.get('lsize') ?? 15; + lsize += lsize * this.sizeRate; + const lstyle = feature.get('lstyle'); + return this.getLineStyles({ lsize: lsize, lcolor: lcolor, lstyle: lstyle }); + } + + getPolygonHighLightStyle(feature) { + if (!feature) return null; + + const lcolor = this.hightLightColor; + // return this.getPolygonStyles({ pcolor: lcolor, lstyle: 'default', lsize: 2 }); + return new Style({ + stroke: new Stroke({ + color: lcolor, + width: 5, + }), + // fill: new Fill({ + // color: lcolor, + // }), + }); } // 淇濆瓨鐐规牱寮忕紦瀛� @@ -168,7 +264,7 @@ * @returns */ getPointStyles(config: { size; color; style }) { - const pSize = config.size ?? 15; + const pSize = config.size; const pcolor = config.color; const pstyle = config.style; @@ -193,6 +289,7 @@ this.pointStyeMap[pkey] = new Style({ text: new Text({ font: `${pSize}px "ywifont"`, + text: config?.text ?? '', fill: new Fill({ color: `#${pcolor}` }), }), @@ -356,6 +453,22 @@ this.adjustViewToOverlays(markers); } + checkEquipIsShow() { + for (const item of this.layerInfo.value) { + if (item.id === 'equip') { + return item.isVisible; + } + } + return false; + } + + getEquipOverlay() { + for (const item of this.layerInfo.value) { + if (item.type === 'equip') { + return item; + } + } + } createEleOverlay(dom: string | HTMLElement, position = [0, 0]) { const ele = typeof dom === 'string' ? (document.querySelector(dom) as HTMLElement) : dom; if (!ele) return; @@ -366,7 +479,7 @@ stopEvent: false, className: 'z-[999]', }); - eleOverlay.setVisible(this.markerIsVisible.value); + eleOverlay.setVisible(this.checkEquipIsShow()); return eleOverlay; } @@ -456,18 +569,13 @@ this.emit('featureChange', feature, layer); } if (feature) { - console.log('馃殌 ~ feature:', feature); const otype = feature.get('otype'); - console.log('馃殌 ~ otype:', otype); const oname = feature.get('oname'); - console.log('馃殌 ~ oname:', oname); const geometryType = feature.getGeometry().getType(); - console.log('馃殌 ~ geometryType:', geometryType); const properties = feature.getProperties(); - console.log('馃殌 ~ properties:', properties); } + this.highlightSelect(feature); this.activeFeature.value = feature; - // this.displayFeatureInfo(feature); }); } @@ -475,23 +583,29 @@ this.themeInfo.value = themeInfo; } + getAllLayers() { + const allLayers = this.layerInfo.value.reduce((preVal, curVal) => { + if (curVal.children && curVal.children.length > 0) { + return preVal.concat(curVal.children.map((item) => item)); + } else { + return preVal; + } + }, []); + return allLayers; + } + + getAllLayerModels() { + return this.layerInfo.value.reduce((preVal, curVal) => { + if (curVal.children && curVal.children.length > 0) { + return preVal.concat(curVal.children.map((item) => item.model)); + } else { + return preVal; + } + }, []); + } + /** @description 璁板綍鎵�鏈夊浘灞� */ setAllLayers(layerModels: Layer[], layers: any[], layerGroup: any[]) { - // this.layerInfo.value = layerModels.map((layer, index) => { - // const layerData = layers[index]; - - // return { - // id: layerData.id, - // title: layerData.title, - // model: markRaw(layer), - // get isVisible() { - // return layer.getVisible(); - // }, - // set isVisible(val) { - // layer.setVisible(val); - // }, - // }; - // }); this.layerInfo.value = layerGroup.reduce((preVal, curVal) => { const group = curVal.group; const groupId = `group-${group}`; @@ -510,9 +624,20 @@ } const layer = layerModels[foundIndex]; const layerData = layers[foundIndex]; + //#region ====================== 璁剧疆缂╂斁绾у埆 ====================== + if (layerData?.max_ratio !== null) { + layer.setMaxZoom(layerData.max_ratio); + } + + if (layerData?.min_ratio !== null) { + layer.setMinZoom(layerData.min_ratio); + } + //#endregion + const data = { id: layerData.id, title: layerData.title, + icon: layerData.icon, model: markRaw(layer), get isVisible() { return layer.getVisible(); @@ -525,6 +650,21 @@ mapGroupItem.children.push(data); return preVal; }, []); + const that = this; + this.layerInfo.value.push({ + id: 'equip', + title: '鐩戞祴璁惧', + children: [], + _isVisible: true, + get isVisible() { + return this._isVisible; + }, + set isVisible(val) { + this._isVisible = val; + that.toggleMarkerOverlayVisible(val); + }, + type: 'equip', + }); } /** @@ -553,21 +693,17 @@ } } }); - this.markerIsVisible.value = visible; } getConfig(): MapConfig { return { sourceType: this.activeSourceType.value, - markerIsVisible: this.markerIsVisible.value, }; } setConfig(config: MapConfig) { this.activeSourceType.value = config.sourceType; - this.markerIsVisible.value = config.markerIsVisible; this.applySourceType(this.activeSourceType.value); - this.toggleMarkerOverlayVisible(this.markerIsVisible.value); } private addBasicControl() { @@ -614,6 +750,9 @@ source: new VectorTileSource({ format: new MVT(), url: url, + // minZoom:5, + // maxZoom:2 + // minZoom:12 }), extent: vectorTileExtent, style: style, @@ -621,14 +760,33 @@ this.map.addLayer(vectorTileLayer); return vectorTileLayer; } - - // highlightFeature = null; - displayFeatureInfo(feature) { + highlightFeature(feature) { const highlightStyle = { + // Point: new Style({ + // // image: new Circle({ + // // radius: 5, + // // fill: new Fill({ color: `blue` }), + // // }), + // image: new Circle({ + // radius: 13, + // stroke: new Stroke({ + // color: `blue`, + // width: 3, + // }), + // }), + // }), + // Point:this.getPointHighLightStyle.call(this,feature), Point: new Style({ + // image: new Circle({ + // radius: 5, + // fill: new Fill({ color: `blue` }), + // }), image: new Circle({ - radius: 5, - fill: new Fill({ color: `blue` }), + radius: 13, + stroke: new Stroke({ + color: `blue`, + width: 3, + }), }), }), LineString: new Style({ @@ -636,6 +794,15 @@ color: `blue`, width: 5, }), + }), + Polygon: new Style({ + stroke: new Stroke({ + color: `blue`, + width: 5, + }), + // fill: new Fill({ + // color: `rgba(0, 0, 255, 0.1)`, + // }), }), }; // 鍒涘缓楂樹寒鍥惧眰 @@ -649,10 +816,115 @@ }, }); } + } + + private searchHighlightStyle = { + // Point: new Style({ + // // image: new Circle({ + // // radius: 5, + // // fill: new Fill({ color: `blue` }), + // // }), + // image: new Circle({ + // radius: 13, + // stroke: new Stroke({ + // color: `blue`, + // width: 3, + // }), + // }), + // }), + // Point:this.getPointHighLightStyle.call(this,feature), + Point: new Style({ + // image: new Circle({ + // radius: 5, + // fill: new Fill({ color: `blue` }), + // }), + image: new Circle({ + radius: 13, + stroke: new Stroke({ + color: `yellow`, + width: 3, + }), + }), + }), + LineString: new Style({ + stroke: new Stroke({ + color: `yellow`, + width: 5, + }), + }), + Polygon: new Style({ + stroke: new Stroke({ + color: `yellow`, + width: 5, + }), + // fill: new Fill({ + // color: `rgba(0, 0, 255, 0.1)`, + // }), + }), + }; + + private selectHighlightStyle = { + // Point: new Style({ + // // image: new Circle({ + // // radius: 5, + // // fill: new Fill({ color: `blue` }), + // // }), + // image: new Circle({ + // radius: 13, + // stroke: new Stroke({ + // color: `blue`, + // width: 3, + // }), + // }), + // }), + // Point:this.getPointHighLightStyle.call(this,feature), + Point: new Style({ + // image: new Circle({ + // radius: 5, + // fill: new Fill({ color: `blue` }), + // }), + image: new Circle({ + radius: 13, + stroke: new Stroke({ + color: `blue`, + width: 3, + }), + }), + }), + LineString: new Style({ + stroke: new Stroke({ + color: `blue`, + width: 5, + }), + }), + Polygon: new Style({ + stroke: new Stroke({ + color: `blue`, + width: 5, + }), + // fill: new Fill({ + // color: `rgba(0, 0, 255, 0.1)`, + // }), + }), + }; + + highlightSelect(feature) { + // 鍒涘缓楂樹寒鍥惧眰 + if (!this.interactLayer) { + this.interactLayer = new VectorLayer({ + source: new VectorSource(), + map: this.map, + style: (feature) => { + const type = feature.getGeometry().getType(); + return this.selectHighlightStyle[type]; + }, + }); + } // 璁剧疆楂樹寒瑕佺礌 if (feature !== this.activeFeature.value) { if (this.activeFeature.value) { + console.log('remove feature:', this.activeFeature.value); this.interactLayer.getSource().removeFeature(this.activeFeature.value as any); } if (feature) { @@ -662,6 +934,32 @@ } } + private preSearchHighlightFeatures: Feature[] = []; + highlightSearch(features) { + if (!Array.isArray(features)) { + features = [features]; + } + // 鍒涘缓楂樹寒鍥惧眰 + if (!this.searchHighlightLayer) { + this.searchHighlightLayer = new VectorLayer({ + source: new VectorSource(), + map: this.map, + style: (feature) => { + const type = feature.getGeometry().getType(); + return this.searchHighlightStyle[type]; + }, + }); + } + if (this.preSearchHighlightFeatures && this.preSearchHighlightFeatures.length > 0) { + this.searchHighlightLayer.getSource().removeFeatures(this.preSearchHighlightFeatures); + } + + // 璁剧疆楂樹寒瑕佺礌 + if (features && features.length > 0) { + this.searchHighlightLayer.getSource().addFeatures(features); + } + this.preSearchHighlightFeatures = features; + } getWMTS = () => { const projection = getProjection('EPSG:3857'); const projectionExtent = projection.getExtent(); -- Gitblit v1.9.3