Browse Source

直播轨迹页面接入真实数据

tags/v1.0.0^2
余菲 2 years ago
parent
commit
94586b996c
7 changed files with 284 additions and 63 deletions
  1. +12
    -0
      src/api/task/index.js
  2. +101
    -0
      src/utils/coordinate-util.js
  3. +55
    -0
      src/utils/getDroneLine.js
  4. +10
    -0
      src/utils/handleText.js
  5. +17
    -14
      src/views/task-manage/all-task/components/DemandDrawer.vue
  6. +88
    -47
      src/views/task-manage/all-task/components/LiveDrawer.vue
  7. +1
    -2
      src/views/task-manage/all-task/index.vue

+ 12
- 0
src/api/task/index.js View File

@@ -72,6 +72,18 @@ export function getQuestionList(params) {
params
})
}

/**
* @description: 获取飞行轨迹列表
* @param {*} id 任务id
* @return {*}
*/
export function getTrackList(id) {
return request({
url: `/inspection/track/${id}`,
method: 'GET'
})
}
/**
* @description: 获取问题列表
* @param {*} params

+ 101
- 0
src/utils/coordinate-util.js View File

@@ -0,0 +1,101 @@
//定义一些常量
var x_PI = 3.14159265358979324 * 3000.0 / 180.0;
var PI = 3.1415926535897932384626;
var a = 6378245.0;
var ee = 0.00669342162296594323;

/**
* 百度坐标系 (BD-09) 与 火星坐标系 (GCJ-02)的转换
* 即 百度 转 谷歌、高德
*/
export function bd09togcj02(bd_lon, bd_lat) {
var x_pi = 3.14159265358979324 * 3000.0 / 180.0;
var x = bd_lon - 0.0065;
var y = bd_lat - 0.006;
var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
var theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
var gg_lng = z * Math.cos(theta);
var gg_lat = z * Math.sin(theta);
return [gg_lng, gg_lat]
}

/**
* 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换
* 即谷歌、高德 转 百度
*/
export function gcj02tobd09(lng, lat) {
var z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * x_PI);
var theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * x_PI);
var bd_lng = z * Math.cos(theta) + 0.0065;
var bd_lat = z * Math.sin(theta) + 0.006;
return [bd_lng, bd_lat]
}

/**
* WGS84转GCj02
*/
export function wgs84togcj02(coordinate) {
let lng=parseFloat(coordinate[0]);
let lat=parseFloat(coordinate[1]);
if (out_of_china(lng, lat)) {
return [lng, lat]
}
else {
var dlat = transformlat(lng - 105.0, lat - 35.0);
var dlng = transformlng(lng - 105.0, lat - 35.0);
var radlat = lat / 180.0 * PI;
var magic = Math.sin(radlat);
magic = 1 - ee * magic * magic;
var sqrtmagic = Math.sqrt(magic);
var dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI);
var dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI);
var mglat = lat + dlat;
var mglng = lng + dlng;
return [mglng, mglat]
}
}

/**
* GCJ02 转换为 WGS84
*/
export function gcj02towgs84(lng, lat) {
if (out_of_china(lng, lat)) {
return [lng, lat]
}
else {
var dlat = transformlat(lng - 105.0, lat - 35.0);
var dlng = transformlng(lng - 105.0, lat - 35.0);
var radlat = lat / 180.0 * PI;
var magic = Math.sin(radlat);
magic = 1 - ee * magic * magic;
var sqrtmagic = Math.sqrt(magic);
dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI);
dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI);
var mglat = lat + dlat;
var mglng = lng + dlng;
return [lng * 2 - mglng, lat * 2 - mglat]
}
}

export function transformlat(lng, lat) {
var ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0;
ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0;
return ret
}

export function transformlng(lng, lat) {
var ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0;
ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0;
return ret
}

/**
* 判断是否在国内,不在国内则不做偏移
*/
export function out_of_china(lng, lat) {
return (lng < 72.004 || lng > 137.8347) || ((lat < 0.8293 || lat > 55.8271) || false);
}

+ 55
- 0
src/utils/getDroneLine.js View File

@@ -0,0 +1,55 @@
import axios from 'axios'
import { wgs84togcj02 } from '@/utils/coordinate-util'
export default function getDroneLine(url, map, isfitView = true) {
if (!url) return Promise.resolve(null)
const temp = url.split('//')
url = temp[temp.length - 1]
url = process.env.VUE_APP_API_BASE_URL + url
const generateMarker = () => {
const dotContainer = document.createElement('div')
dotContainer.style = 'height:16px;width:16px;background-color:#5798FF;border-radius:50%;position:relative'
const dotInner = document.createElement('div')
dotInner.style = 'height:8px;width:8px;background-color:#fff;border-radius:50%;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)'
dotContainer.appendChild(dotInner)
return dotContainer
}
return axios.get(url).then((res) => {
const text = res.data
let arr = text.split('\r\n')
arr.shift()
arr.pop()
arr = arr.map((text) => {
return text.split(/\s+/)
})
const polylinePath = []
// let markerArr = [];
const overlayGroup = new AMap.OverlayGroup()

for (const point of arr) {
if (point[9] !== 0) {
const coordinate = wgs84togcj02([point[9], point[8]])
polylinePath.push(coordinate)
const marker = new AMap.Marker({
position: new AMap.LngLat(coordinate[0], coordinate[1]),
content: generateMarker(),
anchor: 'center',
zIndex: 20
})
overlayGroup.addOverlay(marker)
}
}

const polyline = new AMap.Polyline({
path: polylinePath,
strokeColor: '#5798FF',
strokeWeight: 4,
strokeStyle: 'dashed'
})
overlayGroup.addOverlay(polyline)
map.add(overlayGroup)
if (isfitView) {
map.setFitView(overlayGroup.getOverlays(), true, [70, 100, 300, 50])
}
return overlayGroup
})
}

+ 10
- 0
src/utils/handleText.js View File

@@ -0,0 +1,10 @@
export const handleTextToList = function(text) {
let arr = text.split('\r\n')
arr.shift()
arr.pop()
arr = arr.map((text) => {
return text.split(/\s+/)
})
arr = arr.map(item => [item[9], item[8]])
return arr
}

+ 17
- 14
src/views/task-manage/all-task/components/DemandDrawer.vue View File

@@ -52,6 +52,7 @@ import { transform, fromLonLat } from 'ol/proj'
import { getVectorContext } from 'ol/render'
import * as control from 'ol/control'
import { styleList } from '../tools/style.js'
import { getTrackList } from '@/api/task/index.js'

// 视频组件
import VideoPlayer from '@/components/VideoPlayer/index.vue'
@@ -81,15 +82,7 @@ export default defineComponent({
trackLayer: null,
trackInfo: null,
// 轨迹数据
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' }
],
trackList: [],
disdance: null,
animating: null,
detailData: {
@@ -207,14 +200,24 @@ export default defineComponent({
aiVideoRef.value.playVideo()
}

watch([() => props.visible, () => data.videoStatus], ([visible, status]) => {
if (visible) {
// initTrack(formatTradeList(data.trackList), 'route')
}
/* 获取轨迹数据 */
const getTrackData = async function() {
const res = await getTrackList(props.data.id)
const trackList = res.data
return Promise.resolve({
trackList
})
}

watch([() => data.videoStatus], ([status]) => {
if (status.status === 'ready' && status.aiStatus === 'ready') {
startAllVideo()
initMap()
initTrack(formatTradeList(data.trackList), 'route')
getTrackData().then(res => {
if (res.trackList.length > 0) {
initTrack(formatTradeList(res.trackList), 'route')
}
})
}
}, { deep: true })


+ 88
- 47
src/views/task-manage/all-task/components/LiveDrawer.vue View File

@@ -4,7 +4,7 @@
<div class="main_container">
<div id="live-map" />
<!-- 视频播放 -->
<div v-if="detailData?.name" class="videobox">
<div class="videobox">
<!-- 视频开关 -->
<div
class="flagbox"
@@ -33,7 +33,6 @@
:class="videoShow == 'back' ? 'video_show' : 'video_hidden'"
>
<VideoPlayer :options="getVideoOptions" />
<div class="flagbox">AI识别视频</div>
<VideoPlayer :options="getVideoLiveOptions" />
</div>
</div>
@@ -43,7 +42,7 @@
</template>

<script>
import { defineComponent, computed, reactive, toRefs, onMounted } from 'vue'
import { defineComponent, computed, reactive, toRefs, watch } from 'vue'
import { Map, View, Feature } from 'ol'
import 'ol/ol.css'
import { Tile, Vector as VectorLayer } from 'ol/layer'
@@ -53,10 +52,9 @@ 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'
import { getTrackList } from '@/api/task/index.js'

// 视频组件
import VideoPlayer from '@/components/VideoPlayer/index.vue'
@@ -96,15 +94,14 @@ export default defineComponent({
{ 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.66551', lat: '32.050993' },
{ lng: '118.365591', lat: '32.060993' },
{ lng: '118.265591', lat: '32.180993' },
{ lng: '118.165591', lat: '32.050993' }
],
addIndex: 0,
// 轨迹数据
trackList: [],
// 历史轨迹坐标数据
trajectoryList: [
trackList: [
{ lng: '118.765591', lat: '32.050993' },
{ lng: '118.665591', lat: '32.150993' },
{ lng: '118.565591', lat: '32.070993' },
@@ -131,7 +128,7 @@ export default defineComponent({
const getVideoOptions = computed(() => {
return {
id: 'video-live',
width: '378px',
width: '800px',
height: '212px',
source: data.detailData.pullUrl,
isLive: true
@@ -141,7 +138,7 @@ export default defineComponent({
const getVideoLiveOptions = computed(() => {
return {
id: 'video-live',
width: '378px',
width: '800px',
height: '212px',
source: data.detailData.pullUrl,
isLive: true
@@ -152,13 +149,48 @@ export default defineComponent({
emit('update:visible', false)
}

onMounted(() => {
initMap()
// 加载航线
initTrack(formatTradeList(data.lineTrajectoryList), 'lineTrackLayer', 'lineRoute')
// 加载历史轨迹和实时轨迹
setLiveTrack(formatTradeList(data.trajectoryList))
})
/* 获取轨迹数据 */
const getTrackData = async function() {
const res = await getTrackList(props.data.id)
const trackList = res.data
return Promise.resolve({
trackList
})
}

watch(() => props.visible, (value) => {
if (value) {
if (!data.mapData) {
if (document.getElementById('live-map')) {
initMap()
// 加载机场航线
// initTrack(formatTradeList(data.lineTrajectoryList), 'lineTrackLayer', 'lineRoute')
// 加载历史轨迹和实时轨迹
getTrackData().then(({ trackList }) => {
if (trackList.length > 0) {
setLiveTrack(formatTradeList(trackList))
}
})
} else {
setTimeout(() => {
initMap()
// 加载机场航线
// initTrack(formatTradeList(data.lineTrajectoryList), 'lineTrackLayer', 'lineRoute')
// 加载历史轨迹和实时轨迹
getTrackData().then(({ trackList }) => {
data.trackList = trackList
if (trackList.length > 0) {
setLiveTrack(formatTradeList(data.trackList))
}
})
}, 500)
}
}
} else {
clearInterval(data.socket)
data.socket = null
}
}, { deep: true })

/* 初始化地图 */
const initMap = function() {
@@ -204,11 +236,11 @@ export default defineComponent({
type: routeType,
geometry: route
})
const startMarker = new Feature({
const endMarker = new Feature({
type: 'icon',
geometry: new Point(route.getFirstCoordinate())
geometry: new Point(route.getLastCoordinate())
})
const position = startMarker.getGeometry().clone()
const position = endMarker.getGeometry().clone()
const geoMarker = new Feature({
type: 'geoMarker',
geometry: position
@@ -242,23 +274,11 @@ export default defineComponent({
}
}

/* 轨迹改变 */
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
var changeTrack
if (hisTrackList.length > 1) {
data.trackInfo = initTrack(hisTrackList, 'liveTrackLayer', 'route')
if (data.trackInfo.vectorLayer) {
@@ -266,18 +286,25 @@ export default defineComponent({
}
}

/* 轨迹改变 */
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)
}
}

// 两秒钟获取一次数据
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)
@@ -288,7 +315,16 @@ export default defineComponent({
// data.trackInfo.position.setCoordinates(coordinate)
// }
// })
}, 2000)
const obj = data.lineTrajectoryList[data.addIndex]
const coordinate = fromLonLat([obj.lng, obj.lat])
console.log(coordinate)
data.addIndex = data.addIndex + 1
if (data.trackInfo) {
data.trackInfo.route.appendCoordinate(coordinate)
data.trackInfo.vectorLayer.getSource().changed()
data.trackInfo.position.setCoordinates(coordinate)
}
}, 1000)
// 移动要素
const moveFeature = function(event) {
var lastTime
@@ -347,7 +383,7 @@ export default defineComponent({
}
/* 视频 */
.videobox {
width: 378px;
width: 800px;
display: flex;
flex-direction: column;
justify-content: flex-start;
@@ -357,7 +393,7 @@ export default defineComponent({
right: 10px;
}
.flagbox {
width: 378px;
width: 800px;
height: 27px;
background: #fff;
padding: 0 10px;
@@ -366,7 +402,7 @@ export default defineComponent({
align-items: center;
}
.flagbox_open {
width: 378px;
width: 800px;
animation: openbox 1s;
}
.flaxbox_back {
@@ -375,7 +411,7 @@ export default defineComponent({
}
@keyframes backbox {
from {
width: 378px;
width: 800px;
}
to {
width: 116px;
@@ -386,11 +422,11 @@ export default defineComponent({
width: 116px;
}
to {
width: 378px;
width: 800px;
}
}
.video_content {
width: 378px;
width: 800px;
height: 220px;
position: relative;
}
@@ -419,5 +455,10 @@ export default defineComponent({
opacity: 0;
}
}
.imageicon {
width: 16px;
height: 16px;
margin-right: 10px;
}

</style>

+ 1
- 2
src/views/task-manage/all-task/index.vue View File

@@ -29,7 +29,7 @@
<!-- 新增、编辑弹窗 -->
<TaskModal v-if="modalShow" v-model:visible="modalShow" :type="modalType" :data="rowData" @reload="handleSearch" />
<!-- 直播抽屉 -->
<LiveDrawer v-if="liveDrawer" v-model:visible="liveDrawer" :data="rowData" />
<LiveDrawer v-model:visible="liveDrawer" :data="rowData" />
<!-- 轨迹回放 -->
<DemandDrawer v-model:visible="demandDrawer" :data="rowData" />
<!-- 问题核实 -->
@@ -82,7 +82,6 @@ export default {
}

function handleChange(value) {
console.log(value)
const { airportId } = value
if (data.airportId !== airportId) {
if (!airportId) {

Loading…
Cancel
Save