| | |
| | | import { defaultsDeep } from 'lodash-es'; |
| | | import type { Overlay } from 'ol'; |
| | | import { Map as OpenLayerMap, View } from 'ol'; |
| | | import { ZoomSlider } from 'ol/control'; |
| | | import type { Extent } from 'ol/extent'; |
| | | import { getTopLeft, getWidth } from 'ol/extent'; |
| | | import Tile from 'ol/layer/Tile'; |
| | |
| | | import WMTS from 'ol/source/WMTS'; |
| | | import WMTSTileGrid from 'ol/tilegrid/WMTS'; |
| | | import type { ViewOptions } from 'ol/View'; |
| | | |
| | | import MVT from 'ol/format/MVT.js'; |
| | | import VectorTileLayer from 'ol/layer/VectorTile'; |
| | | import VectorTileSource from 'ol/source/VectorTile'; |
| | | import { defaults as olDefaults } from 'ol/interaction'; |
| | | import type { Ref } from 'vue'; |
| | | import { ref } from 'vue'; |
| | | import { MarkerOverlay } from './overlay/marker'; |
| | | import { TileGrid } from 'ol/tilegrid'; |
| | | import Style from 'ol/style/Style'; |
| | | import Fill from 'ol/style/Fill'; |
| | | import Stroke from 'ol/style/Stroke'; |
| | | import Circle from 'ol/style/Circle'; |
| | | |
| | | export type LangType = 'zh_cn' | 'en'; |
| | | export const enum GaoDeSourceType { |
| | | /** @description 默认地图 */ |
| | |
| | | export const MARKER_OVERLAY_CLASS_NAME = 'marker-overlay'; |
| | | |
| | | export const gaoDeSourceTypeMap = { |
| | | [GaoDeSourceType.Default]: '默认地图', |
| | | [GaoDeSourceType.Satellite]: '影像地图', |
| | | [GaoDeSourceType.Vector]: '矢量地图', |
| | | [GaoDeSourceType.SatelliteRoad]: '影像路网', |
| | | // [GaoDeSourceType.Default]: '默认地图', |
| | | [GaoDeSourceType.Vector]: '标准地图', |
| | | |
| | | [GaoDeSourceType.Satellite]: '卫星地图', |
| | | [GaoDeSourceType.SatelliteRoad]: '路网地图', |
| | | }; |
| | | |
| | | export const getGaoDeSourceUrl = (type: GaoDeSourceType, lang: LangType = 'zh_cn') => { |
| | |
| | | |
| | | view?: ViewOptions; |
| | | } & MapConfig; |
| | | |
| | | const resolutions = []; |
| | | for (let i = 0; i <= 8; ++i) { |
| | | resolutions.push(156543.03392804097 / Math.pow(2, i * 2)); |
| | | } |
| | | export class OLMap { |
| | | map: OpenLayerMap; |
| | | source: XYZ; |
| | | private eventMap: Map<OLEventType, Function[]>; |
| | | |
| | | activeSourceType: Ref<GaoDeSourceType> = ref(GaoDeSourceType.Vector); |
| | | markerIsVisible: Ref<boolean> = ref(true); |
| | | private emit(eventName: OLEventType, ...args: any[]) { |
| | |
| | | target: container, // 绑定 DOM 容器 |
| | | layers: [layer], // 添加图层 |
| | | view: new View(view), |
| | | interactions: olDefaults({ doubleClickZoom: false }), |
| | | }); |
| | | this.activeSourceType.value = sourceType; |
| | | this.markerIsVisible.value = markerIsVisible; |
| | | this.setSourceUrl(this.activeSourceType.value); |
| | | this.applySourceType(this.activeSourceType.value); |
| | | this.listenMapClick(); |
| | | this.addBasicControl(); |
| | | } |
| | | |
| | | setSourceUrl(type: GaoDeSourceType = GaoDeSourceType.Vector) { |
| | | applySourceType(type: GaoDeSourceType = GaoDeSourceType.Vector) { |
| | | const url = getGaoDeSourceUrl(type); |
| | | this.source.setUrl(url); |
| | | } |
| | | |
| | | setSourceType(type: GaoDeSourceType = GaoDeSourceType.Vector) { |
| | | this.activeSourceType.value = type; |
| | | this.applySourceType(type); |
| | | } |
| | | addMarkerLayer(dataList: any[], options: any) { |
| | | const { markerOpt } = options; |
| | |
| | | return overlay; |
| | | } |
| | | |
| | | adjustViewToMarkers() { |
| | | const overlays = this.map.getOverlays().getArray(); |
| | | |
| | | const filteredOverlays = overlays.filter((overlay) => { |
| | | const type = overlay.get('type'); |
| | | return type === OverlayType.Marker; |
| | | }); |
| | | this.adjustViewToOverlays(filteredOverlays); |
| | | } |
| | | |
| | | adjustViewToOverlays(overlays: Overlay[]) { |
| | | if (overlays.length === 0) return; |
| | | const extent = overlays.reduce<number[] | null>((ext, item) => { |
| | |
| | | setConfig(config: MapConfig) { |
| | | this.activeSourceType.value = config.sourceType; |
| | | this.markerIsVisible.value = config.markerIsVisible; |
| | | this.setSourceUrl(this.activeSourceType.value); |
| | | this.applySourceType(this.activeSourceType.value); |
| | | this.toggleMarkerOverlayVisible(this.markerIsVisible.value); |
| | | } |
| | | |
| | | private addBasicControl() { |
| | | this.map.addControl(new ZoomSlider()); |
| | | // this.map.addControl(new ZoomSlider()); |
| | | // this.map.addControl(new FullScreen()); |
| | | const container = this.map.getViewport(); |
| | | if (!container) return; |
| | | const olZoom = container.querySelector('.ol-zoom') as HTMLElement; |
| | | if (!olZoom) return; |
| | | olZoom.style.display = 'none'; |
| | | } |
| | | |
| | | /** |
| | | * 放大地图 |
| | | */ |
| | | zoomIn() { |
| | | const view = this.map.getView(); |
| | | const zoom = view.getZoom(); |
| | | view.setZoom(zoom + 1); |
| | | } |
| | | |
| | | /** |
| | | * 缩小地图 |
| | | */ |
| | | zoomOut() { |
| | | const view = this.map.getView(); |
| | | const zoom = view.getZoom(); |
| | | view.setZoom(zoom - 1); |
| | | } |
| | | |
| | | private tileUrlFunction(url) { |
| | | return (tileCoord) => |
| | | url |
| | | .replace('{z}', String(tileCoord[0] * 2 - 1)) |
| | | .replace('{x}', String(tileCoord[1])) |
| | | .replace('{y}', String(tileCoord[2])) |
| | | .replace('{a-d}', 'abcd'.substr(((tileCoord[1] << tileCoord[0]) + tileCoord[2]) % 4, 1)); |
| | | } |
| | | |
| | | addCustomLayer(url: string, style?: any) { |
| | | const vectorTileExtent = [13270414.528705932, 2994644.904997596, 13295641.139349712, 3018305.0256410106]; |
| | | |
| | | const vectorTileLayer = new VectorTileLayer({ |
| | | source: new VectorTileSource({ |
| | | format: new MVT(), |
| | | url: url, |
| | | }), |
| | | extent: vectorTileExtent, |
| | | style: style |
| | | }); |
| | | this.map.addLayer(vectorTileLayer); |
| | | return vectorTileLayer; |
| | | } |
| | | |
| | | getWMTS = () => { |