历史轨迹查询实现
This commit is contained in:
parent
29cadf45ba
commit
b98b01f05c
@ -150,8 +150,8 @@ function rangeToOptions(dateData){
|
||||
return true;
|
||||
}
|
||||
|
||||
let result = moment(date.value.from).isSameOrBefore(dateData)
|
||||
if(!result){
|
||||
let result = moment(date.value.from).startOf('d').isSameOrBefore(dateData)
|
||||
if(!moment(date.value.from).startOf('d').isSameOrBefore(date.value.to)){
|
||||
date.value.to = date.value.from
|
||||
}
|
||||
return result;
|
||||
|
@ -1,12 +1,14 @@
|
||||
<template>
|
||||
<div class="flex justify-start flex-wrap items-center">
|
||||
<DateTimeSelector v-model="date" range></DateTimeSelector>
|
||||
<q-btn @click="search">查询</q-btn>
|
||||
</div>
|
||||
<div class="flex justify-end flex-wrap items-center p-1">
|
||||
<q-toggle
|
||||
label="卫星地图"
|
||||
v-model="layers.satellite.show"
|
||||
color="primary"
|
||||
@update:model-value="toggleSatellite"
|
||||
keep-color
|
||||
/>
|
||||
|
||||
@ -14,6 +16,7 @@
|
||||
label="路网"
|
||||
v-model="layers.roadNet.show"
|
||||
color="primary"
|
||||
@update:model-value="toggleRoadNet"
|
||||
keep-color
|
||||
/>
|
||||
|
||||
@ -21,6 +24,15 @@
|
||||
label="实时交通"
|
||||
v-model="layers.traffic.show"
|
||||
color="primary"
|
||||
@update:model-value="toggleTraffic"
|
||||
keep-color
|
||||
/>
|
||||
|
||||
<q-toggle
|
||||
label="纠偏路线"
|
||||
v-model="feature.showFixed"
|
||||
color="primary"
|
||||
@update:model-value="fixedLocation"
|
||||
keep-color
|
||||
/>
|
||||
</div>
|
||||
@ -30,8 +42,42 @@
|
||||
import AMapLoader from '@amap/amap-jsapi-loader';
|
||||
import {reactive, ref} from "vue";
|
||||
import DateTimeSelector from "matrix-middle-service-web/src/components/DateTimeSelector.vue";
|
||||
import {useQuasar} from "quasar";
|
||||
import moment from "moment";
|
||||
const $q = useQuasar();
|
||||
const COLOR = [
|
||||
'#6090e0', '#30c030', '#d070d0', '#80c0f0', '#f07050', '#ffb900',
|
||||
'#37a2da', '#ffdb5c', '#8378ea', '#e7bcf3', '#32c5e9', '#67e0e3',
|
||||
'#dd6b66', '#759aa0', '#e69d87', '#8dc1a9', '#ea7e53', '#eedd78',
|
||||
]
|
||||
let canvasDir = document.createElement('canvas')
|
||||
let width = 24;
|
||||
let height = 24;
|
||||
canvasDir.width = width;
|
||||
canvasDir.height = height;
|
||||
let context = canvasDir.getContext('2d');
|
||||
context.strokeStyle = 'white';
|
||||
context.lineJoin = 'round';
|
||||
context.lineWidth = 8;
|
||||
context.moveTo(-4, width - 4);
|
||||
context.lineTo(width / 2, 6);
|
||||
context.lineTo(width + 4, width - 4);
|
||||
context.stroke();
|
||||
const date = ref({})
|
||||
const feature = reactive({
|
||||
showFixed: false
|
||||
})
|
||||
// 地图实例 和 数据不要交给 vue 管理 否则性能大打折扣 且 会有各种奇葩问题
|
||||
let map = {}
|
||||
const data = {
|
||||
data: [],
|
||||
polyline: {},
|
||||
polylines: [],
|
||||
fixedPolyline: {},
|
||||
labelsLayer: {},
|
||||
markers: [],
|
||||
tmpMarker: {},
|
||||
}
|
||||
const layers = reactive({
|
||||
satellite: {
|
||||
inst: {},
|
||||
@ -46,15 +92,320 @@ const layers = reactive({
|
||||
show: false,
|
||||
}
|
||||
})
|
||||
function toggleSatellite(){
|
||||
if (layers.satellite.show) {
|
||||
layers.satellite.inst.show()
|
||||
} else {
|
||||
layers.satellite.inst.hide()
|
||||
}
|
||||
}
|
||||
function toggleRoadNet() {
|
||||
if (layers.roadNet.show) {
|
||||
layers.roadNet.inst.show()
|
||||
} else {
|
||||
layers.roadNet.inst.hide()
|
||||
}
|
||||
}
|
||||
function toggleTraffic() {
|
||||
if (layers.traffic.show) {
|
||||
layers.traffic.inst.show()
|
||||
} else {
|
||||
layers.traffic.inst.hide()
|
||||
}
|
||||
}
|
||||
|
||||
AMapLoader.load({
|
||||
"key": "e01d7df3a4c3a1b8f06fa4544ddbbe9c", // 申请好的Web端开发者Key,首次调用 load 时必填
|
||||
"version": "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
|
||||
"plugins": [], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
|
||||
"plugins": [
|
||||
"AMap.Scale",
|
||||
"AMap.HawkEye",
|
||||
"AMap.ToolBar",
|
||||
"AMap.ControlBar"
|
||||
], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
|
||||
}).then((AMap) => {
|
||||
map = new AMap.Map('container');
|
||||
let scale = new AMap.Scale({
|
||||
visible: true
|
||||
})
|
||||
let toolBar = new AMap.ToolBar({
|
||||
visible: true,
|
||||
position: {
|
||||
top: '110px',
|
||||
right: '40px'
|
||||
}
|
||||
})
|
||||
let controlBar = new AMap.ControlBar({
|
||||
visible: true,
|
||||
position: {
|
||||
top: '10px',
|
||||
right: '10px'
|
||||
}
|
||||
})
|
||||
|
||||
map = new AMap.Map('container',{
|
||||
zoom: 14,
|
||||
});
|
||||
console.log("地图对象", map)
|
||||
map.addControl(scale)
|
||||
map.addControl(toolBar)
|
||||
map.addControl(controlBar)
|
||||
|
||||
// 卫星
|
||||
layers.satellite.inst = new AMap.TileLayer.Satellite({
|
||||
visible: layers.satellite.show,
|
||||
})
|
||||
// 路网
|
||||
layers.roadNet.inst = new AMap.TileLayer.RoadNet({
|
||||
visible: layers.roadNet.show,
|
||||
index: 10
|
||||
})
|
||||
// 实时交通
|
||||
layers.traffic.inst = new AMap.TileLayer.Traffic({
|
||||
zIndex: 11,
|
||||
visible: layers.traffic.show,
|
||||
});
|
||||
|
||||
map.addLayer(layers.satellite.inst)
|
||||
map.addLayer(layers.roadNet.inst)
|
||||
map.addLayer(layers.traffic.inst)
|
||||
|
||||
}).catch(e => {
|
||||
$q.notify({
|
||||
position: "top",
|
||||
color: 'negative',
|
||||
message: "地图组件初始化失败",
|
||||
icon: 'report_problem'
|
||||
})
|
||||
console.log(e);
|
||||
})
|
||||
|
||||
function search() {
|
||||
console.log(date.value)
|
||||
let params = {
|
||||
startTime: !date.value.from ? undefined : moment(date.value.from).format("YYYY-MM-DD HH:mm:ss"),
|
||||
endTime: !date.value.to ? undefined : moment(date.value.to).format("YYYY-MM-DD HH:mm:ss"),
|
||||
}
|
||||
map.remove(data.polylines)
|
||||
map.remove(data.polyline)
|
||||
map.remove(data.labelsLayer)
|
||||
map.remove(data.markers)
|
||||
|
||||
let labelsLayer = new AMap.LabelsLayer({
|
||||
zooms: [3, 20],
|
||||
zIndex: 1000,
|
||||
// 该层内标注是否避让
|
||||
collision: true,
|
||||
// 设置 allowCollision:true,可以让标注避让用户的标注
|
||||
allowCollision: false,
|
||||
});
|
||||
data.labelsLayer = labelsLayer
|
||||
|
||||
fetch("http://10.10.10.100:6573/record/location/get", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(params)
|
||||
}).then(resp => resp.json()).then(res => {
|
||||
let _data = res.data || []
|
||||
_data = _data.map(item=>{
|
||||
return {
|
||||
time: moment(item.locationTime),
|
||||
...item,
|
||||
}
|
||||
})
|
||||
_data.sort((a,b)=>{
|
||||
return a.time.isBefore(b.time)?-1:1
|
||||
})
|
||||
data.data = _data
|
||||
console.log("data", _data)
|
||||
|
||||
data.tmpMarker = new AMap.Marker({
|
||||
anchor: 'bottom-center',
|
||||
offset: [0, -15],
|
||||
});
|
||||
let markers = _data.filter((_, index) => index % 1 === 0).map((item, index) => {
|
||||
let text = {
|
||||
fontSize: 10,
|
||||
content: `时间:${item.locationTime}<br>速度: ${((item.speed || 0) * 3.6).toFixed(2)}km/h 方向角: ${(item.bearing || 0).toFixed(2)}°`
|
||||
}
|
||||
|
||||
let marker = new AMap.LabelMarker({
|
||||
name: item.id,
|
||||
position: [item.longitude, item.latitude],
|
||||
zIndex: 10,
|
||||
icon: {
|
||||
// 图标类型,现阶段只支持 image 类型
|
||||
type: 'image',
|
||||
// 图片 url
|
||||
image: 'https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png',
|
||||
// 图片尺寸
|
||||
size: [6, 9],
|
||||
// 图片相对 position 的锚点,默认为 bottom-center
|
||||
anchor: 'bottom-center'
|
||||
},
|
||||
// text,
|
||||
})
|
||||
|
||||
marker.on('mouseover', (e) => {
|
||||
let position = e.data.data && e.data.data.position;
|
||||
|
||||
if (position) {
|
||||
data.tmpMarker.setContent(
|
||||
`<div class="amap-info-window"
|
||||
style="padding: .75rem 1.25rem;font-size:12px;
|
||||
margin-bottom: 1rem;
|
||||
border-radius: .25rem;
|
||||
position: fixed;
|
||||
top: 1rem;
|
||||
background-color: white;
|
||||
width: auto;
|
||||
min-width: 22rem;
|
||||
border-width: 0;
|
||||
right: 1rem;
|
||||
box-shadow: 0 2px 6px 0 rgba(114, 124, 245, .5);">`
|
||||
+ text.content +
|
||||
'<div class="amap-info-sharp"></div>' +
|
||||
'</div>');
|
||||
data.tmpMarker.setPosition(position);
|
||||
map.add(data.tmpMarker);
|
||||
}
|
||||
});
|
||||
|
||||
marker.on('mouseout', () => {
|
||||
map.remove(data.tmpMarker);
|
||||
});
|
||||
|
||||
return marker;
|
||||
})
|
||||
labelsLayer.add(markers)
|
||||
map.add(data.labelsLayer)
|
||||
|
||||
let days = []
|
||||
let prev = moment(0)
|
||||
for (let i = 0; i < _data.length; i++) {
|
||||
let datum = _data[i]
|
||||
|
||||
if (prev.year() === datum.time.year() && prev.month() === datum.time.month() && prev.date() === datum.time.date() ) {
|
||||
prev = datum.time
|
||||
} else {
|
||||
prev = datum.time
|
||||
days.push([])
|
||||
}
|
||||
days[days.length -1].push(datum)
|
||||
}
|
||||
|
||||
let colorList = Array.from({ length: days.length })
|
||||
.map(() => COLOR[Math.floor(Math.random() * COLOR.length)]);
|
||||
data.polylines = []
|
||||
days.forEach((_data,index) => {
|
||||
let path = _data.map((item) => {
|
||||
return new AMap.LngLat(item.longitude, item.latitude)
|
||||
})
|
||||
|
||||
let polyline = new AMap.Polyline({
|
||||
path: path,
|
||||
showDir: true,
|
||||
dirImg: canvasDir,
|
||||
borderWeight: 6, // 线条宽度,默认为 1
|
||||
strokeWeight: 6,
|
||||
strokeOpacity: 0.9, // 透明度
|
||||
strokeColor: colorList[index], // 线条颜色
|
||||
dirColor: 'white',
|
||||
lineJoin: 'round' // 折线拐点连接处样式})
|
||||
})
|
||||
data.polylines.push(polyline)
|
||||
})
|
||||
console.log("polylines",data.polylines)
|
||||
|
||||
if (data.polylines.length > 0) {
|
||||
map.panTo(data.polylines[0].getPath()[0])
|
||||
map.setFitView()
|
||||
}
|
||||
// polyline = new AMap.Polyline({
|
||||
// path: path,
|
||||
// showDir: true,
|
||||
// dirImg: canvasDir,
|
||||
// borderWeight: 6, // 线条宽度,默认为 1
|
||||
// strokeWeight: 6,
|
||||
// strokeColor: 'red', // 线条颜色
|
||||
// dirColor: 'white',
|
||||
// lineJoin: 'round' // 折线拐点连接处样式})
|
||||
// })
|
||||
map.add(data.polylines)
|
||||
|
||||
fixedLocation()
|
||||
})
|
||||
}
|
||||
|
||||
function fixedLocation() {
|
||||
map.remove(data.fixedPolyline)
|
||||
|
||||
if (!feature.showFixed) {
|
||||
return
|
||||
}
|
||||
|
||||
let task = []
|
||||
let startTime
|
||||
let preFixedData = (data.data || []).map((item, index) => {
|
||||
if (index % 500 === 0) {
|
||||
startTime = data.data[0].time
|
||||
}
|
||||
|
||||
let time = item.time
|
||||
return {
|
||||
x: item.longitude,
|
||||
y: item.latitude,
|
||||
sp: item.speed || 0,
|
||||
ag: item.bearing || 0,
|
||||
tm: index % 500 === 0 ? time.unix() : time.diff(startTime, 's')
|
||||
}
|
||||
})
|
||||
console.log("纠偏路线 预处理数据: ", preFixedData)
|
||||
|
||||
let group = []
|
||||
let len = preFixedData.length
|
||||
for (let i = 0; i < Math.ceil(len / 500); i++) {
|
||||
group.push(preFixedData.splice(0, 500))
|
||||
}
|
||||
console.log("分组: ", group)
|
||||
|
||||
task = group.map(item => {
|
||||
return new Promise(resolve => {
|
||||
AMap.plugin('AMap.GraspRoad', function () {
|
||||
let grasp = new AMap.GraspRoad();
|
||||
grasp.driving(item, function (error, result) {
|
||||
if (error) {
|
||||
resolve([])
|
||||
}
|
||||
if (!error) {
|
||||
let newPath = result.data.points;//纠偏后的轨迹
|
||||
let distance = result.data.distance;//里程
|
||||
|
||||
console.log("返回值 => ", "路径: ", newPath, "里程: ", distance)
|
||||
resolve(newPath)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Promise.all(task).then(paths => {
|
||||
let fixedData = paths.flat(1)
|
||||
console.log("纠偏路线数据: ", fixedData)
|
||||
|
||||
data.fixedPolyline = new AMap.Polyline({
|
||||
path: fixedData.map(item => {
|
||||
return new AMap.LngLat(item.x, item.y)
|
||||
}),
|
||||
showDir: true,
|
||||
strokeColor: 'orange', // 线条颜色
|
||||
borderWeight: 6, // 线条宽度,默认为 1
|
||||
strokeWeight: 6,
|
||||
})
|
||||
map.add(data.fixedPolyline)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
Loading…
Reference in New Issue
Block a user