Browse Source

异常状态排序

master
xh 11 hours ago
parent
commit
0cbabf8d9c
  1. 360
      web/public/map.html
  2. 2
      web/src/views/HandDevice/Home/components/constants/map.constants.ts
  3. 4
      web/src/views/HandDevice/Home/components/services/marker.service.ts
  4. 2
      web/src/views/HandDevice/Home/index.vue

360
web/public/map.html

@ -1,360 +0,0 @@
<!doctype html>
<html lang="zh">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>轨迹点实现</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol/ol.css" />
<style>
#map {
width: 100%;
height: 500px;
}
#controls {
padding: 10px;
background: #f5f5f5;
}
#info-panel {
padding: 10px;
background: white;
border: 1px solid #ddd;
}
.timeline {
display: flex;
overflow-x: auto;
padding: 10px 0;
}
.timeline-marker {
padding: 5px 10px;
margin: 0 5px;
background: #1890ff;
color: white;
border-radius: 3px;
cursor: pointer;
}
</style>
</head>
<body>
<div id="controls">
<button id="btn-play">播放轨迹</button>
<button id="btn-pause">暂停</button>
<div id="info-panel">轨迹信息将显示在这里</div>
</div>
<div id="map"></div>
<div class="timeline" id="timeline"></div>
<script src="https://unpkg.com/ol@9.2.4/dist/ol.js"></script>
<script>
// 轨迹数据(示例数据 - 北京到天津的轨迹)
const trackData = [
{ time: '09:00', lng: 116.404, lat: 39.915, speed: 60, name: '起点' },
{ time: '09:15', lng: 116.704, lat: 39.915, speed: 65, name: '大兴区' },
{ time: '09:30', lng: 116.904, lat: 39.815, speed: 70, name: '廊坊' },
{ time: '09:45', lng: 117.204, lat: 39.715, speed: 75, name: '武清区' },
{ time: '10:00', lng: 117.404, lat: 39.615, speed: 80, name: '天津市区' }
]
// 全局变量
let map, trackSource, trackPlayer
// 初始化地图
function initMap() {
const source = new ol.source.XYZ({
url: 'http://qtbj.icpcdev.site/roadmap/{z}/{x}/{y}.png',
maxZoom: 16,
minZoom: 10
})
map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: source
})
],
view: new ol.View({
center: ol.proj.fromLonLat([116.404, 39.915]),
zoom: 10
})
})
// 创建轨迹图层
trackSource = new ol.source.Vector()
const trackLayer = new ol.layer.Vector({
source: trackSource,
style: function (feature) {
const type = feature.get('type')
if (type === 'track-line') {
return new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#1890FF',
width: 4,
lineDash: [5, 5]
})
})
} else if (type === 'track-point') {
const speed = feature.get('speed')
return new ol.style.Style({
image: new ol.style.Circle({
radius: 6,
fill: new ol.style.Fill({
color: speed > 70 ? '#FF4D4F' : '#52C41A'
}),
stroke: new ol.style.Stroke({
color: 'white',
width: 2
})
}),
text: new ol.style.Text({
text: feature.get('name') || feature.get('time'),
offsetY: -15,
fill: new ol.style.Fill({ color: '#000' }),
stroke: new ol.style.Stroke({ color: '#fff', width: 3 })
})
})
} else if (type === 'moving-point') {
return new ol.style.Style({
image: new ol.style.Circle({
radius: 10,
fill: new ol.style.Fill({ color: '#FAAD14' }),
stroke: new ol.style.Stroke({
color: 'white',
width: 3
})
})
})
}
}
})
map.addLayer(trackLayer)
}
// 轨迹播放器类
class TrackPlayer {
constructor(trackData, source, map) {
this.trackData = trackData
this.source = source
this.map = map
this.currentIndex = 0
this.isPlaying = false
this.animationId = null
this.movingPoint = null
this.initMovingPoint()
this.createTimeline()
}
// 初始化移动点
initMovingPoint() {
this.movingPoint = new ol.Feature({
geometry: new ol.geom.Point(
ol.proj.fromLonLat([this.trackData[0].lng, this.trackData[0].lat])
),
type: 'moving-point'
})
this.source.addFeature(this.movingPoint)
}
// 创建时间轴
createTimeline() {
const timeline = document.getElementById('timeline')
timeline.innerHTML = ''
this.trackData.forEach((point, index) => {
const pointElement = document.createElement('div')
pointElement.className = 'timeline-point'
pointElement.innerHTML = `
<div>${point.time}</div>
<div>${point.name}</div>
`
pointElement.addEventListener('click', () => {
this.jumpToPoint(index)
})
timeline.appendChild(pointElement)
})
}
// 播放轨迹
play() {
if (this.isPlaying) return
this.isPlaying = true
this.currentIndex = 0
this.updateTimeline()
this.animate()
}
// 暂停播放
pause() {
this.isPlaying = false
if (this.animationId) {
cancelAnimationFrame(this.animationId)
}
}
// 跳转到指定点
jumpToPoint(index) {
this.pause()
this.currentIndex = Math.max(0, Math.min(index, this.trackData.length - 1))
this.updateMovingPoint()
this.updateTimeline()
}
// 动画循环
animate() {
if (!this.isPlaying || this.currentIndex >= this.trackData.length - 1) {
this.isPlaying = false
this.updateInfo('轨迹播放完成')
return
}
const start = this.trackData[this.currentIndex]
const end = this.trackData[this.currentIndex + 1]
this.moveToNextPoint(start, end, 0, 1500) // 1.5秒移动到下一点
}
// 移动到下一点
moveToNextPoint(start, end, progress, duration) {
if (!this.isPlaying) return
if (progress >= 1) {
this.currentIndex++
this.updateTimeline()
this.animate()
return
}
// 计算插值坐标
const lng = start.lng + (end.lng - start.lng) * progress
const lat = start.lat + (end.lat - start.lat) * progress
// 更新移动点位置
this.movingPoint.getGeometry().setCoordinates(ol.proj.fromLonLat([lng, lat]))
// 更新信息面板
this.updateInfo(end, progress)
// 平滑跟随移动点
if (progress > 0.3) {
// 延迟一点开始跟随
this.map.getView().animate({
center: ol.proj.fromLonLat([lng, lat]),
duration: 200,
easing: ol.easing.linear
})
}
// 继续动画
progress += 16 / duration // 基于60fps
this.animationId = requestAnimationFrame(() => {
this.moveToNextPoint(start, end, progress, duration)
})
}
// 更新移动点位置(直接跳转)
updateMovingPoint() {
const point = this.trackData[this.currentIndex]
this.movingPoint.getGeometry().setCoordinates(ol.proj.fromLonLat([point.lng, point.lat]))
this.map.getView().animate({
center: ol.proj.fromLonLat([point.lng, point.lat]),
zoom: 14,
duration: 500
})
}
// 更新信息面板
updateInfo(point, progress) {
const progressText = progress ? `进度: ${Math.round(progress * 100)}%` : ''
document.getElementById('info-panel').innerHTML = `
<div><strong>当前位置:</strong> ${point.name}</div>
<div><strong>时间:</strong> ${point.time}</div>
<div><strong>速度:</strong> ${point.speed} km/h</div>
<div><strong>${progressText}</strong></div>
`
}
// 更新时间轴高亮
updateTimeline() {
const points = document.querySelectorAll('.timeline-point')
points.forEach((point, index) => {
point.classList.toggle('active', index === this.currentIndex)
})
}
// 重置轨迹
reset() {
this.pause()
this.currentIndex = 0
this.updateMovingPoint()
this.updateTimeline()
this.updateInfo(this.trackData[0], 0)
}
}
// 添加轨迹到地图
function addTrackToMap() {
// 清空现有轨迹
trackSource.clear()
// 添加轨迹点
trackData.forEach((point, index) => {
const feature = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.fromLonLat([point.lng, point.lat])),
type: 'track-point',
time: point.time,
speed: point.speed,
name: point.name,
index: index
})
trackSource.addFeature(feature)
})
// 添加轨迹线
const lineCoords = trackData.map((p) => ol.proj.fromLonLat([p.lng, p.lat]))
const lineFeature = new ol.Feature({
geometry: new ol.geom.LineString(lineCoords),
type: 'track-line'
})
trackSource.addFeature(lineFeature)
// 自适应缩放
const extent = trackSource.getExtent()
map.getView().fit(extent, {
padding: [50, 50, 50, 50],
duration: 1000
})
// 初始化播放器
trackPlayer = new TrackPlayer(trackData, trackSource, map)
}
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', function () {
// 初始化地图
initMap()
// 绑定按钮事件
// document.getElementById('btn-add-track').addEventListener('click', addTrackToMap);
document.getElementById('btn-play').addEventListener('click', function () {
if (trackPlayer) trackPlayer.play()
})
// document.getElementById('btn-play')
// document.getElementById('btn-pause').addEventListener('click', function() {
// if (trackPlayer) trackPlayer.pause();
// });
// document.getElementById('btn-reset').addEventListener('click', function() {
// if (trackPlayer) trackPlayer.reset();
// });
// document.getElementById('btn-clear').addEventListener('click', function() {
// trackSource.clear();
// document.getElementById('timeline').innerHTML = '';
// document.getElementById('info-panel').innerHTML = '轨迹已清空';
// });
// trackPlayer.play();
// 页面加载后自动添加示例轨迹
setTimeout(addTrackToMap, 1500)
})
</script>
</body>
</html>

2
web/src/views/HandDevice/Home/components/constants/map.constants.ts

@ -21,7 +21,7 @@ export const STATUS_DICT = {
] as StatusDictItem[],
fenceStatus: [
{ value: '0', label: '正常', cssClass: '#67c23a' },
{ value: '1', label: '一级围栏报警', cssClass: '#e6a23c' }
{ value: '1', label: '围栏报警', cssClass: '#e6a23c' }
// { value: '2', label: '二级围栏报警', cssClass: '#f56c6c' }
] as StatusDictItem[]
}

4
web/src/views/HandDevice/Home/components/services/marker.service.ts

@ -125,8 +125,8 @@ export class MarkerService {
renderOrder: (a, b) => {
// console.log('renderOrder',a,b.get('markerData').time);
// 按xxx属性降序排列
return a.get('markerData').statusPriority - b.get('markerData').statusPriority
// 按xxx属性排列
return b.get('markerData').statusPriority - a.get('markerData').statusPriority
}
})
}

2
web/src/views/HandDevice/Home/index.vue

@ -154,7 +154,7 @@ const getMarkers = async () => {
statusLabel: getStatusLabel(statusStr), //
statusPriority: getStatusPriority(statusStr), //,
}
})
}).sort((a,b) => a.statusPriority - b.statusPriority)
markers.value = res2
})
}

Loading…
Cancel
Save