mirror of
https://github.com/eatfishfish/openpilot-server.git
synced 2026-08-22 04:42:32 +00:00
增加远程、本地查看摄像头功能
This commit is contained in:
+630
-273
@@ -1,273 +1,630 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head><meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
|
||||
<title>Route replay</title>
|
||||
<link rel="stylesheet" href="https://a.amap.com/jsapi_demos/static/demo-center/css/demo-center.css"/>
|
||||
<style>
|
||||
html,
|
||||
body,
|
||||
#container {
|
||||
height: 100%;width: 100%;font-family: "微软雅黑";
|
||||
}
|
||||
.input-card .btn {margin-right: 1.2rem;width: 9rem;}
|
||||
.input-card .btn:last-child {margin-right: 0;}
|
||||
.amap-marker-label{border: 0;background-color: transparent;}
|
||||
.amap-marker-content img {width: 25px;height: 34px;}
|
||||
.info {position: relative;top: 0;right: 0;min-width: 0;font-size: 16px;border: 1px solid rgb(204, 204, 204);}
|
||||
</style></head><body>
|
||||
|
||||
|
||||
<div id="container"></div>
|
||||
<div class="input-card">
|
||||
<div class="input-item">
|
||||
<input type="date" style="direction: rtl" onchange="onDataChange()" id="myTime"/>
|
||||
</div>
|
||||
<div class="input-item">
|
||||
<input type="button" class="btn" value="开始动画" id="start" onclick="startAnimation()"/>
|
||||
<input type="button" class="btn" value="暂停动画" id="pause" onclick="pauseAnimation()"/>
|
||||
</div>
|
||||
<!--<div class="input-item">
|
||||
<input type="button" class="btn" value="继续动画" id="resume" onclick="resumeAnimation()"/>
|
||||
<input type="button" class="btn" value="停止动画" id="stop" onclick="stopAnimation()"/>
|
||||
</div>-->
|
||||
<div class="input-item">
|
||||
<input type="button" class="btn" value="显示时间" id="showDate" onclick="showDate()"/>
|
||||
<input type="button" class="btn" value="隐藏时间" id="hideDate" onclick="hideDate()"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key=6a5cbc4029bcee01691fab072982280f&plugin=AMap.Driving"></script>
|
||||
|
||||
<script>
|
||||
document.getElementById("myTime").value= '_DATE_';
|
||||
|
||||
function onDataChange() {
|
||||
var oTimer = document.getElementById("myTime");
|
||||
var value = oTimer.value;
|
||||
dongleid = localStorage.getItem("dongleId");
|
||||
window.location= "/replaygps/"+dongleid+"/"+value;
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
//只要起点 和 终点的 经纬度信息
|
||||
var allData = '_GPS_DATA_';
|
||||
var lineArr;
|
||||
var polyline;
|
||||
var passedPolyline;
|
||||
//全部的点
|
||||
var path = [];
|
||||
//是否显示时间
|
||||
var showStatus = true;
|
||||
//途经点
|
||||
var wayMarker;
|
||||
//初始化中心坐标
|
||||
var centerGPS = _GPS_CENTER_;
|
||||
//途经点数组。方便清空数据
|
||||
var wayMarkerArray = new Array();
|
||||
var carStart, carEnd;
|
||||
//创建地图。中心点、缩放等级
|
||||
var map = new AMap.Map("container", {
|
||||
resizeEnable: true,
|
||||
center: [centerGPS[0], centerGPS[1]],
|
||||
zoom: 17
|
||||
});
|
||||
//驾车策略基础信息
|
||||
var drivingOption = {
|
||||
policy: AMap.DrivingPolicy.LEAST_DISTANCE,
|
||||
ferry: 1,
|
||||
}
|
||||
var gpsData = JSON.parse(allData)
|
||||
var rowLength = gpsData.data.rows.length;
|
||||
var gpsLength = gpsData.data.rows[rowLength - 1].gpsInfos.length;
|
||||
for(var i=0;i<rowLength;i++){
|
||||
wayMarkerArray[i] = new Array();
|
||||
}
|
||||
|
||||
//添加小汽车
|
||||
carStart = [gpsData.data.rows[0].gpsInfos[0].longitude, gpsData.data.rows[0].gpsInfos[0].latitude]
|
||||
carEnd = [gpsData.data.rows[rowLength - 1].gpsInfos[gpsLength - 1].longitude, gpsData.data.rows[rowLength - 1].gpsInfos[gpsLength - 1].latitude]
|
||||
addCar('');
|
||||
|
||||
for (var i = 0; i < rowLength; i++) {
|
||||
getRoute(i);
|
||||
}
|
||||
|
||||
function getRoute(i) {
|
||||
var data = gpsData.data.rows[i];
|
||||
addMarker(i);
|
||||
pts = getWayPoints(data.gpsInfos);
|
||||
drawTrack(pts);
|
||||
drawPassedPolyLine();
|
||||
lineArr = pts;
|
||||
return
|
||||
}
|
||||
|
||||
function getWayPoints(coords) {
|
||||
var GPS = new Array();
|
||||
if (coords.length > 1) {
|
||||
//不要第一个和最后一个,会导致起点终点图标被覆盖
|
||||
for (var i = 1; i < coords.length - 1; i++) {
|
||||
var wayPoint = coords[i];
|
||||
var wayPointGPS = new AMap.LngLat(wayPoint.longitude, wayPoint.latitude)
|
||||
GPS.push(wayPointGPS);
|
||||
}
|
||||
}
|
||||
return GPS;
|
||||
}
|
||||
|
||||
// 绘制轨迹
|
||||
function drawTrack(path) {
|
||||
color = "#"+parseInt(Math.random()*65536).toString(16)+ "5b"
|
||||
polyline = new AMap.Polyline({
|
||||
map: map,
|
||||
path: path,
|
||||
showDir: true,
|
||||
strokeColor: color,//"#18a45b", //线颜色
|
||||
strokeWeight: 6, //线宽
|
||||
});
|
||||
}
|
||||
|
||||
// 绘制运动轨迹样式
|
||||
function drawPassedPolyLine() {
|
||||
passedPolyline = new AMap.Polyline({
|
||||
map: map,
|
||||
strokeColor: "#AF5", //线颜色
|
||||
strokeWeight: 6, //线宽
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
增加轨迹回放的小汽车和车牌
|
||||
@param plate - 车牌
|
||||
*/
|
||||
function addCar(plate) {
|
||||
if (plate == "")
|
||||
{
|
||||
marker = new AMap.Marker({
|
||||
map: map,
|
||||
zIndex: 9999,
|
||||
position: [carStart[0], carStart[1]],
|
||||
icon: "https://lbsyun.baidu.com/jsdemo/img/car.png",
|
||||
offset: new AMap.Pixel(-26, -13),
|
||||
autoRotation: true,
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
marker = new AMap.Marker({
|
||||
map: map,
|
||||
zIndex: 9999,
|
||||
position: [carStart[0], carStart[1]],
|
||||
icon: "https://lbsyun.baidu.com/jsdemo/img/car.png",
|
||||
offset: new AMap.Pixel(-26, -13),
|
||||
autoRotation: true,
|
||||
label: {
|
||||
content: "<div class='info'>" + plate + "</div>",
|
||||
offset: new AMap.Pixel(-26, -35),
|
||||
autoRotation: true
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 显示时间
|
||||
function showDate() {
|
||||
showStatus = true;
|
||||
for (var i = 0; i < rowLength; i++) {
|
||||
addMarker(i);
|
||||
}
|
||||
}
|
||||
|
||||
// 隐藏时间
|
||||
function hideDate() {
|
||||
showStatus = false;
|
||||
for (var i = 0; i < rowLength; i++) {
|
||||
addMarker(i);
|
||||
}
|
||||
}
|
||||
|
||||
// 实例化点标记
|
||||
function addMarker(i) {
|
||||
if (null != wayMarker) {
|
||||
wayMarkerArray[i].forEach(function (wayMarkerPoint) {
|
||||
wayMarkerPoint.setMap(null);
|
||||
})
|
||||
wayMarkerArray[i] = new Array();
|
||||
}
|
||||
|
||||
var data = gpsData.data.rows[i];
|
||||
for (var j = 0; j < data.gpsInfos.length; j++) {
|
||||
var gpsInfo = data.gpsInfos[j];
|
||||
wayMarker = new AMap.Marker({
|
||||
map: map,
|
||||
position: [gpsInfo.longitude, gpsInfo.latitude],
|
||||
offset: new AMap.Pixel(-13, -30)
|
||||
});
|
||||
|
||||
if (showStatus) {
|
||||
wayMarker.setLabel({
|
||||
offset: new AMap.Pixel(20, 20), //设置文本标注偏移量
|
||||
content: "<div class='info'>" + gpsInfo.create_time + "</div>", //设置文本标注内容
|
||||
direction: 'right' //设置文本标注方位
|
||||
});
|
||||
}
|
||||
wayMarkerArray[i].push(wayMarker);
|
||||
}
|
||||
}
|
||||
|
||||
/**********起点ICON**********/
|
||||
var startMarker = new AMap.Marker({
|
||||
position: carStart,
|
||||
icon: 'https://webapi.amap.com/theme/v1.3/markers/n/start.png',
|
||||
map: map
|
||||
})
|
||||
/**********终点ICON**********/
|
||||
var endMarker = new AMap.Marker({
|
||||
position: carEnd,
|
||||
icon: 'https://webapi.amap.com/theme/v1.3/markers/n/end.png',
|
||||
map: map
|
||||
})
|
||||
|
||||
// 调整视野达到最佳显示区域
|
||||
map.setFitView([startMarker, endMarker])
|
||||
|
||||
marker.on('moving', function (e) {
|
||||
passedPolyline.setPath(e.passedPath);
|
||||
});
|
||||
|
||||
/**********动画 START**********/
|
||||
function startAnimation() {
|
||||
marker.moveAlong(lineArr, 992);
|
||||
}
|
||||
|
||||
function pauseAnimation() {
|
||||
marker.pauseMove();
|
||||
}
|
||||
|
||||
function resumeAnimation() {
|
||||
marker.resumeMove();
|
||||
}
|
||||
|
||||
function stopAnimation() {
|
||||
marker.stopMove();
|
||||
}
|
||||
|
||||
/**********动画 END**********/
|
||||
|
||||
// 解析DrivingRoute对象,构造成AMap.Polyline的path参数需要的格式
|
||||
function parseRouteToPath(route, type) {
|
||||
for (var i = 0, l = route.steps.length; i < l; i++) {
|
||||
var step = route.steps[i]
|
||||
|
||||
for (var j = 0, n = step.path.length; j < n; j++) {
|
||||
path.push(step.path[j])
|
||||
}
|
||||
}
|
||||
return path
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head><meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
|
||||
<title>Route replay</title>
|
||||
<link rel="stylesheet" href="https://a.amap.com/jsapi_demos/static/demo-center/css/demo-center.css"/>
|
||||
<style>
|
||||
html,
|
||||
body,
|
||||
#container {
|
||||
height: 100%;width: 100%;font-family: "微软雅黑";
|
||||
}
|
||||
.input-card {width: auto;min-width: 0;padding: .45rem .55rem;display: grid;grid-template-columns: 9.2rem 14.2rem 3.8rem 5rem;align-items: center;gap: .35rem;white-space: nowrap;}
|
||||
.input-card .input-item {height: auto;margin: 0;display: flex;align-items: center;gap: .25rem;min-width: 0;}
|
||||
.input-card .btn {margin-right: 0;width: auto;min-width: 3.2rem;padding: 0 .35rem;height: 2.25rem;line-height: 2.25rem;}
|
||||
.input-card .btn:last-child {margin-right: 0;}
|
||||
#myTime {width: 9rem;height: 2.25rem;box-sizing: border-box;padding: 0 .25rem;line-height: normal;}
|
||||
#tripSelect {width: 14rem;height: 2.25rem;box-sizing: border-box;min-width: 0;padding: .25rem 1.75rem .25rem .35rem;line-height: normal;}
|
||||
.amap-marker-label{border: 0;background-color: transparent;}
|
||||
.amap-marker-content img {width: 25px;height: 34px;}
|
||||
.info {position: relative;top: 0;right: 0;min-width: 0;font-size: 16px;border: 1px solid rgb(204, 204, 204);white-space: nowrap;padding: 0 4px;}
|
||||
#carGpsTip {position: fixed;left: calc(50% + 18px);top: calc(50% - 34px);z-index: 10000;display: none;white-space: nowrap;font-size: 16px;border: 1px solid rgb(204, 204, 204);background: #fff;padding: 0 4px;pointer-events: none;}
|
||||
#loadStatus {position: fixed;left: 50%;top: 1rem;transform: translateX(-50%);z-index: 10001;padding: .35rem .65rem;background: rgba(255,255,255,.94);border: 1px solid #ccc;font-size: 13px;white-space: nowrap;}
|
||||
@media (max-width: 760px) {
|
||||
.input-card {max-width: calc(100% - 1rem);grid-template-columns: 8rem 10rem 3.2rem 4.5rem;gap: .25rem;overflow-x: auto;}
|
||||
.input-card .btn {min-width: 2.8rem;padding: 0 .25rem;font-size: 12px;}
|
||||
#myTime {width: 7.8rem;font-size: 12px;}
|
||||
#tripSelect {width: 9.8rem;font-size: 12px;}
|
||||
}
|
||||
</style></head><body>
|
||||
|
||||
|
||||
<div id="container"></div>
|
||||
<div id="carGpsTip"></div>
|
||||
<div id="loadStatus">GPS数据加载中...</div>
|
||||
<div class="input-card">
|
||||
<div class="input-item">
|
||||
<input type="date" style="direction: rtl" onchange="onDataChange()" id="myTime"/>
|
||||
</div>
|
||||
<div class="input-item">
|
||||
<select id="tripSelect" onchange="selectTrip(this.value)"></select>
|
||||
</div>
|
||||
<div class="input-item">
|
||||
<input type="button" class="btn" value="播放" id="playToggle" onclick="toggleAnimation()"/>
|
||||
</div>
|
||||
<div class="input-item">
|
||||
<input type="button" class="btn" value="隐藏GPS" id="gpsToggle" onclick="toggleGpsPoints()"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key=6a5cbc4029bcee01691fab072982280f&plugin=AMap.Driving"></script>
|
||||
|
||||
<script>
|
||||
document.getElementById("myTime").value= '_DATE_';
|
||||
var replayDongleId = '_DONGLE_ID_';
|
||||
|
||||
function onDataChange() {
|
||||
var oTimer = document.getElementById("myTime");
|
||||
var value = oTimer.value;
|
||||
var dongleid = replayDongleId || localStorage.getItem("dongleId");
|
||||
window.location= "/replaygps/"+dongleid+"/"+value;
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
var lineArr = [];
|
||||
var passedPolyline;
|
||||
var tripPolylines = [];
|
||||
var marker;
|
||||
var startMarker;
|
||||
var endMarker;
|
||||
var selectedTripIndex = 0;
|
||||
var showPointStatus = true;
|
||||
var animationPlaying = false;
|
||||
var currentGpsPointIndex = -1;
|
||||
var currentGpsLabelMarker;
|
||||
var currentTimeLabel;
|
||||
var wayMarkerArray = new Array();
|
||||
var tripPaths = [];
|
||||
var rows = [];
|
||||
var gpsRenderVersion = 0;
|
||||
|
||||
var map = new AMap.Map("container", {
|
||||
resizeEnable: true,
|
||||
center: [114.03, 22.54],
|
||||
zoom: 17
|
||||
});
|
||||
|
||||
loadGpsData();
|
||||
|
||||
async function loadGpsData() {
|
||||
setControlsDisabled(true);
|
||||
setLoadStatus("GPS数据加载中...");
|
||||
try {
|
||||
var date = document.getElementById("myTime").value;
|
||||
var url = "/replaygpsdata/" + encodeURIComponent(replayDongleId) + "/" + encodeURIComponent(date);
|
||||
var response = await fetch(url, {cache: "no-store"});
|
||||
if (!response.ok) {
|
||||
throw new Error("GPS数据加载失败");
|
||||
}
|
||||
|
||||
var gpsData = await response.json();
|
||||
rows = gpsData.data && gpsData.data.rows ? gpsData.data.rows : [];
|
||||
if (gpsData.date) {
|
||||
document.getElementById("myTime").value = gpsData.date;
|
||||
}
|
||||
if (rows.length === 0) {
|
||||
setLoadStatus("当天没有GPS数据");
|
||||
return;
|
||||
}
|
||||
|
||||
var firstPoint = rows[0].gpsInfos && rows[0].gpsInfos[0];
|
||||
if (firstPoint) {
|
||||
map.setCenter([firstPoint.longitude, firstPoint.latitude]);
|
||||
}
|
||||
|
||||
setLoadStatus("正在生成行程...");
|
||||
await buildTripPaths();
|
||||
initTripSelect();
|
||||
drawPassedPolyLine();
|
||||
await drawAllTrips();
|
||||
selectTrip(0);
|
||||
setLoadStatus("");
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
setLoadStatus(error.message || "GPS数据加载失败");
|
||||
} finally {
|
||||
setControlsDisabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
function setControlsDisabled(disabled) {
|
||||
document.getElementById("tripSelect").disabled = disabled;
|
||||
document.getElementById("playToggle").disabled = disabled;
|
||||
document.getElementById("gpsToggle").disabled = disabled;
|
||||
}
|
||||
|
||||
function setLoadStatus(text) {
|
||||
var status = document.getElementById("loadStatus");
|
||||
status.innerText = text;
|
||||
status.style.display = text ? "block" : "none";
|
||||
}
|
||||
|
||||
function nextFrame() {
|
||||
return new Promise(function (resolve) {
|
||||
requestAnimationFrame(resolve);
|
||||
});
|
||||
}
|
||||
|
||||
async function buildTripPaths() {
|
||||
var processed = 0;
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
var points = rows[i].gpsInfos || [];
|
||||
var path = [];
|
||||
for (var j = 0; j < points.length; j++) {
|
||||
path.push(new AMap.LngLat(points[j].longitude, points[j].latitude));
|
||||
processed++;
|
||||
if (processed % 1000 === 0) {
|
||||
await nextFrame();
|
||||
}
|
||||
}
|
||||
tripPaths.push(path);
|
||||
}
|
||||
}
|
||||
|
||||
function initTripSelect() {
|
||||
var select = document.getElementById("tripSelect");
|
||||
select.innerHTML = "";
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
var option = document.createElement("option");
|
||||
option.value = i;
|
||||
option.text = rows[i].pointDay;
|
||||
select.appendChild(option);
|
||||
}
|
||||
}
|
||||
|
||||
async function drawAllTrips() {
|
||||
for (var i = 0; i < tripPaths.length; i++) {
|
||||
if (tripPaths[i].length < 2) {
|
||||
tripPolylines[i] = null;
|
||||
continue;
|
||||
}
|
||||
setLoadStatus("正在绘制行程 " + (i + 1) + "/" + tripPaths.length);
|
||||
await drawTripSegments(i, tripPaths[i], rows[i].gpsInfos || []);
|
||||
}
|
||||
}
|
||||
|
||||
async function drawTripSegments(tripIndex, path, points) {
|
||||
var base = new AMap.Polyline({
|
||||
map: map,
|
||||
path: path,
|
||||
strokeColor: getTripColor(tripIndex),
|
||||
strokeOpacity: tripIndex === selectedTripIndex ? 1 : 0.55,
|
||||
strokeWeight: tripIndex === selectedTripIndex ? 16 : 11,
|
||||
zIndex: 40
|
||||
});
|
||||
var speeds = [];
|
||||
for (var i = 1; i < path.length; i++) {
|
||||
var segPoints = [path[i - 1], path[i]];
|
||||
var speed = getSegmentSpeed(points[i - 1], points[i]);
|
||||
var speedSegment = new AMap.Polyline({
|
||||
map: map,
|
||||
path: segPoints,
|
||||
showDir: true,
|
||||
strokeColor: getSpeedColor(speed),
|
||||
strokeOpacity: tripIndex === selectedTripIndex ? 1 : 0.45,
|
||||
strokeWeight: tripIndex === selectedTripIndex ? 6 : 3,
|
||||
zIndex: 50
|
||||
});
|
||||
speeds.push(speedSegment);
|
||||
if (i % 200 === 0) {
|
||||
await nextFrame();
|
||||
}
|
||||
}
|
||||
tripPolylines[tripIndex] = {base: base, speeds: speeds};
|
||||
}
|
||||
|
||||
function selectTrip(index) {
|
||||
selectedTripIndex = parseInt(index, 10) || 0;
|
||||
if (!rows[selectedTripIndex] || tripPaths[selectedTripIndex].length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
stopAnimation();
|
||||
setAnimationPlaying(false);
|
||||
lineArr = tripPaths[selectedTripIndex];
|
||||
setTripHighlight();
|
||||
resetCar();
|
||||
resetStartEndMarkers();
|
||||
renderGpsPoints();
|
||||
currentGpsPointIndex = -1;
|
||||
clearCurrentTimeLabel();
|
||||
hideCarGpsTip();
|
||||
passedPolyline.setPath([]);
|
||||
var fitItems = [];
|
||||
var tripLines = tripPolylines[selectedTripIndex];
|
||||
if (tripLines) {
|
||||
fitItems.push(tripLines.base);
|
||||
for (var i = 0; i < tripLines.speeds.length; i++) {
|
||||
fitItems.push(tripLines.speeds[i]);
|
||||
}
|
||||
}
|
||||
fitItems.push(startMarker);
|
||||
fitItems.push(endMarker);
|
||||
map.setFitView(fitItems);
|
||||
}
|
||||
|
||||
function setTripHighlight() {
|
||||
for (var i = 0; i < tripPolylines.length; i++) {
|
||||
var tripLines = tripPolylines[i];
|
||||
if (!tripLines) {
|
||||
continue;
|
||||
}
|
||||
tripLines.base.setOptions({
|
||||
strokeOpacity: i === selectedTripIndex ? 1 : 0.55,
|
||||
strokeWeight: i === selectedTripIndex ? 16 : 11
|
||||
});
|
||||
for (var j = 0; j < tripLines.speeds.length; j++) {
|
||||
tripLines.speeds[j].setOptions({
|
||||
strokeOpacity: i === selectedTripIndex ? 1 : 0.45,
|
||||
strokeWeight: i === selectedTripIndex ? 6 : 3
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetCar() {
|
||||
if (marker) {
|
||||
marker.setMap(null);
|
||||
}
|
||||
marker = new AMap.Marker({
|
||||
map: map,
|
||||
zIndex: 9999,
|
||||
position: lineArr[0],
|
||||
icon: "https://lbsyun.baidu.com/jsdemo/img/car.png",
|
||||
offset: new AMap.Pixel(-26, -13),
|
||||
autoRotation: true
|
||||
});
|
||||
marker.on('moving', function (e) {
|
||||
passedPolyline.setPath(e.passedPath);
|
||||
focusMapOnCar();
|
||||
showCurrentGpsTime();
|
||||
});
|
||||
}
|
||||
|
||||
function resetStartEndMarkers() {
|
||||
if (startMarker) {
|
||||
startMarker.setMap(null);
|
||||
}
|
||||
if (endMarker) {
|
||||
endMarker.setMap(null);
|
||||
}
|
||||
|
||||
startMarker = new AMap.Marker({
|
||||
position: lineArr[0],
|
||||
icon: 'https://webapi.amap.com/theme/v1.3/markers/n/start.png',
|
||||
map: map
|
||||
});
|
||||
endMarker = new AMap.Marker({
|
||||
position: lineArr[lineArr.length - 1],
|
||||
icon: 'https://webapi.amap.com/theme/v1.3/markers/n/end.png',
|
||||
map: map
|
||||
});
|
||||
}
|
||||
|
||||
function drawPassedPolyLine() {
|
||||
passedPolyline = new AMap.Polyline({
|
||||
map: map,
|
||||
strokeColor: "#2b7fff",
|
||||
strokeWeight: 6
|
||||
});
|
||||
}
|
||||
|
||||
function showGpsPoints() {
|
||||
showPointStatus = true;
|
||||
updateGpsToggleText();
|
||||
hideCarGpsTip();
|
||||
renderGpsPoints();
|
||||
if (animationPlaying) {
|
||||
currentGpsPointIndex = -1;
|
||||
showCurrentGpsTime();
|
||||
}
|
||||
}
|
||||
|
||||
function hideGpsPoints() {
|
||||
showPointStatus = false;
|
||||
currentGpsPointIndex = -1;
|
||||
updateGpsToggleText();
|
||||
renderGpsPoints();
|
||||
if (animationPlaying) {
|
||||
currentGpsPointIndex = -1;
|
||||
showCurrentGpsTime();
|
||||
}
|
||||
}
|
||||
|
||||
function toggleGpsPoints() {
|
||||
if (showPointStatus) {
|
||||
hideGpsPoints();
|
||||
} else {
|
||||
showGpsPoints();
|
||||
}
|
||||
}
|
||||
|
||||
function updateGpsToggleText() {
|
||||
var button = document.getElementById("gpsToggle");
|
||||
if (button) {
|
||||
button.value = showPointStatus ? "隐藏GPS" : "显示GPS";
|
||||
}
|
||||
}
|
||||
|
||||
function clearGpsPoints() {
|
||||
gpsRenderVersion++;
|
||||
currentGpsLabelMarker = null;
|
||||
wayMarkerArray.forEach(function (wayMarkerPoint) {
|
||||
wayMarkerPoint.setMap(null);
|
||||
});
|
||||
wayMarkerArray = new Array();
|
||||
}
|
||||
|
||||
async function renderGpsPoints() {
|
||||
clearGpsPoints();
|
||||
currentGpsPointIndex = -1;
|
||||
if (!showPointStatus || !rows[selectedTripIndex]) {
|
||||
return;
|
||||
}
|
||||
|
||||
var renderVersion = gpsRenderVersion;
|
||||
var data = rows[selectedTripIndex];
|
||||
for (var j = 0; j < data.gpsInfos.length; j++) {
|
||||
if (renderVersion !== gpsRenderVersion || !showPointStatus) {
|
||||
return;
|
||||
}
|
||||
var gpsInfo = data.gpsInfos[j];
|
||||
var wayMarker = new AMap.Marker({
|
||||
map: map,
|
||||
position: [gpsInfo.longitude, gpsInfo.latitude],
|
||||
offset: new AMap.Pixel(-13, -30)
|
||||
});
|
||||
wayMarkerArray.push(wayMarker);
|
||||
if (animationPlaying && showPointStatus && j === currentGpsPointIndex) {
|
||||
currentGpsPointIndex = -1;
|
||||
showCurrentGpsTime(j);
|
||||
}
|
||||
if ((j + 1) % 100 === 0) {
|
||||
await nextFrame();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function startAnimation() {
|
||||
if (marker && lineArr.length > 1) {
|
||||
setAnimationPlaying(true);
|
||||
if (showPointStatus && wayMarkerArray.length === 0) {
|
||||
renderGpsPoints();
|
||||
}
|
||||
focusMapOnCar();
|
||||
showCurrentGpsTime(0);
|
||||
marker.moveAlong(lineArr, 99200);
|
||||
}
|
||||
}
|
||||
|
||||
function pauseAnimation() {
|
||||
if (marker) {
|
||||
marker.pauseMove();
|
||||
setAnimationPlaying(false);
|
||||
hideCarGpsTip();
|
||||
}
|
||||
}
|
||||
|
||||
function toggleAnimation() {
|
||||
if (animationPlaying) {
|
||||
pauseAnimation();
|
||||
} else {
|
||||
startAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
function setAnimationPlaying(isPlaying) {
|
||||
animationPlaying = isPlaying;
|
||||
var button = document.getElementById("playToggle");
|
||||
if (button) {
|
||||
button.value = animationPlaying ? "暂停" : "播放";
|
||||
}
|
||||
}
|
||||
|
||||
function resumeAnimation() {
|
||||
if (marker) {
|
||||
marker.resumeMove();
|
||||
}
|
||||
}
|
||||
|
||||
function stopAnimation() {
|
||||
if (marker) {
|
||||
marker.stopMove();
|
||||
}
|
||||
setAnimationPlaying(false);
|
||||
hideCarGpsTip();
|
||||
}
|
||||
|
||||
function focusMapOnCar() {
|
||||
if (!marker) {
|
||||
return;
|
||||
}
|
||||
|
||||
var position = marker.getPosition();
|
||||
if (position) {
|
||||
map.setCenter(position);
|
||||
}
|
||||
}
|
||||
|
||||
function showCurrentGpsTime(forceIndex) {
|
||||
if (!rows[selectedTripIndex]) {
|
||||
return;
|
||||
}
|
||||
|
||||
var index = typeof forceIndex === "number" ? forceIndex : getNearestGpsPointIndex(marker.getPosition());
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
if (showPointStatus && index === currentGpsPointIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
clearGpsPointLabels();
|
||||
clearCurrentTimeLabel();
|
||||
currentGpsPointIndex = index;
|
||||
var gpsInfo = rows[selectedTripIndex].gpsInfos[index];
|
||||
var clock = formatGpsClock(gpsInfo.create_time);
|
||||
var content = "<div class='info'>" + clock + "</div>";
|
||||
if (showPointStatus && wayMarkerArray[index]) {
|
||||
hideCarGpsTip();
|
||||
currentGpsLabelMarker = wayMarkerArray[index];
|
||||
currentGpsLabelMarker.setLabel({
|
||||
offset: new AMap.Pixel(20, 20),
|
||||
content: content,
|
||||
direction: 'right'
|
||||
});
|
||||
} else {
|
||||
showCarGpsTip(clock);
|
||||
}
|
||||
}
|
||||
|
||||
function formatGpsClock(value) {
|
||||
var parts = value.split(" ");
|
||||
return parts.length > 1 ? parts[1] : value;
|
||||
}
|
||||
|
||||
function clearGpsPointLabels() {
|
||||
if (currentGpsLabelMarker) {
|
||||
currentGpsLabelMarker.setLabel({
|
||||
offset: new AMap.Pixel(20, 20),
|
||||
content: "",
|
||||
direction: 'right'
|
||||
});
|
||||
currentGpsLabelMarker = null;
|
||||
}
|
||||
}
|
||||
|
||||
function showCurrentTimeLabel(position, content) {
|
||||
currentTimeLabel = new AMap.Marker({
|
||||
map: map,
|
||||
position: position,
|
||||
content: "<div></div>",
|
||||
offset: new AMap.Pixel(0, 0),
|
||||
zIndex: 10000
|
||||
});
|
||||
currentTimeLabel.setLabel({
|
||||
offset: new AMap.Pixel(20, -20),
|
||||
content: content,
|
||||
direction: 'right'
|
||||
});
|
||||
}
|
||||
|
||||
function clearCurrentTimeLabel() {
|
||||
if (currentTimeLabel) {
|
||||
currentTimeLabel.setMap(null);
|
||||
currentTimeLabel = null;
|
||||
}
|
||||
}
|
||||
|
||||
function showCarGpsTip(clock) {
|
||||
var tip = document.getElementById("carGpsTip");
|
||||
if (tip) {
|
||||
tip.innerText = clock;
|
||||
tip.style.display = "block";
|
||||
}
|
||||
}
|
||||
|
||||
function hideCarGpsTip() {
|
||||
var tip = document.getElementById("carGpsTip");
|
||||
if (tip) {
|
||||
tip.style.display = "none";
|
||||
tip.innerText = "";
|
||||
}
|
||||
}
|
||||
|
||||
function getNearestGpsPointIndex(position) {
|
||||
if (!position || lineArr.length === 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
var nearestIndex = 0;
|
||||
var nearestDistance = Number.MAX_VALUE;
|
||||
for (var i = 0; i < lineArr.length; i++) {
|
||||
var distance = position.distance(lineArr[i]);
|
||||
if (distance < nearestDistance) {
|
||||
nearestDistance = distance;
|
||||
nearestIndex = i;
|
||||
}
|
||||
}
|
||||
return nearestIndex;
|
||||
}
|
||||
|
||||
function getSegmentSpeed(a, b) {
|
||||
var start = parseGpsTime(a.create_time);
|
||||
var end = parseGpsTime(b.create_time);
|
||||
var seconds = (end - start) / 1000;
|
||||
if (seconds <= 0) {
|
||||
return 0;
|
||||
}
|
||||
return getDistance(a, b) / seconds;
|
||||
}
|
||||
|
||||
function parseGpsTime(value) {
|
||||
return new Date(value.replace(/-/g, "/")).getTime();
|
||||
}
|
||||
|
||||
function getDistance(a, b) {
|
||||
var earthRadius = 6371000;
|
||||
var lat1 = toRad(parseFloat(a.latitude));
|
||||
var lat2 = toRad(parseFloat(b.latitude));
|
||||
var deltaLat = toRad(parseFloat(b.latitude) - parseFloat(a.latitude));
|
||||
var deltaLng = toRad(parseFloat(b.longitude) - parseFloat(a.longitude));
|
||||
var h = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) +
|
||||
Math.cos(lat1) * Math.cos(lat2) *
|
||||
Math.sin(deltaLng / 2) * Math.sin(deltaLng / 2);
|
||||
return earthRadius * 2 * Math.atan2(Math.sqrt(h), Math.sqrt(1 - h));
|
||||
}
|
||||
|
||||
function toRad(value) {
|
||||
return value * Math.PI / 180;
|
||||
}
|
||||
|
||||
function getSpeedColor(speed) {
|
||||
var maxSpeed = 20;
|
||||
var ratio = Math.max(0, Math.min(speed / maxSpeed, 1));
|
||||
var red = Math.round(214 * (1 - ratio) + 25 * ratio);
|
||||
var green = Math.round(69 * (1 - ratio) + 165 * ratio);
|
||||
var blue = Math.round(49 * (1 - ratio) + 90 * ratio);
|
||||
return rgbToHex(red, green, blue);
|
||||
}
|
||||
|
||||
function getTripColor(index) {
|
||||
var colors = [
|
||||
"#2563eb", "#9333ea", "#f97316", "#0891b2",
|
||||
"#db2777", "#7c3aed", "#0f766e", "#ca8a04"
|
||||
];
|
||||
return colors[index % colors.length];
|
||||
}
|
||||
|
||||
function rgbToHex(red, green, blue) {
|
||||
return "#" + [red, green, blue].map(function (value) {
|
||||
var hex = value.toString(16);
|
||||
return hex.length === 1 ? "0" + hex : hex;
|
||||
}).join("");
|
||||
}
|
||||
|
||||
// 保留旧按钮或缓存页面调用,避免旧事件找不到函数。
|
||||
function showDate() {
|
||||
showGpsPoints();
|
||||
}
|
||||
|
||||
function hideDate() {
|
||||
hideGpsPoints();
|
||||
}
|
||||
|
||||
function parseRouteToPath(route, type) {
|
||||
var path = [];
|
||||
for (var i = 0, l = route.steps.length; i < l; i++) {
|
||||
var step = route.steps[i];
|
||||
for (var j = 0, n = step.path.length; j < n; j++) {
|
||||
path.push(step.path[j]);
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user