2025-04-28 15:04:06 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<div id="mapContainer" ref="mapContainer" style="width: 100%;height: 100%;" />
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
import 'ol/ol.css'
|
|
|
|
|
|
import Map from 'ol/Map'
|
|
|
|
|
|
import OSM from 'ol/source/OSM'
|
|
|
|
|
|
import XYZ from 'ol/source/XYZ'
|
|
|
|
|
|
import VectorSource from 'ol/source/Vector'
|
|
|
|
|
|
import Tile from 'ol/layer/Tile'
|
|
|
|
|
|
import VectorLayer from 'ol/layer/Vector'
|
2025-10-14 22:58:18 +08:00
|
|
|
|
import LayerGroup from 'ol/layer/Group'
|
2025-10-30 23:52:01 +08:00
|
|
|
|
import MVT from 'ol/format/MVT.js'
|
|
|
|
|
|
import VectorTileLayer from 'ol/layer/VectorTile.js'
|
|
|
|
|
|
import VectorTileSource from 'ol/source/VectorTile.js'
|
2025-10-20 09:32:45 +08:00
|
|
|
|
import WebGLVectorLayer from 'ol/layer/WebGLVector'
|
2025-04-28 15:04:06 +08:00
|
|
|
|
import Style from 'ol/style/Style'
|
|
|
|
|
|
import Stroke from 'ol/style/Stroke'
|
|
|
|
|
|
import Icon from 'ol/style/Icon'
|
|
|
|
|
|
import View from 'ol/View'
|
|
|
|
|
|
import Feature from 'ol/Feature'
|
|
|
|
|
|
import Overlay from 'ol/Overlay'
|
|
|
|
|
|
import { Point, LineString } from 'ol/geom'
|
2025-10-10 22:41:19 +08:00
|
|
|
|
import { get as getProj } from 'ol/proj'
|
2025-04-28 15:04:06 +08:00
|
|
|
|
import { containsCoordinate } from 'ol/extent'
|
2025-10-10 22:41:19 +08:00
|
|
|
|
import { defaults as defaultInteractions } from 'ol/interaction'
|
2025-10-14 15:57:24 +08:00
|
|
|
|
import Draw, { createBox } from 'ol/interaction/Draw'
|
2025-09-24 16:21:02 +08:00
|
|
|
|
import DragInteraction from './map/DragInteraction'
|
|
|
|
|
|
import { fromLonLat, toLonLat } from './map/TransformLonLat'
|
2025-04-28 15:04:06 +08:00
|
|
|
|
|
|
|
|
|
|
import { v4 } from 'uuid'
|
2025-09-24 16:21:02 +08:00
|
|
|
|
import { getUid } from 'ol'
|
2025-10-10 22:41:19 +08:00
|
|
|
|
import {Fill} from "ol/style";
|
2025-04-28 15:04:06 +08:00
|
|
|
|
|
2025-09-25 18:06:58 +08:00
|
|
|
|
let olMap, tileLayer = null
|
2025-04-28 15:04:06 +08:00
|
|
|
|
export default {
|
|
|
|
|
|
name: 'MapComponent',
|
|
|
|
|
|
props: [],
|
|
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
2025-09-24 16:21:02 +08:00
|
|
|
|
overlayId: null,
|
2025-09-25 15:27:30 +08:00
|
|
|
|
dragInteraction: new DragInteraction(),
|
|
|
|
|
|
mapTileList: [],
|
|
|
|
|
|
mapTileIndex: 0
|
2025-04-28 15:04:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
created() {
|
|
|
|
|
|
this.$nextTick(() => {
|
2025-09-25 15:27:30 +08:00
|
|
|
|
this.init()
|
2025-04-28 15:04:06 +08:00
|
|
|
|
})
|
2025-09-25 15:27:30 +08:00
|
|
|
|
|
2025-04-28 15:04:06 +08:00
|
|
|
|
},
|
|
|
|
|
|
mounted() {
|
|
|
|
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
destroyed() {
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
|
|
|
|
|
init() {
|
2025-09-25 15:27:30 +08:00
|
|
|
|
this.$store.dispatch('server/getMapConfig')
|
|
|
|
|
|
.then(mapConfigList => {
|
|
|
|
|
|
if (mapConfigList.length === 0) {
|
|
|
|
|
|
if (window.mapParam.tilesUrl) {
|
|
|
|
|
|
this.mapTileList.push({
|
|
|
|
|
|
tilesUrl: window.mapParam.tilesUrl,
|
|
|
|
|
|
coordinateSystem: window.mapParam.coordinateSystem
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}else {
|
|
|
|
|
|
this.mapTileList = mapConfigList
|
|
|
|
|
|
}
|
|
|
|
|
|
this.initMap()
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
initMap(){
|
2025-04-28 15:04:06 +08:00
|
|
|
|
let center = fromLonLat([116.41020, 39.915119])
|
2025-09-25 18:06:58 +08:00
|
|
|
|
window.coordinateSystem = this.mapTileList[this.mapTileIndex].coordinateSystem
|
2025-09-24 16:21:02 +08:00
|
|
|
|
if (window.mapParam.center) {
|
|
|
|
|
|
center = fromLonLat(window.mapParam.center)
|
2025-04-28 15:04:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
const view = new View({
|
|
|
|
|
|
center: center,
|
2025-09-24 16:21:02 +08:00
|
|
|
|
zoom: window.mapParam.zoom || 10,
|
2025-04-28 15:04:06 +08:00
|
|
|
|
projection: this.projection,
|
2025-09-24 16:21:02 +08:00
|
|
|
|
maxZoom: window.mapParam.maxZoom || 19,
|
|
|
|
|
|
minZoom: window.mapParam.minZoom || 1
|
2025-04-28 15:04:06 +08:00
|
|
|
|
})
|
2025-09-25 18:06:58 +08:00
|
|
|
|
|
2025-09-25 15:27:30 +08:00
|
|
|
|
if (this.mapTileList.length > 0 && this.mapTileList[this.mapTileIndex].tilesUrl) {
|
2025-04-28 15:04:06 +08:00
|
|
|
|
tileLayer = new Tile({
|
|
|
|
|
|
source: new XYZ({
|
|
|
|
|
|
projection: getProj('EPSG:3857'),
|
|
|
|
|
|
wrapX: false,
|
2025-09-24 16:21:02 +08:00
|
|
|
|
tileSize: 256 || window.mapParam.tileSize,
|
2025-09-25 15:27:30 +08:00
|
|
|
|
url: this.mapTileList[this.mapTileIndex].tilesUrl
|
2025-04-28 15:04:06 +08:00
|
|
|
|
})
|
|
|
|
|
|
})
|
2025-10-30 23:52:01 +08:00
|
|
|
|
console.log(4444)
|
|
|
|
|
|
console.log(this.mapTileList[this.mapTileIndex].tilesUrl)
|
2025-04-28 15:04:06 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
tileLayer = new Tile({
|
|
|
|
|
|
preload: 4,
|
|
|
|
|
|
source: new OSM()
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
olMap = new Map({
|
2025-09-24 16:21:02 +08:00
|
|
|
|
interactions: defaultInteractions().extend([this.dragInteraction]),
|
2025-04-28 15:04:06 +08:00
|
|
|
|
target: this.$refs.mapContainer, // 容器ID
|
|
|
|
|
|
layers: [tileLayer], // 默认图层
|
|
|
|
|
|
view: view, // 视图
|
|
|
|
|
|
controls: [ // 控件
|
|
|
|
|
|
]
|
|
|
|
|
|
})
|
2025-10-13 22:18:17 +08:00
|
|
|
|
// olMap.addControl(new ZoomSlider({
|
|
|
|
|
|
// className: 'zoom-slider'
|
|
|
|
|
|
// }))
|
2025-09-24 16:21:02 +08:00
|
|
|
|
olMap.once('loadend', event => {
|
|
|
|
|
|
this.$emit('loaded')
|
|
|
|
|
|
})
|
|
|
|
|
|
olMap.on('click', event => {
|
|
|
|
|
|
let features = {}
|
|
|
|
|
|
let layers = {}
|
|
|
|
|
|
// 单个元素事件传递
|
|
|
|
|
|
olMap.forEachFeatureAtPixel(event.pixel, (featureAtPixel, layerAtPixel) => {
|
|
|
|
|
|
|
|
|
|
|
|
if (layerAtPixel) {
|
|
|
|
|
|
let ol_uid = 'key' + getUid(layerAtPixel)
|
|
|
|
|
|
layers[ol_uid] = layerAtPixel
|
|
|
|
|
|
if (Object.hasOwn(features, ol_uid)) {
|
|
|
|
|
|
features[ol_uid].push(featureAtPixel)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
features[ol_uid] = new Array(featureAtPixel)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
// 遍历图层,传递事件
|
|
|
|
|
|
for (const key in layers) {
|
|
|
|
|
|
if (Object.hasOwn(layers, key)) {
|
|
|
|
|
|
var layer = layers[key]
|
|
|
|
|
|
layer.dispatchEvent({ type: 'click', event: event, features: features[key], outParam: { layersCount: Object.keys(layers).length } });
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
features = {}
|
|
|
|
|
|
layer = {}
|
|
|
|
|
|
})
|
2025-10-13 22:18:17 +08:00
|
|
|
|
olMap.getView().on('change:resolution', () => {
|
|
|
|
|
|
this.$emit('zoomChange', olMap.getView().getZoom())
|
2025-10-13 15:35:12 +08:00
|
|
|
|
})
|
2025-04-28 15:04:06 +08:00
|
|
|
|
},
|
2025-10-30 23:52:01 +08:00
|
|
|
|
addVectorTileLayer(tileUrl){
|
|
|
|
|
|
let source = new VectorTileSource({
|
|
|
|
|
|
|
|
|
|
|
|
format: new MVT(),
|
|
|
|
|
|
url: tileUrl
|
|
|
|
|
|
})
|
|
|
|
|
|
let layer = new VectorTileLayer({
|
|
|
|
|
|
source: source,
|
|
|
|
|
|
style: {
|
|
|
|
|
|
// 必须提供 style 配置,可以是对象或函数
|
|
|
|
|
|
'circle-radius': 4,
|
|
|
|
|
|
'circle-fill-color': 'red',
|
|
|
|
|
|
'circle-stroke-color': 'white',
|
|
|
|
|
|
'circle-stroke-width': 0.5
|
|
|
|
|
|
// 'icon-src': 'static/images/gis/sprite.png',
|
|
|
|
|
|
// 'icon-width': 120,
|
|
|
|
|
|
// 'icon-height': 40,
|
|
|
|
|
|
// 'icon-size': [40, 40],
|
|
|
|
|
|
// 'icon-anchor': [0.5, 1],
|
|
|
|
|
|
// 'icon-offset-origin': 'bottom-left',
|
|
|
|
|
|
// 'icon-offset': [
|
|
|
|
|
|
// 'match',
|
|
|
|
|
|
// ['get', 'status'],
|
|
|
|
|
|
// 'ON',
|
|
|
|
|
|
// [0, 0],
|
|
|
|
|
|
// 'OFF',
|
|
|
|
|
|
// [40, 0],
|
|
|
|
|
|
// 'checked',
|
|
|
|
|
|
// [80, 0],
|
|
|
|
|
|
// [120, 60]
|
|
|
|
|
|
// ]
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
olMap.addLayer(layer)
|
|
|
|
|
|
layer.on('click', (event) => {
|
|
|
|
|
|
console.log(event)
|
|
|
|
|
|
if (event.features.length > 0) {
|
|
|
|
|
|
const items = []
|
|
|
|
|
|
for (let i = 0; i < event.features.length; i++) {
|
|
|
|
|
|
items.push(event.features[i].customData)
|
|
|
|
|
|
}
|
|
|
|
|
|
console.log(items)
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
2025-04-28 15:04:06 +08:00
|
|
|
|
setCenter(point) {
|
|
|
|
|
|
|
2025-09-24 16:21:02 +08:00
|
|
|
|
},
|
|
|
|
|
|
getCenter() {
|
|
|
|
|
|
return toLonLat(olMap.getView().getCenter())
|
2025-04-28 15:04:06 +08:00
|
|
|
|
},
|
2025-10-13 22:18:17 +08:00
|
|
|
|
getZoom() {
|
|
|
|
|
|
return olMap.getView().getZoom()
|
|
|
|
|
|
},
|
2025-10-15 15:57:25 +08:00
|
|
|
|
zoomIn() {
|
|
|
|
|
|
let zoom = olMap.getView().getZoom()
|
|
|
|
|
|
if (zoom >= olMap.getView().getMaxZoom()) {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
olMap.getView().animate({
|
|
|
|
|
|
zoom: Math.trunc(zoom) + 1,
|
|
|
|
|
|
duration: 600
|
|
|
|
|
|
})
|
2025-04-28 15:04:06 +08:00
|
|
|
|
},
|
2025-10-15 15:57:25 +08:00
|
|
|
|
zoomOut() {
|
|
|
|
|
|
let zoom = olMap.getView().getZoom()
|
|
|
|
|
|
if (zoom <= olMap.getView().getMinZoom()) {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
olMap.getView().animate({
|
|
|
|
|
|
zoom: Math.trunc(zoom) - 1,
|
|
|
|
|
|
duration: 400
|
|
|
|
|
|
})
|
2025-04-28 15:04:06 +08:00
|
|
|
|
},
|
|
|
|
|
|
centerAndZoom(point, zoom, callback) {
|
|
|
|
|
|
var zoom_ = olMap.getView().getZoom()
|
|
|
|
|
|
zoom = zoom || zoom_
|
|
|
|
|
|
var duration = 600
|
|
|
|
|
|
olMap.getView().setCenter(fromLonLat(point))
|
|
|
|
|
|
olMap.getView().animate({
|
|
|
|
|
|
zoom: zoom,
|
|
|
|
|
|
duration: duration
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
2025-09-24 16:21:02 +08:00
|
|
|
|
coordinateInView: function(point) {
|
|
|
|
|
|
return containsCoordinate(olMap.getView().calculateExtent(), fromLonLat(point))
|
|
|
|
|
|
},
|
|
|
|
|
|
panTo(point, zoom, endCallback) {
|
|
|
|
|
|
const duration = 1500
|
|
|
|
|
|
var coordinate = fromLonLat(point)
|
|
|
|
|
|
if (containsCoordinate(olMap.getView().calculateExtent(), coordinate)) {
|
|
|
|
|
|
olMap.getView().setCenter(coordinate)
|
2025-10-15 15:57:25 +08:00
|
|
|
|
if (zoom !== olMap.getView().getZoom()) {
|
|
|
|
|
|
olMap.getView().setZoom(zoom)
|
|
|
|
|
|
}
|
2025-09-24 16:21:02 +08:00
|
|
|
|
if (endCallback) {
|
|
|
|
|
|
endCallback()
|
|
|
|
|
|
}
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2025-04-28 15:04:06 +08:00
|
|
|
|
|
|
|
|
|
|
olMap.getView().cancelAnimations()
|
|
|
|
|
|
olMap.getView().animate({
|
2025-09-24 16:21:02 +08:00
|
|
|
|
center: coordinate,
|
2025-04-28 15:04:06 +08:00
|
|
|
|
duration: duration
|
|
|
|
|
|
})
|
2025-09-24 16:21:02 +08:00
|
|
|
|
olMap.getView().animate({
|
2025-10-15 15:57:25 +08:00
|
|
|
|
zoom: zoom -2,
|
2025-09-24 16:21:02 +08:00
|
|
|
|
duration: duration / 2
|
|
|
|
|
|
}, {
|
|
|
|
|
|
zoom: zoom || olMap.getView().getZoom(),
|
|
|
|
|
|
duration: duration / 2
|
|
|
|
|
|
})
|
|
|
|
|
|
setTimeout(endCallback, duration + 100)
|
2025-04-28 15:04:06 +08:00
|
|
|
|
},
|
|
|
|
|
|
fit(layer) {
|
|
|
|
|
|
const extent = layer.getSource().getExtent()
|
|
|
|
|
|
if (extent) {
|
|
|
|
|
|
olMap.getView().fit(extent, {
|
|
|
|
|
|
duration: 600,
|
|
|
|
|
|
padding: [100, 100, 100, 100]
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
openInfoBox(position, content, offset) {
|
2025-09-24 16:21:02 +08:00
|
|
|
|
if (this.overlayId !== null) {
|
|
|
|
|
|
this.closeInfoBox(this.overlayId)
|
|
|
|
|
|
this.overlayId = null
|
|
|
|
|
|
}
|
2025-04-28 15:04:06 +08:00
|
|
|
|
const id = v4()
|
2025-09-24 16:21:02 +08:00
|
|
|
|
// let infoBox = document.createElement('div')
|
|
|
|
|
|
// infoBox.setAttribute('id', id)
|
|
|
|
|
|
// infoBox.innerHTML = content
|
2025-04-28 15:04:06 +08:00
|
|
|
|
const overlay = new Overlay({
|
|
|
|
|
|
id: id,
|
|
|
|
|
|
autoPan: true,
|
|
|
|
|
|
autoPanAnimation: {
|
|
|
|
|
|
duration: 250
|
|
|
|
|
|
},
|
|
|
|
|
|
element: content,
|
|
|
|
|
|
positioning: 'bottom-center',
|
2025-09-24 16:21:02 +08:00
|
|
|
|
offset: offset,
|
|
|
|
|
|
position: fromLonLat(position)
|
2025-04-28 15:04:06 +08:00
|
|
|
|
// className:overlayStyle.className
|
|
|
|
|
|
})
|
|
|
|
|
|
olMap.addOverlay(overlay)
|
2025-09-24 16:21:02 +08:00
|
|
|
|
this.overlayId = id
|
2025-04-28 15:04:06 +08:00
|
|
|
|
return id
|
|
|
|
|
|
},
|
|
|
|
|
|
closeInfoBox(id) {
|
2025-09-24 16:21:02 +08:00
|
|
|
|
let overlay = olMap.getOverlayById(id)
|
|
|
|
|
|
if (overlay) {
|
|
|
|
|
|
olMap.removeOverlay(overlay)
|
|
|
|
|
|
}
|
2025-10-27 19:02:57 +08:00
|
|
|
|
let element = document.getElementById(id)
|
2025-09-24 16:21:02 +08:00
|
|
|
|
if (element) {
|
|
|
|
|
|
element.remove()
|
|
|
|
|
|
}
|
2025-04-28 15:04:06 +08:00
|
|
|
|
},
|
|
|
|
|
|
/**
|
2025-10-12 23:41:30 +08:00
|
|
|
|
* 添加图层, 数据坐标系由控件内完成,输入和输出永远是wgs84
|
|
|
|
|
|
* [
|
|
|
|
|
|
* {
|
|
|
|
|
|
*
|
|
|
|
|
|
* position: [119.1212,45,122],
|
|
|
|
|
|
* image: {
|
|
|
|
|
|
* src:"/images/123.png",
|
|
|
|
|
|
* anchor: [0.5, 0.5]
|
|
|
|
|
|
*
|
|
|
|
|
|
* }
|
|
|
|
|
|
* }
|
|
|
|
|
|
*
|
|
|
|
|
|
* ]
|
|
|
|
|
|
* @param data
|
|
|
|
|
|
* @param clickEvent
|
2025-10-13 22:18:17 +08:00
|
|
|
|
* @param option
|
2025-10-12 23:41:30 +08:00
|
|
|
|
*/
|
2025-10-13 15:35:12 +08:00
|
|
|
|
addPointLayer(data, clickEvent, option) {
|
2025-10-27 19:02:57 +08:00
|
|
|
|
let vectorLayer = this.createPointLayer(data, clickEvent, option)
|
|
|
|
|
|
olMap.addLayer(vectorLayer)
|
|
|
|
|
|
return vectorLayer
|
2025-10-14 22:58:18 +08:00
|
|
|
|
},
|
|
|
|
|
|
createPointLayer(data, clickEvent, option){
|
2025-10-30 23:52:01 +08:00
|
|
|
|
console.log(444)
|
|
|
|
|
|
console.log(data)
|
2025-10-27 19:02:57 +08:00
|
|
|
|
const features = []
|
|
|
|
|
|
let maxZoom = (option && option.maxZoom) ? option.maxZoom : olMap.getView().getMaxZoom()
|
|
|
|
|
|
let minZoom = (option && option.minZoom) ? option.minZoom : olMap.getView().getMinZoom()
|
|
|
|
|
|
let declutter = option && option.declutter
|
2025-10-18 20:19:46 +08:00
|
|
|
|
if (data.length > 0) {
|
|
|
|
|
|
for (let i = 0; i < data.length; i++) {
|
|
|
|
|
|
const feature = new Feature(new Point(fromLonLat(data[i].position)))
|
|
|
|
|
|
feature.setId(data[i].id)
|
|
|
|
|
|
feature.customData = data[i].data
|
2025-10-20 22:16:03 +08:00
|
|
|
|
feature.setProperties({
|
2025-10-27 19:02:57 +08:00
|
|
|
|
status: data[i].status
|
2025-10-20 22:16:03 +08:00
|
|
|
|
})
|
2025-10-18 20:19:46 +08:00
|
|
|
|
features.push(feature)
|
|
|
|
|
|
}
|
2025-10-27 19:02:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
const source = new VectorSource()
|
|
|
|
|
|
if (features.length > 0) {
|
2025-10-18 20:19:46 +08:00
|
|
|
|
source.addFeatures(features)
|
2025-10-27 19:02:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
const vectorLayer = new WebGLVectorLayer({
|
|
|
|
|
|
source: source,
|
|
|
|
|
|
maxZoom: maxZoom,
|
|
|
|
|
|
minZoom: minZoom,
|
|
|
|
|
|
style: {
|
|
|
|
|
|
// 必须提供 style 配置,可以是对象或函数
|
|
|
|
|
|
// 'circle-radius': 10,
|
|
|
|
|
|
// 'circle-fill-color': 'red',
|
|
|
|
|
|
// 'circle-stroke-color': 'white',
|
|
|
|
|
|
// 'circle-stroke-width': 0.5
|
|
|
|
|
|
'icon-src': 'static/images/gis/sprite.png',
|
|
|
|
|
|
'icon-width': 120,
|
|
|
|
|
|
'icon-height': 40,
|
|
|
|
|
|
'icon-size': [40, 40],
|
|
|
|
|
|
'icon-anchor': [0.5, 1],
|
|
|
|
|
|
'icon-offset-origin': 'bottom-left',
|
|
|
|
|
|
'icon-offset': [
|
|
|
|
|
|
'match',
|
|
|
|
|
|
['get', 'status'],
|
|
|
|
|
|
'ON',
|
|
|
|
|
|
[0, 0],
|
|
|
|
|
|
'OFF',
|
|
|
|
|
|
[40, 0],
|
|
|
|
|
|
'checked',
|
|
|
|
|
|
[80, 0],
|
|
|
|
|
|
[120, 60]
|
|
|
|
|
|
]
|
2025-10-18 20:19:46 +08:00
|
|
|
|
}
|
2025-10-27 19:02:57 +08:00
|
|
|
|
})
|
|
|
|
|
|
if (clickEvent && typeof clickEvent === 'function') {
|
|
|
|
|
|
vectorLayer.on('click', (event) => {
|
2025-10-30 23:52:01 +08:00
|
|
|
|
console.log(event)
|
2025-10-27 19:02:57 +08:00
|
|
|
|
if (event.features.length > 0) {
|
|
|
|
|
|
const items = []
|
|
|
|
|
|
for (let i = 0; i < event.features.length; i++) {
|
|
|
|
|
|
items.push(event.features[i].customData)
|
|
|
|
|
|
}
|
|
|
|
|
|
clickEvent(items)
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
2025-10-18 20:19:46 +08:00
|
|
|
|
}
|
2025-10-27 19:02:57 +08:00
|
|
|
|
return vectorLayer
|
|
|
|
|
|
|
2025-10-18 20:19:46 +08:00
|
|
|
|
},
|
|
|
|
|
|
createPointLayer2(data, clickEvent, option){
|
2025-04-28 15:04:06 +08:00
|
|
|
|
if (data.length > 0) {
|
|
|
|
|
|
const features = []
|
2025-10-14 15:57:24 +08:00
|
|
|
|
let maxZoom = (option && option.maxZoom) ? option.maxZoom : olMap.getView().getMaxZoom()
|
|
|
|
|
|
let minZoom = (option && option.minZoom) ? option.minZoom : olMap.getView().getMinZoom()
|
2025-10-14 22:58:18 +08:00
|
|
|
|
let declutter = option && option.declutter
|
2025-10-13 22:18:17 +08:00
|
|
|
|
|
2025-04-28 15:04:06 +08:00
|
|
|
|
for (let i = 0; i < data.length; i++) {
|
|
|
|
|
|
const feature = new Feature(new Point(fromLonLat(data[i].position)))
|
2025-09-24 16:21:02 +08:00
|
|
|
|
feature.setId(data[i].id)
|
2025-04-28 15:04:06 +08:00
|
|
|
|
feature.customData = data[i].data
|
2025-10-10 22:41:19 +08:00
|
|
|
|
const style = new Style()
|
|
|
|
|
|
style.setImage(new Icon({
|
2025-04-28 15:04:06 +08:00
|
|
|
|
anchor: data[i].image.anchor,
|
|
|
|
|
|
crossOrigin: 'Anonymous',
|
2025-10-10 22:41:19 +08:00
|
|
|
|
src: data[i].image.src,
|
|
|
|
|
|
opacity: 1
|
2025-04-28 15:04:06 +08:00
|
|
|
|
}))
|
2025-10-10 22:41:19 +08:00
|
|
|
|
feature.setStyle(style)
|
2025-04-28 15:04:06 +08:00
|
|
|
|
features.push(feature)
|
|
|
|
|
|
}
|
|
|
|
|
|
const source = new VectorSource()
|
|
|
|
|
|
source.addFeatures(features)
|
|
|
|
|
|
const vectorLayer = new VectorLayer({
|
|
|
|
|
|
source: source,
|
|
|
|
|
|
renderMode: 'image',
|
2025-10-14 22:58:18 +08:00
|
|
|
|
declutter: declutter,
|
2025-10-13 15:35:12 +08:00
|
|
|
|
maxZoom: maxZoom,
|
|
|
|
|
|
minZoom: minZoom
|
2025-04-28 15:04:06 +08:00
|
|
|
|
})
|
2025-10-14 22:58:18 +08:00
|
|
|
|
if (clickEvent && typeof clickEvent === 'function') {
|
2025-09-24 16:21:02 +08:00
|
|
|
|
vectorLayer.on('click', (event) => {
|
|
|
|
|
|
|
|
|
|
|
|
if (event.features.length > 0) {
|
|
|
|
|
|
const items = []
|
|
|
|
|
|
for (let i = 0; i < event.features.length; i++) {
|
|
|
|
|
|
items.push(event.features[i].customData)
|
2025-04-28 15:04:06 +08:00
|
|
|
|
}
|
2025-09-24 16:21:02 +08:00
|
|
|
|
clickEvent(items)
|
|
|
|
|
|
}
|
2025-04-28 15:04:06 +08:00
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return vectorLayer
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-10-27 19:02:57 +08:00
|
|
|
|
hasFeature (layer, id) {
|
|
|
|
|
|
if (layer instanceof LayerGroup) {
|
|
|
|
|
|
// 目前LayerGroup的情况肯定含有这个
|
|
|
|
|
|
return true
|
|
|
|
|
|
}else {
|
|
|
|
|
|
if (layer.getSource().getFeatureById(id)) {
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return false
|
|
|
|
|
|
},
|
|
|
|
|
|
addFeature (layer, data) {
|
|
|
|
|
|
|
|
|
|
|
|
const feature = new Feature(new Point(fromLonLat(data.position)))
|
|
|
|
|
|
feature.setId(data.id)
|
|
|
|
|
|
feature.customData = data.data
|
|
|
|
|
|
feature.setProperties({
|
|
|
|
|
|
status: data.status
|
|
|
|
|
|
})
|
|
|
|
|
|
layer.getSource().addFeature(feature)
|
|
|
|
|
|
},
|
2025-10-12 23:41:30 +08:00
|
|
|
|
updatePointLayer(layer, data, postponement) {
|
2025-10-30 23:52:01 +08:00
|
|
|
|
console.log(data)
|
2025-09-24 16:21:02 +08:00
|
|
|
|
layer.getSource().clear(true)
|
2025-10-27 19:02:57 +08:00
|
|
|
|
if (!data || data.length == 0) {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2025-09-24 16:21:02 +08:00
|
|
|
|
const features = []
|
|
|
|
|
|
for (let i = 0; i < data.length; i++) {
|
|
|
|
|
|
const feature = new Feature(new Point(fromLonLat(data[i].position)))
|
|
|
|
|
|
feature.setId(data[i].id)
|
|
|
|
|
|
feature.customData = data[i].data
|
2025-10-30 23:52:01 +08:00
|
|
|
|
feature.setProperties({
|
|
|
|
|
|
status: data[i].status
|
|
|
|
|
|
})
|
2025-09-24 16:21:02 +08:00
|
|
|
|
features.push(feature)
|
|
|
|
|
|
}
|
|
|
|
|
|
layer.getSource().addFeatures(features)
|
|
|
|
|
|
if (postponement) {
|
|
|
|
|
|
olMap.removeLayer(layer)
|
|
|
|
|
|
setTimeout(() => {
|
2025-10-13 15:35:12 +08:00
|
|
|
|
olMap.addLayer(layer)
|
2025-09-24 16:21:02 +08:00
|
|
|
|
}, 100)
|
|
|
|
|
|
}
|
|
|
|
|
|
return layer
|
|
|
|
|
|
},
|
2025-10-14 22:58:18 +08:00
|
|
|
|
addPointLayerGroup(data, clickEvent) {
|
2025-10-14 15:57:24 +08:00
|
|
|
|
|
2025-10-14 22:58:18 +08:00
|
|
|
|
let keys = Array.from(data.keys())
|
|
|
|
|
|
|
|
|
|
|
|
let layers = []
|
|
|
|
|
|
for (let i = 0; i < keys.length; i++) {
|
|
|
|
|
|
let zoom = keys[i]
|
|
|
|
|
|
console.log(zoom)
|
|
|
|
|
|
let vectorLayer = this.createPointLayer(data.get(zoom), clickEvent, {
|
|
|
|
|
|
minZoom : zoom
|
|
|
|
|
|
})
|
2025-10-27 19:02:57 +08:00
|
|
|
|
vectorLayer.setProperties('layerId', zoom)
|
2025-10-14 22:58:18 +08:00
|
|
|
|
if (vectorLayer) {
|
|
|
|
|
|
layers.push(vectorLayer)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
let groupLayer = new LayerGroup({
|
|
|
|
|
|
layers: layers
|
|
|
|
|
|
})
|
|
|
|
|
|
olMap.addLayer(groupLayer)
|
|
|
|
|
|
return groupLayer
|
2025-10-14 15:57:24 +08:00
|
|
|
|
},
|
|
|
|
|
|
updatePointLayerGroup(layer, data, postponement) {
|
|
|
|
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-04-28 15:04:06 +08:00
|
|
|
|
removeLayer(layer) {
|
|
|
|
|
|
olMap.removeLayer(layer)
|
|
|
|
|
|
},
|
2025-10-27 19:02:57 +08:00
|
|
|
|
clearLayer(layer) {
|
|
|
|
|
|
layer.getSource().clear(true)
|
|
|
|
|
|
},
|
2025-09-24 16:21:02 +08:00
|
|
|
|
setFeatureImageById(layer, featureId, image) {
|
|
|
|
|
|
let feature = layer.getSource().getFeatureById(featureId)
|
|
|
|
|
|
if (!feature) {
|
|
|
|
|
|
console.error('更改feature的图标时未找到图标')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
let style = feature.getStyle()
|
|
|
|
|
|
style.setImage(new Icon({
|
|
|
|
|
|
anchor: image.anchor,
|
|
|
|
|
|
crossOrigin: 'Anonymous',
|
|
|
|
|
|
src: image.src
|
|
|
|
|
|
}))
|
|
|
|
|
|
feature.setStyle(style)
|
|
|
|
|
|
olMap.render()
|
|
|
|
|
|
},
|
|
|
|
|
|
setFeaturePositionById(layer, featureId, data) {
|
2025-10-27 19:02:57 +08:00
|
|
|
|
if (layer instanceof LayerGroup) {
|
|
|
|
|
|
|
|
|
|
|
|
}else {
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2025-09-24 16:21:02 +08:00
|
|
|
|
let featureOld = layer.getSource().getFeatureById(featureId)
|
|
|
|
|
|
if (featureOld) {
|
|
|
|
|
|
layer.getSource().removeFeature(featureOld)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const feature = new Feature(new Point(fromLonLat(data.position)))
|
|
|
|
|
|
feature.setId(data.id)
|
|
|
|
|
|
feature.customData = data.data
|
2025-10-23 22:49:18 +08:00
|
|
|
|
feature.setProperties({
|
|
|
|
|
|
status: data.status
|
|
|
|
|
|
})
|
2025-09-24 16:21:02 +08:00
|
|
|
|
layer.getSource().addFeature(feature)
|
|
|
|
|
|
},
|
2025-04-28 15:04:06 +08:00
|
|
|
|
|
|
|
|
|
|
addLineLayer(positions) {
|
|
|
|
|
|
if (positions.length > 0) {
|
|
|
|
|
|
const points = []
|
|
|
|
|
|
for (let i = 0; i < positions.length; i++) {
|
|
|
|
|
|
points.push(fromLonLat(positions[i]))
|
|
|
|
|
|
}
|
|
|
|
|
|
const line = new LineString(points)
|
|
|
|
|
|
const lineFeature = new Feature(line)
|
|
|
|
|
|
lineFeature.setStyle(new Style({
|
|
|
|
|
|
stroke: new Stroke({
|
|
|
|
|
|
width: 4,
|
|
|
|
|
|
color: '#0c6d6a'
|
|
|
|
|
|
})
|
|
|
|
|
|
}))
|
|
|
|
|
|
const source = new VectorSource()
|
|
|
|
|
|
source.addFeature(lineFeature)
|
|
|
|
|
|
const vectorLayer = new VectorLayer({
|
|
|
|
|
|
source: source
|
|
|
|
|
|
})
|
2025-10-13 15:35:12 +08:00
|
|
|
|
olMap.addLayer(vectorLayer)
|
2025-04-28 15:04:06 +08:00
|
|
|
|
return vectorLayer
|
|
|
|
|
|
}
|
2025-09-25 15:27:30 +08:00
|
|
|
|
},
|
|
|
|
|
|
getCurrentCoordinateSystem() {
|
|
|
|
|
|
return this.mapTileList[this.mapTileIndex].coordinateSystem
|
2025-09-25 18:06:58 +08:00
|
|
|
|
},
|
|
|
|
|
|
changeMapTile(index) {
|
|
|
|
|
|
let center = this.getCenter()
|
|
|
|
|
|
let mapTileConfig = this.mapTileList[this.mapTileIndex]
|
|
|
|
|
|
this.mapTileIndex = index
|
|
|
|
|
|
window.coordinateSystem = this.mapTileList[this.mapTileIndex].coordinateSystem
|
|
|
|
|
|
tileLayer.getSource().setUrl(this.mapTileList[index].tilesUrl)
|
|
|
|
|
|
if (mapTileConfig.coordinateSystem !== this.mapTileList[this.mapTileIndex].coordinateSystem) {
|
|
|
|
|
|
// 发送通知
|
|
|
|
|
|
this.$emit('coordinateSystemChange', this.mapTileList[this.mapTileIndex].coordinateSystem)
|
|
|
|
|
|
// 修正地图的中心点
|
|
|
|
|
|
olMap.getView().setCenter(fromLonLat(center))
|
|
|
|
|
|
}
|
2025-10-12 23:41:30 +08:00
|
|
|
|
},
|
2025-10-13 15:35:12 +08:00
|
|
|
|
getZoomExtent(){
|
|
|
|
|
|
return [olMap.getView().getMinZoom(), olMap.getView().getMaxZoom()]
|
|
|
|
|
|
},
|
2025-10-12 23:41:30 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 根据距离计算经纬度差值,方便前端抽稀计算
|
|
|
|
|
|
* @param distance 距离, 单位:像素值
|
|
|
|
|
|
* @param zoom 地图层级,默认取值当前层级
|
|
|
|
|
|
*/
|
|
|
|
|
|
computeDiff(distance, zoom) {
|
|
|
|
|
|
if (!distance) {
|
|
|
|
|
|
return []
|
|
|
|
|
|
}
|
2025-10-13 15:35:12 +08:00
|
|
|
|
let resolution
|
2025-10-12 23:41:30 +08:00
|
|
|
|
if (!zoom) {
|
|
|
|
|
|
resolution = olMap.getView().getResolution()
|
|
|
|
|
|
}else {
|
|
|
|
|
|
resolution = olMap.getView().getResolutionForZoom(zoom)
|
|
|
|
|
|
}
|
|
|
|
|
|
let diff = resolution * distance
|
2025-10-13 15:35:12 +08:00
|
|
|
|
return toLonLat([diff, diff])[0]
|
|
|
|
|
|
|
2025-10-12 23:41:30 +08:00
|
|
|
|
|
2025-10-13 15:35:12 +08:00
|
|
|
|
// let extent = olMap.getView().calculateExtent(olMap.getSize())
|
|
|
|
|
|
//
|
|
|
|
|
|
//
|
|
|
|
|
|
// let minLng = extent[0]
|
|
|
|
|
|
// let maxLng = extent[2]
|
|
|
|
|
|
// let minLat = extent[1]
|
|
|
|
|
|
// let maxLat = extent[3]
|
|
|
|
|
|
//
|
|
|
|
|
|
// let style = new Style({
|
|
|
|
|
|
// stroke: new Stroke({
|
|
|
|
|
|
// width: 1,
|
|
|
|
|
|
// color: 'rgba(65,65,65,0.8)'
|
|
|
|
|
|
// })
|
|
|
|
|
|
// })
|
|
|
|
|
|
// const source = new VectorSource()
|
|
|
|
|
|
// let lng = minLng
|
|
|
|
|
|
// while (lng <= maxLng) {
|
|
|
|
|
|
//
|
|
|
|
|
|
// const points = [[lng, minLat], [lng, maxLat]]
|
|
|
|
|
|
// const line = new LineString(points)
|
|
|
|
|
|
// const lineFeature = new Feature(line)
|
|
|
|
|
|
// lineFeature.setStyle(style)
|
|
|
|
|
|
// source.addFeature(lineFeature)
|
|
|
|
|
|
// lng += diff
|
|
|
|
|
|
// }
|
|
|
|
|
|
//
|
|
|
|
|
|
// let lat = minLat
|
|
|
|
|
|
// while (lat <= maxLat) {
|
|
|
|
|
|
//
|
|
|
|
|
|
// const points = [[minLng, lat], [maxLng, lat]]
|
|
|
|
|
|
// console.log(points)
|
|
|
|
|
|
// const line = new LineString(points)
|
|
|
|
|
|
// const lineFeature = new Feature(line)
|
|
|
|
|
|
// lineFeature.setStyle(style)
|
|
|
|
|
|
// source.addFeature(lineFeature)
|
|
|
|
|
|
// lat += diff
|
|
|
|
|
|
// }
|
|
|
|
|
|
//
|
|
|
|
|
|
// const vectorLayer = new VectorLayer({
|
|
|
|
|
|
// source: source
|
|
|
|
|
|
// })
|
|
|
|
|
|
// olMap.addLayer(vectorLayer)
|
2025-10-14 15:57:24 +08:00
|
|
|
|
},
|
|
|
|
|
|
startDrawBox(callback) {
|
|
|
|
|
|
|
|
|
|
|
|
const source = new VectorSource({ wrapX: false })
|
|
|
|
|
|
|
|
|
|
|
|
const vectorLayer = new VectorLayer({
|
|
|
|
|
|
source: source,
|
|
|
|
|
|
style: new Style({
|
|
|
|
|
|
fill: new Fill({
|
|
|
|
|
|
color: 'rgba(255, 97, 97, 0.24)'
|
|
|
|
|
|
}),
|
|
|
|
|
|
stroke: new Stroke({
|
|
|
|
|
|
color: 'rgba(255, 97, 97, 0.84)',
|
|
|
|
|
|
width: 0
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
olMap.addLayer(vectorLayer)
|
|
|
|
|
|
let draw = new Draw({
|
|
|
|
|
|
source: source,
|
|
|
|
|
|
type: 'Circle',
|
|
|
|
|
|
geometryFunction: createBox(),
|
|
|
|
|
|
style: new Style({
|
|
|
|
|
|
fill: new Fill({
|
|
|
|
|
|
color: 'rgba(255, 97, 97, 0.24)'
|
|
|
|
|
|
}),
|
|
|
|
|
|
stroke: new Stroke({
|
|
|
|
|
|
color: 'rgba(255, 97, 97, 0.84)',
|
|
|
|
|
|
width: 0
|
|
|
|
|
|
}),
|
|
|
|
|
|
freehand: true
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
olMap.addInteraction(draw)
|
|
|
|
|
|
// 添加事件
|
|
|
|
|
|
draw.on('drawstart', function (event) {
|
|
|
|
|
|
source.clear()
|
|
|
|
|
|
})
|
|
|
|
|
|
draw.on('drawend', function (event) {
|
|
|
|
|
|
let geometry = event.feature.getGeometry()
|
|
|
|
|
|
let extent = geometry.getExtent()
|
|
|
|
|
|
let min = toLonLat([extent[0], extent[1]])
|
|
|
|
|
|
let max = toLonLat([extent[2], extent[3]])
|
|
|
|
|
|
|
|
|
|
|
|
callback([min[0], min[1], max[0], max[1]])
|
|
|
|
|
|
draw.abortDrawing()
|
|
|
|
|
|
olMap.removeInteraction(draw)
|
2025-10-15 15:57:25 +08:00
|
|
|
|
source.clear(true)
|
|
|
|
|
|
olMap.removeLayer(vectorLayer)
|
2025-10-14 15:57:24 +08:00
|
|
|
|
})
|
2025-04-28 15:04:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style>
|
2025-10-10 22:41:19 +08:00
|
|
|
|
#mapContainer .zoom-slider {
|
|
|
|
|
|
width: 14px;
|
|
|
|
|
|
height: 200px;
|
|
|
|
|
|
right: 20px;
|
|
|
|
|
|
bottom: 400px;
|
|
|
|
|
|
border-bottom: 1px #dfdfdf solid;
|
|
|
|
|
|
border-right: 1px #dfdfdf solid;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
background-color: #FFFFFF;
|
|
|
|
|
|
border-radius: 3px;
|
2025-04-28 15:04:06 +08:00
|
|
|
|
|
2025-10-10 22:41:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
#mapContainer .zoom-slider button {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
width: 10px;
|
|
|
|
|
|
height: 10px;
|
|
|
|
|
|
border-radius: 5px;
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
background-color: #606266;
|
|
|
|
|
|
}
|
2025-04-28 15:04:06 +08:00
|
|
|
|
</style>
|