|
|
|
|
|
|
|
|
<template> |
|
|
<template> |
|
|
<n-drawer v-bind="getDrawerOptions" @update:show="handleDrawerColse"> |
|
|
<n-drawer v-bind="getDrawerOptions" @update:show="handleDrawerColse"> |
|
|
<n-drawer-content closable title="飞行直播"> |
|
|
<n-drawer-content closable title="飞行直播"> |
|
|
飞行直播 |
|
|
|
|
|
|
|
|
<div class="main_container"> |
|
|
|
|
|
<div id="live-map" /> |
|
|
|
|
|
</div> |
|
|
</n-drawer-content> |
|
|
</n-drawer-content> |
|
|
</n-drawer> |
|
|
</n-drawer> |
|
|
</template> |
|
|
</template> |
|
|
|
|
|
|
|
|
<script> |
|
|
<script> |
|
|
import { h, defineComponent, computed, reactive, toRefs } from 'vue' |
|
|
|
|
|
|
|
|
import { defineComponent, computed, reactive, toRefs, onMounted } from 'vue' |
|
|
|
|
|
import { Map, View, Feature } from 'ol' |
|
|
|
|
|
import 'ol/ol.css' |
|
|
|
|
|
import { Tile, Vector as VectorLayer } from 'ol/layer' |
|
|
|
|
|
import LineString from 'ol/geom/LineString' |
|
|
|
|
|
import Point from 'ol/geom/Point' |
|
|
|
|
|
import { XYZ, Vector as VectorSource } from 'ol/source' |
|
|
|
|
|
import { transform, fromLonLat } from 'ol/proj' |
|
|
|
|
|
import { getVectorContext } from 'ol/render' |
|
|
|
|
|
import VectorContext from 'ol/render/VectorContext' |
|
|
|
|
|
import { Draw } from 'ol/interaction' |
|
|
|
|
|
import { toRaw } from '@vue/reactivity' |
|
|
|
|
|
import * as control from 'ol/control' |
|
|
|
|
|
import { styleList } from '../tools/style.js' |
|
|
|
|
|
|
|
|
export default defineComponent({ |
|
|
export default defineComponent({ |
|
|
name: 'LiveDrawer', |
|
|
name: 'LiveDrawer', |
|
|
|
|
|
|
|
|
}, |
|
|
}, |
|
|
setup(props, { emit }) { |
|
|
setup(props, { emit }) { |
|
|
const data = reactive({ |
|
|
const data = reactive({ |
|
|
|
|
|
|
|
|
|
|
|
mapData: null, |
|
|
|
|
|
view: null, |
|
|
|
|
|
liveTrackLayer: null, |
|
|
|
|
|
lineTrackLayer: null, |
|
|
|
|
|
trackInfo: null, |
|
|
|
|
|
socket: null, |
|
|
|
|
|
// 预计航线数据 |
|
|
|
|
|
lineTrajectoryList: [ |
|
|
|
|
|
{ lng: '118.765591', lat: '32.050993' }, |
|
|
|
|
|
{ lng: '118.665591', lat: '32.150993' }, |
|
|
|
|
|
{ lng: '118.565591', lat: '32.070993' }, |
|
|
|
|
|
{ lng: '118.465591', lat: '32.020993' }, |
|
|
|
|
|
{ lng: '118.365591', lat: '32.110993' }, |
|
|
|
|
|
{ lng: '118.265591', lat: '32.080993' }, |
|
|
|
|
|
{ lng: '118.165591', lat: '32.150993' }, |
|
|
|
|
|
{ lng: '118.765591', lat: '32.150993' }, |
|
|
|
|
|
{ lng: '118.665591', lat: '32.050993' }, |
|
|
|
|
|
{ lng: '118.565591', lat: '32.170993' }, |
|
|
|
|
|
{ lng: '118.465591', lat: '32.010993' }, |
|
|
|
|
|
{ lng: '118.365591', lat: '32.060993' }, |
|
|
|
|
|
{ lng: '118.265591', lat: '32.180993' }, |
|
|
|
|
|
{ lng: '118.165591', lat: '32.050993' } |
|
|
|
|
|
], |
|
|
|
|
|
// 轨迹数据 |
|
|
|
|
|
trackList: [ |
|
|
|
|
|
{ lng: '118.765591', lat: '32.050993' }, |
|
|
|
|
|
{ lng: '118.665591', lat: '32.150993' }, |
|
|
|
|
|
{ lng: '118.565591', lat: '32.070993' }, |
|
|
|
|
|
{ lng: '118.465591', lat: '32.020993' }, |
|
|
|
|
|
{ lng: '118.365591', lat: '32.110993' }, |
|
|
|
|
|
{ lng: '118.265591', lat: '32.080993' }, |
|
|
|
|
|
{ lng: '118.165591', lat: '32.150993' } |
|
|
|
|
|
], |
|
|
|
|
|
trajectoryList: [], // 历史轨迹坐标数据 |
|
|
|
|
|
disdance: null, |
|
|
|
|
|
animating: null |
|
|
}) |
|
|
}) |
|
|
|
|
|
|
|
|
/* 获取抽屉的信息 */ |
|
|
/* 获取抽屉的信息 */ |
|
|
const getDrawerOptions = computed(() => { |
|
|
const getDrawerOptions = computed(() => { |
|
|
return { |
|
|
return { |
|
|
|
|
|
|
|
|
emit('update:visible', false) |
|
|
emit('update:visible', false) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
onMounted(() => { |
|
|
|
|
|
initMap() |
|
|
|
|
|
// 加载航线 |
|
|
|
|
|
initTrack(formatTradeList(data.lineTrajectoryList), 'lineTrackLayer', 'lineRoute') |
|
|
|
|
|
// 加载历史轨迹和实时轨迹 |
|
|
|
|
|
setLiveTrack(formatTradeList(data.trackList)) |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
/* 初始化地图 */ |
|
|
|
|
|
const initMap = function() { |
|
|
|
|
|
const layers = [ |
|
|
|
|
|
new Tile({ |
|
|
|
|
|
visible: true, |
|
|
|
|
|
source: new XYZ({ |
|
|
|
|
|
url: 'https://tianditu.t-aaron.com/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=f82bb2fd8115c7fb576a8b2fcf738523' |
|
|
|
|
|
}) |
|
|
|
|
|
}) |
|
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
data.view = new View({ |
|
|
|
|
|
maxZoom: 18, |
|
|
|
|
|
zoom: 5, |
|
|
|
|
|
center: transform([118.837886, 32.057175], 'EPSG:4326', 'EPSG:3857') |
|
|
|
|
|
}) |
|
|
|
|
|
data.mapData = new Map({ |
|
|
|
|
|
layers: layers, |
|
|
|
|
|
target: 'live-map', |
|
|
|
|
|
view: data.view, |
|
|
|
|
|
controls: control.defaults({ |
|
|
|
|
|
attribution: false, |
|
|
|
|
|
rotate: false, |
|
|
|
|
|
zoom: false |
|
|
|
|
|
}) |
|
|
|
|
|
}) |
|
|
|
|
|
data.mapData.render() |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* 处理轨迹列表 */ |
|
|
|
|
|
const formatTradeList = function(trackList) { |
|
|
|
|
|
return trackList.map((item) => |
|
|
|
|
|
fromLonLat([parseFloat(item.lng), parseFloat(item.lat)]) |
|
|
|
|
|
) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* 初始化轨迹 */ |
|
|
|
|
|
const initTrack = function(coordinate, layer, routeType) { |
|
|
|
|
|
let vectorLayer = null |
|
|
|
|
|
const route = new LineString(coordinate) |
|
|
|
|
|
const routeFeature = new Feature({ |
|
|
|
|
|
type: routeType, |
|
|
|
|
|
geometry: route |
|
|
|
|
|
}) |
|
|
|
|
|
const startMarker = new Feature({ |
|
|
|
|
|
type: 'icon', |
|
|
|
|
|
geometry: new Point(route.getFirstCoordinate()) |
|
|
|
|
|
}) |
|
|
|
|
|
const position = startMarker.getGeometry().clone() |
|
|
|
|
|
const geoMarker = new Feature({ |
|
|
|
|
|
type: 'geoMarker', |
|
|
|
|
|
geometry: position |
|
|
|
|
|
}) |
|
|
|
|
|
geoMarker.setProperties({ type: 'geoMarker' }, false) |
|
|
|
|
|
if (data.liveTrackLayer) { |
|
|
|
|
|
data.liveTrackLayer.setSource( |
|
|
|
|
|
new VectorSource({ |
|
|
|
|
|
features: [geoMarker, routeFeature] |
|
|
|
|
|
}) |
|
|
|
|
|
) |
|
|
|
|
|
vectorLayer = data.liveTrackLayer |
|
|
|
|
|
} else { |
|
|
|
|
|
vectorLayer = new VectorLayer({ |
|
|
|
|
|
source: new VectorSource({ |
|
|
|
|
|
features: [geoMarker, routeFeature] |
|
|
|
|
|
}), |
|
|
|
|
|
style: function(feature) { |
|
|
|
|
|
return styleList[feature.get('type')] |
|
|
|
|
|
} |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
data[layer] = vectorLayer |
|
|
|
|
|
data.mapData.addLayer(data[layer]) |
|
|
|
|
|
data.view.fit(route, { padding: [50, 50, 50, 50] }) |
|
|
|
|
|
return { |
|
|
|
|
|
vectorLayer, |
|
|
|
|
|
geoMarker, |
|
|
|
|
|
route, |
|
|
|
|
|
position |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* 轨迹改变 */ |
|
|
|
|
|
const changeTrack = (event) => { |
|
|
|
|
|
try { |
|
|
|
|
|
const vectorContext = getVectorContext(event) |
|
|
|
|
|
vectorContext.setStyle(styleList['geoMarker']) |
|
|
|
|
|
VectorContext.drawGeometry(data.trackInfo.position) |
|
|
|
|
|
vectorContext.drawGeometry(data.trackInfo.route) |
|
|
|
|
|
data.mapData.render() |
|
|
|
|
|
} catch { |
|
|
|
|
|
console.log(event) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* 加载实时轨迹 */ |
|
|
|
|
|
const setLiveTrack = function(hisTrackList) { |
|
|
|
|
|
data.animating = false |
|
|
|
|
|
data.disdance = 0 |
|
|
|
|
|
if (hisTrackList.length > 1) { |
|
|
|
|
|
data.trackInfo = initTrack(hisTrackList, 'liveTrackLayer', 'route') |
|
|
|
|
|
if (data.trackInfo.vectorLayer) { |
|
|
|
|
|
data.liveTrackLayer.on('change', changeTrack) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 两秒钟获取一次数据 |
|
|
|
|
|
data.socket = setInterval(() => { |
|
|
|
|
|
// getTrackdata({ inspectionId: id }).then((res) => { |
|
|
|
|
|
// const coordinate = fromLonLat([res.data.lng, res.data.lat]) |
|
|
|
|
|
// const unUseableCoordinate = !coordinate.every((item) => !isNaN(item)) |
|
|
|
|
|
// if (unUseableCoordinate) return |
|
|
|
|
|
// // 赋值动态无人机坐标 |
|
|
|
|
|
// if (coordinate.length) { |
|
|
|
|
|
// data.trajectoryList.lng = coordinate[0] |
|
|
|
|
|
// data.trajectoryList.lat = coordinate[1] |
|
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
|
|
// data.trackList.push(coordinate) |
|
|
|
|
|
// if (data.trackList.length > 1 && !data.trackInfo) { |
|
|
|
|
|
// initTrack(data.trackList) |
|
|
|
|
|
// } |
|
|
|
|
|
// if (data.trackInfo) { |
|
|
|
|
|
// data.trackInfo.route.appendCoordinate(coordinate) |
|
|
|
|
|
// data.trackInfo.vectorLayer.getSource().changed() |
|
|
|
|
|
// data.trackInfo.position.setCoordinates(coordinate) |
|
|
|
|
|
// } |
|
|
|
|
|
// }) |
|
|
|
|
|
}, 2000) |
|
|
|
|
|
// 移动要素 |
|
|
|
|
|
const moveFeature = function(event) { |
|
|
|
|
|
var lastTime |
|
|
|
|
|
const speed = Number(50) |
|
|
|
|
|
const time = event.frameState.time |
|
|
|
|
|
const elapsedTime = time - lastTime |
|
|
|
|
|
data.disdance = (data.disdance + (speed * elapsedTime) / 1e6) % 2 |
|
|
|
|
|
if (data.disdance > 1) { |
|
|
|
|
|
stopAnimation(data.trackInfo) |
|
|
|
|
|
} |
|
|
|
|
|
lastTime = time |
|
|
|
|
|
|
|
|
|
|
|
const currentCoordinate = data.trackInfo.route.getCoordinateAt( |
|
|
|
|
|
data.disdance > 1 ? 2 - data.disdance : data.disdance |
|
|
|
|
|
) |
|
|
|
|
|
data.trackInfo.position.setCoordinates(currentCoordinate) |
|
|
|
|
|
const vectorContext = getVectorContext(event) |
|
|
|
|
|
vectorContext.setStyle(styleList['geoMarker']) |
|
|
|
|
|
vectorContext.drawGeometry(data.trackInfo.position) |
|
|
|
|
|
data.mapData.render() |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 停止动画 |
|
|
|
|
|
const stopAnimation = function(trackInfo) { |
|
|
|
|
|
const { vectorLayer, geoMarker } = trackInfo |
|
|
|
|
|
data.animating = false |
|
|
|
|
|
geoMarker.setGeometry(trackInfo.position) |
|
|
|
|
|
vectorLayer.un('postrender', moveFeature) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
return { |
|
|
return { |
|
|
...toRefs(data), |
|
|
...toRefs(data), |
|
|
getDrawerOptions, |
|
|
getDrawerOptions, |
|
|
|
|
|
|
|
|
.n-button+.n-button{ |
|
|
.n-button+.n-button{ |
|
|
margin-left: 30px; |
|
|
margin-left: 30px; |
|
|
} |
|
|
} |
|
|
|
|
|
.main_container { |
|
|
|
|
|
width: 100%; |
|
|
|
|
|
height: 100%; |
|
|
|
|
|
position: relative; |
|
|
|
|
|
overflow: hidden; |
|
|
|
|
|
} |
|
|
|
|
|
#live-map { |
|
|
|
|
|
width: 100%; |
|
|
|
|
|
height: 100%; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
</style> |
|
|
</style> |