AnalysisSystemForRadionucli.../src/views/stationOperation/components/Map.vue

252 lines
5.8 KiB
Vue

<template>
<div ref="mapContainerRef" class="map-container">
<template v-if="map">
<slot></slot>
</template>
</div>
</template>
<script>
import TileLayer from 'ol/layer/Tile'
import Map from 'ol/Map'
import XYZ from 'ol/source/XYZ'
import View from 'ol/View'
import { fromLonLat } from 'ol/proj'
import Stroke from 'ol/style/Stroke'
import { MarkerIcon, MarkerType } from './markerEnum'
import Icon from 'ol/style/Icon'
import VectorSource from 'ol/source/Vector'
import VectorLayer from 'ol/layer/Vector'
import { LineString, Point } from 'ol/geom'
import { Feature } from 'ol'
import Style from 'ol/style/Style'
const mapSourceUrl = process.env.VUE_APP_MAP_BASE_URL
export default {
props: {
zoom: {
type: Number,
default: 1,
},
maxZoom: {
type: Number,
default: 16,
},
minZoom: {
type: Number,
default: 1,
},
center: {
type: Object,
default() {
return {
longitude: 116,
latitude: 40,
}
},
},
},
data() {
return {
map: null,
stationList: [],
}
},
mounted() {
this.initMap()
},
methods: {
// 初始化地图
initMap() {
const { longitude, latitude } = this.center
this.tileLayer = new TileLayer({
source: new XYZ({
url: mapSourceUrl,
}),
})
this.animationSource = new VectorSource({
features: [],
})
this.animationLayer = new VectorLayer({
source: this.animationSource,
})
const layers = [this.tileLayer, this.animationLayer]
this.view = new View({
projection: 'EPSG:3857', // 使用这个坐标系
center: fromLonLat([longitude, latitude]),
zoom: this.zoom,
maxZoom: this.maxZoom,
minZoom: this.minZoom,
extent: [-20037508.34 - 3500000, -20037508.34, 20037508.34 + 3500000, 20037508.34],
})
this.map = new Map({
target: this.$refs.mapContainerRef,
layers,
view: this.view,
controls: [],
})
},
/**
* 以下是工具方法
*/
// 获取地图缩放级别
getZoom() {
return this.map.getView().getZoom()
},
// 设置地图缩放级别
setZoom(zoom) {
if (zoom < this.minZoom) {
zoom = this.minZoom
}
if (zoom > this.maxZoom) {
zoom = this.maxZoom
}
this.map.getView().animate({ zoom })
},
getMapInstance() {
return this.map
},
// 获取地图中心点
getCenter() {
return this.map.getView().getCenter()
},
// 平移到某个位置
panTo(center, duration = 1000) {
return this.map.getView().animate({
center: fromLonLat(center),
duration,
})
},
// 修改地图来源
changeSource(url) {
this.tileLayer.setSource(
new XYZ({
url,
})
)
},
// 按路线运动
animateByRoute(coordinates) {
if (!coordinates) {
return
}
if (!coordinates.length) {
this.stopRouteAnimation()
this.removeAnimationFeatures()
return
}
this.startRouteAnimation(
coordinates,
{
stroke: new Stroke({
color: '#17f85c',
lineDash: [6],
width: 2,
}),
},
{
image: new Icon({
src: MarkerIcon[MarkerType.Car],
anchor: [0.65, 0.5],
}),
},
[100, 430, 100, 450]
)
},
/**
* 沿轨迹运动
* @param {Array<any>} route 轨迹路线
* @param {Object} marker 运动的物体
*/
startRouteAnimation(route, lineStyleOptions, markerStyleOptions, padding = []) {
// 清理上次的动画
this.stopRouteAnimation()
// 清理动画图层
this.removeAnimationFeatures()
const lineString = new LineString(route.map((item) => fromLonLat(item)))
const extent = lineString.getExtent()
this.view.fit(extent, {
padding,
duration: 1000,
})
// 创建轨迹线
const routeFeature = new Feature({
geometry: lineString,
})
// 设置轨迹线样式,并添加到地图上
routeFeature.setStyle(new Style(lineStyleOptions))
this.animationSource.addFeature(routeFeature)
// 创建标记物,并设置位置到轨迹路线的初始位置
const markerFeature = new Feature({
geometry: new Point(lineString.getFirstCoordinate()),
})
// 设置标记物样式,并添加到地图上
markerFeature.setStyle(new Style(markerStyleOptions))
this.animationSource.addFeature(markerFeature)
let lastTime = Date.now(),
distance = 0
this.postRenderCallback = (event) => {
const speed = 60
const time = event.frameState.time
const elapsedTime = time - lastTime
distance = (distance + (speed * elapsedTime) / 1e6) % 2
lastTime = time
if (distance >= 1) {
this.stopRouteAnimation()
return
}
const currentCoordinate = lineString.getCoordinateAt(distance > 1 ? 2 - distance : distance)
markerFeature.setGeometry(new Point(currentCoordinate))
// tell OpenLayers to continue the postrender animation
this.map.render()
}
this.animationLayer.on('postrender', this.postRenderCallback)
},
// 移除动画层所有元素
removeAnimationFeatures() {
this.animationSource.clear()
},
// 停止轨迹动画
stopRouteAnimation() {
if (this.postRenderCallback) {
this.animationLayer.un('postrender', this.postRenderCallback)
this.postRenderCallback = null
}
},
},
}
</script>
<style lang="less" scoped>
.map-container {
height: 100%;
position: relative;
}
</style>