ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

高德地图实时轨迹展示:从定位采集到前端平滑渲染的完整实践

高德地图实时轨迹展示:从定位采集到前端平滑渲染的完整实践 说来也巧上个月给一家做配送调度的客户写后台需求翻译过来就是一句话“我打开网页要看到每辆车的实时位置还得能回看最近10分钟它是怎么走的。”放到技术方案里就是高德地图上的实时轨迹展示。这种需求听起来不难但真要做到“像打车软件里那个点一样丝滑地往前跑”而不是一秒卡顿一下、两秒猛跳一段背后要处理的细节比我预想的多太多。我把整条链路拆成四块定位采集、数据上报、前端推送、地图渲染每块都有不少坑。这篇文章我打算用项目复盘的方式把完整的实现思路、实操代码、参数选择和踩坑记录都写出来。无论你是要接类似的车队监控、外卖配送大屏还是自己玩户外轨迹记录这套方案都能直接改改拿来用。1. 项目从哪开始需求拆解与方案选型1.1 实时轨迹展示的核心难点在哪先说清楚“实时轨迹展示”和普通地图应用的本质区别。普通地图应用是静态的一个点、一条线、一个覆盖物画出来就完了。实时轨迹展示是动态的逻辑上是一条完整的流水线设备每隔几秒采集一次经纬度通过网络上报到服务器服务器把新坐标推送到浏览器浏览器再把这个坐标画到高德地图上。任何一个环节出现延迟或抖动页面上那个点就会“跳”而不是“走”。这里有两个层面的核心难点。数据链路的实时性。GPS上报间隔、网络传输耗时、后端推送机制、前端接收频率每一步都有延迟。你要在延迟和资源消耗之间找一个平衡点。间隔太短设备流量和服务器压力都扛不住间隔太长用户看到的轨迹就是一顿一顿的。地图渲染的平滑性。实时轨迹不只是画一条线。移动小图标要跟着坐标前进轨迹线要不断延伸定位点时不时还会抖动。你不能让图标在地图上乱颤也不能让它瞬间从位置A闪现到位置B。所有这一切都需要前端做额外的处理和优化。这套链路想清楚了后面每一步都有明确目标。1.2 为什么选择高德地图JS API我对比过几套方案最终选了高德地图JS API。主要原因有三个。一是国内坐标系统的兼容问题。国内地图用的都是GCJ-02坐标系而硬件GPS设备返回的是WGS-84坐标系两种坐标之间会有几十到几百米的偏移。高德针对前端开发者提供了坐标转换工具虽然不能完全免掉转换工作但至少省了很大一部分折腾成本。二是高德JS API自带的AMap.Marker、AMap.Polyline、AMap.Map这些基础能力刚好覆盖实时轨迹展示的所有底层需求。移动点用Marker轨迹线用Polyline地图实例负责场景承载不需要自己去造轮子。三是免费配额对中小项目足够。普通的车辆监控、人员轨迹展示日常请求量在免费配额范围内完全够用。对创业团队或者中小公司来说这个是实打实的成本优势。对比一下Leaflet虽然轻量但国内底图服务要自己找百度地图API和腾讯地图API在能力上也都够但当时手头项目的高德文档熟悉度更高案例更丰富所以最终定在高德。2. 动手前的准备Key申请与地图初始化2.1 Key申请与安全密钥配置高德地图JS API 2.0和老的1.x版本有个重要区别不再只有一个Key就完事而是要配合安全密钥securityJsCode一起使用。没有正确配置JS安全密钥的话地图加载出来之后过不了多久就会报鉴权错误整个地图直接罢工。申请的安全密钥有两种配置方式。第一种直接把securityJsCode明文写在页面HTML里。这种方式适合本地开发、快速验证demo但是暴露在前端代码里的密钥一旦发布到生产环境就失去了真正的安全意义随便谁看下网页源码都能拿走。第二种通过代理服务器获取。前端访问一个后端接口由后端去请求高德接口再把加密密钥返还给前端使用。这样密钥不会暴露在浏览器端安全性更高。生产环境我强烈建议用这种方式。注意无论用哪种方式一定要记得在Key的“域名白名单”里把自己正在用的域名加进去。开发阶段尤其要加localhost。我见过太多人本地代码写好了地图死活加载不出来在控制台看了半天才找到原因是域名没加白。这个坑越早避开越好。2.2 基础地图初始化引入高德JS API 2.0的完整流程是这样的。HTML的head区域先配置安全密钥再加载地图脚本script window._AMapSecurityConfig { securityJsCode: 你的安全密钥, }; /script script srchttps://webapi.amap.com/maps?v2.0key你的Key/script初始化地图实例时有几个参数对实时轨迹项目很重要const map new AMap.Map(mapContainer, { zoom: 14, center: [116.397428, 39.90923], viewMode: 2D, mapStyle: amap://styles/whitesmoke });下面逐个解释。zoom是初始缩放级别。实时轨迹场景下建议初始级别设在13到15之间既能看清道路级别车辆位置出现时又不至于像大头针一样充满全屏。center是地图中心点。项目里通常先用第一个定位点来初始化或者在用户首次进入页面时请求一次所有设备的最近位置取一个中心点。viewMode我特意设成2D。很多人喜欢3D模式但实时轨迹项目里3D视角的倾斜和旋转会干扰用户判断移动点的真实位置。2D俯视图干净直接轨迹展示最直观也减少视觉眩晕。mapStyle是地图样式。whitesmoke这种浅色风格做轨迹展示比较清爽轨迹线和移动点颜色可以突出出来。如果你后续要做数据大屏还可以换成暗色样式。3. 轨迹数据从哪来定位采集与上报链路地图渲染是“果”数据链路才是“因”。这部分的坑比地图代码多得多。3.1 终端定位数据采集我那个项目用的是车载硬件设备上报GPS数据走的是固定硬件方案。如果你做的是手机端场景一般有两种选择高德定位SDK或者浏览器的navigator.geolocation。先说浏览器geolocation适合Web端快速跑通逻辑navigator.geolocation.watchPosition( (position) { const { longitude, latitude } position.coords; reportPosition(longitude, latitude); }, (error) { console.error(定位失败, error); }, { enableHighAccuracy: true, timeout: 5000, maximumAge: 1000 } );三个配置项要点enableHighAccuracy设为true表示开启高精度定位。但要注意浏览器的“高精度”在不同终端上的表现差异很大。在手机上Chrome的geolocation高精度模式通常能拿到相对不错的GPS数据但桌面浏览器或一些WebView里就未必了。timeout是定位超时时间。5000毫秒比较合理如果5秒内没有拿到位置就触发error回调。maximumAge允许浏览器返回缓存位置的最长时间。设成1000毫秒避免拿到的还是10秒前的老位置。如果你的项目是原生App我强烈建议用高德定位SDK而不是通过WebView套一层浏览器定位。原生定位的稳定性、连续性和精度都比浏览器geolocation好一个档次。定位点采集频率我是这么定的车辆场景2秒一次人员徒步场景3秒一次。为什么不是越快越好从设备角度看上报越频繁GPS模块功耗越大流量消耗越多。从服务器角度看几千台设备同时2秒一报每秒的请求压力很可观。从渲染角度看前端处理插值动画也是成本。以移动速度为依据来定采集频率最合理速度快的车辆用1到2秒速度慢的人员行走用3到5秒。这个经验值在多个项目里实践过效果稳定。3.2 后端接收与前端推送方案原始坐标采集到之后需要通过网络上报到后端。这里有两套方案可选。HTTP轮询方案前端每隔几秒发起一次请求拉取最新坐标。优点是实现简单后端只要提供REST接口就行。缺点是实时性和资源消耗是一对矛盾轮询间隔短实时性好了但服务器压力剧增轮询间隔长服务器轻松了轨迹就变成了“卡顿动画”。WebSocket方案前端和后端建立长连接后端有新坐标时主动推给前端。优点是真正意义上的实时毫秒级到达。缺点是后端需要多维护一层长连接状态断线重连要自己处理。我的项目最终用了WebSocket作为主力通道HTTP轮询只是兜底。原因很简单定位设备2秒报一次如果轮询间隔也是2秒那刚好匹配但如果后端因为网络波动延迟了几秒推送前端轮询就会拿到重复数据或者在窗口期漏掉关键坐标。上线前我用一个最简单的方式验证了WebSocket方案的稳定性本地写一个脚本模拟后端推送每2秒push一条坐标前端页面保持不动观察24小时看有没有丢消息、断线、堆积。跑完这轮测试数据链路稳定性基本心里有底了。后端推送的数据结构我设计成这样{ deviceId: T001, lng: 116.397428, lat: 39.90923, speed: 32.5, direction: 148.2, timestamp: 1712300000000 }lng和lat是经纬度speed是当前速度direction是方向角timestamp是定位时间。这几个字段各有用途经纬度决定Marker画在哪方向角控制图标旋转时间戳用来判断数据新鲜度和顺序速度则是坐标滤波的重要参考。踩坑提示timestamp字段必须带而且前端必须做新鲜度校验。实际运行中遇到过“旧数据最后到达”的情况设备在网络差的地方缓存了几条坐标恢复网络后一次性补传结果最新位置先画出来了随后旧坐标又覆盖上去移动点瞬间“倒退”。前端每次收到推送先比较一下timestamp只接受比当前展示点更新的坐标这个逻辑很简单但非常关键。4. 移动点与轨迹线的渲染实现这一节是整个项目的核心实战部分。4.1 移动点Marker的创建高德地图上的点标记用AMap.Marker。最简单粗暴的用法是new一个Marker然后每次拿到新坐标就调用setPosition。但这样会有一个问题坐标更新一次Marker就整帧跳一次视觉上非常生硬看起来不像在“走”而是在“瞬移”。我在项目里的做法分两步第一步创建Marker并设置好图标、偏移和锚点。const marker new AMap.Marker({ content: div classcar-icon/div, offset: new AMap.Pixel(-16, -16), map: map });这里用content传了一个自定义HTML元素作为图标。这样做的好处是图标样式可以直接用CSS控制后面加旋转、动效都方便。用AMap.Icon当然也可以但灵活性略差一点。offset是图标偏移量。这里设成(-16, -16)是把图标的中心点对准经纬度位置。如果你的图标是32x32像素刚好偏移一半点位就和图标中心重合。第二步拿到新坐标后不是直接setPosition而是从旧位置平滑过渡到新位置。具体的插值逻辑在下面单独说。4.2 平滑移动的核心requestAnimationFrame插值实时轨迹最核心的视觉体验就是“平滑”。实现平滑移动的主流做法是借助requestAnimationFrame做坐标插值。整体思路是这样的新坐标到达后记录当前坐标和目标坐标计算两者之间的距离设定一个合理的移动时长然后在每一帧动画里按时间进度插值更新Marker位置。直接看核心代码function smoothMove(marker, from, to, duration 1000) { const startTime performance.now(); const dx to.lng - from.lng; const dy to.lat - from.lat; function frame(now) { const progress Math.min((now - startTime) / duration, 1); const lng from.lng dx * progress; const lat from.lat dy * progress; marker.setPosition([lng, lat]); if (progress 1) { requestAnimationFrame(frame); } } requestAnimationFrame(frame); }progress是一个0到1之间的数字代表当前动画进度。乘以坐标差dx和dy就能得到当前应处的经纬度。Math.min的处理是为了防止动画时长超过预期导致progress大于1。duration这个参数怎么取值我的经验是上报间隔2秒动画时长取1.5秒留0.5秒缓冲上报间隔3秒动画时长取2秒总之动画时长要略小于上报间隔。否则上一个动画还没走完新坐标又来了两个动画任务互相干扰点会来回抽动。还有一个细节如果两个连续坐标点的距离特别近小于1米不要做动画直接setPosition。否则点会给人一种原地颤抖的错觉反而不好。4.3 轨迹线Polyline的绘制轨迹线用高德的AMap.Polyline。基础用法const line new AMap.Polyline({ path: [], strokeColor: #1E90FF, strokeWeight: 4, strokeOpacity: 0.85, lineJoin: round, lineCap: round, map: map });随着新坐标到达把新点push进path数组然后刷新线function appendPointToLine(line, lngLat) { const path line.getPath(); path.push(lngLat); line.setPath(path); }这段逻辑很直观但有一个性能大坑每2秒增加一个点运行10分钟后轨迹就有300个点如果屏幕上同时有几十辆车每辆车都有这么一条不断增长的线浏览器迟早被拖垮。我的解法是轨迹线只保留“最近一段时间”的点集。比如展示最近10分钟那就是300个点老的坐标点直接踢出path数组。const MAX_POINTS 300; // 10分钟 * 每分钟30个点 function appendPoint(line, lngLat) { const path line.getPath(); path.push(lngLat); while (path.length MAX_POINTS) { path.shift(); } line.setPath(path); }用shift()把最早的点从数组头部移除整个轨迹线就像一条不断向前滚动的“传送带”始终保持最近10分钟的轨迹可见。真正要看历史完整轨迹时再单独走回放接口查询不占用实时渲染的额度。关于Polyline的样式我这里补充几个实际调优过的细节strokeColor建议用高亮色蓝色或者绿色比较突出配合透明度使用。strokeWeight在4到6之间比较合适太细看不清太粗会遮挡底图道路。lineJoin和lineCap都设成round线的拐角处就不会出现尖角观感圆润很多。如果屏幕上同时展示多条轨迹不同设备用不同颜色区分并配合页面侧边的图例列表用户才能分辨出哪条线是哪辆车。4.4 地图跟随与视野适配移动点一直在往前走地图视口不跟随点就会跑出屏幕。跟随方式我测试过两种。方案A每次更新Marker位置后就调用map.setCenter(newPos)。效果是地图跟着点走但有个问题高德的setCenter不是平滑滚动而是直接跳到新中心点视觉上是地图“啪”地一下瞬移体验很生硬。方案B只在移动点接近屏幕边缘时才调整地图中心。也就是实时监测Marker在屏幕中的像素位置超过设定阈值才setCenter否则让地图保持不动。我最终用了方案B。具体实现是先通过map.lngLatToContainer(lngLat)把经纬度转成容器像素坐标判断该像素坐标是否落在屏幕边界内。如果距离边缘小于80像素就setCenter到当前位置。这套逻辑跑起来很稳用户观看轨迹时不会感觉镜头一直在乱晃。另外map.setFitView这个方法要注意。它的作用是调整缩放级别去适应某个覆盖物的边界让轨迹完整显示。这在初始化展示整车轨迹时很有用但在实时轨迹场景里不要频繁调用。因为setFitView会不断重置缩放级别连续调用会让地图像抽搐一样缩放。一般只在“查看整车轨迹”或首次进入页面时调用一次。5. 坐标系偏移必须面对的隐形坑5.1 WGS-84和GCJ-02的偏移问题如果你的定位数据来自硬件GPS模块车载终端、外接GPS receiver那拿到的是WGS-84坐标系。而高德地图跟国内所有主流地图一样用的是GCJ-02坐标俗称火星坐标系。两个坐标系之间的偏移量在城市区域通常是几十米到几百米不等。几百米的偏差在路网上是什么概念如果你的轨迹沿着一条东西向的马路偏出去200米可能已经到隔壁第二条、第三条街上了。画出来的轨迹线与实际跑过的路线完全对不上这在车辆监管场景里是不可接受的。所以数据进入地图之前坐标转换这一步绝对不能省。5.2 高德官方转换工具和自写转换的取舍高德JS API提供了坐标转换能力。官方封装的方法可以在前端直接调用AMap.convertFrom( [new AMap.LngLat(wgsLng, wgsLat)], gps, (status, result) { if (status complete result.info ok) { const gcjCoord result.locations[0]; // 用转换后的坐标做后续绘制 } } );但是这个方法有一个限制它是批量接口一次最多只能转40个坐标点。对于实时轨迹场景来说如果每个上报坐标都单独调一次请求频率会非常高而且接口响应延迟不可控。我在项目里的建议是能转就在后端统一转。后端接收到设备上报的WGS-84坐标后直接统一批量转换成高德坐标系再写入数据库或推送给前端。前端拿到的就是高德坐标系绘制时不需要再考虑转换问题。这样既省了前端请求延迟也避免了频繁调用高德转换接口的配额压力。如果项目确实需要在前端转换建议做一个小范围的坐标缓存。同一个设备在短时间内的坐标偏移量基本一致可以把最近一次转换结果缓存起来连续坐标直接应用偏移校正不必每个点都走接口。5.3 坐标漂移与滤波处理坐标转换之后还有一个隐藏问题某些定位设备本身精度不够或者在城市高架、隧道、高楼密集区域GPS信号反射严重转换后的坐标偶尔会剧烈抖动。表现就是移动点在两条车道之间来回跳或者轨迹线出现奇怪的锯齿。这通常不是地图代码的问题而是原始坐标漂移。处理办法是在上游做滤波。我的做法是做一个简单的运动合理性判断如果新点和上一个有效点之间的距离小于5米且计算出的瞬时速度异常比如从30km/h瞬间蹦到120km/h就判定这个点为异常点直接丢弃。反之则接受。这个“距离阈值速度突变”的组合判断在实测中筛掉了不少GPS漂移产生的坏点轨迹线干净了很多。代价是过滤了一部分真实的数据点但对实时展示来说这种精度损失完全可接受。6. 轨迹平滑与性能优化6.1 轨迹点抽稀点到一定数量必须瘦身实时轨迹跑起来轨迹点多到一定数量后地图交互会明显变慢。我的经验是分两级管理。第一级是轨迹线段抽稀。相邻两个点距离特别近比如6米以内时可以不上报前端。这样做能保持轨迹的基本形状同时大幅减少点的数量。这个思路是经典Douglas-Peucker抽稀算法的实时场景简化版。不需要引入复杂算法用一个简单的距离阈值判断就够。第二级是历史点归档。超过设定展示时长比如15分钟的点从地图上的线里移除只保留在数据库里。用户要回放历史轨迹时再单独查询加载。这个逻辑我在4.3节里已经讲过了用while循环从path数组头部弹出旧点即可。这样地图上的轨迹线段负载始终在可控范围。6.2 Marker和Polyline的批量操作实时更新多个移动点时我踩过一个很现实的性能坑每条轨迹线的每个新坐标都单独调用setPosition和setPath会导致渲染性能急剧下降。高德的DOM渲染策略对频繁的单项操作并不友好尤其是在低端安卓手机上。优化主要从两个方向入手。第一个方向是合并渲染。轨迹点批量更新的时候不要一个点一个点地push再setPath而是攒一批点一次性setPath传入整个新路径数组。这样能减少重绘次数。第二个方向是减少无谓的setPosition调用。如果新坐标和当前坐标的距离小于阈值直接不更新Marker。很多情况下定位设备静止或低速移动时产生的一堆近似重复坐标完全可以省掉。6.3 浏览器标签页后台休眠问题这个问题很容易被忽略但在实时轨迹场景里非常重要。浏览器有一个特性标签页切到后台后requestAnimationFrame会暂停执行WebSocket消息也会堆积在内存里不处理。用户切回页面时你写好的smoothMove动画不会精彩地补播而是会一次性把积压的全部坐标瞬间播放完屏幕上那个点像抽风一样乱跳或者直接卡死。我的处理方案是监听visibilitychange事件document.addEventListener(visibilitychange, () { if (document.visibilityState visible) { latestPositions.forEach((pos) { marker.setPosition(pos); }); } });页面切回前台时丢弃堆积的历史推送消息只取后端推送队列里的最新坐标直接用setPosition强制同步位置不做插值动画。同时把堆积的轨迹点数据清理掉防止动画队列越积越多。这个细节不处理好的话用户最小化页面几分钟再切回来看到的就是一辆车从城南瞬移到城北体验非常糟糕。处理掉之后切回来看到的是丝滑的衔接差别特别大。6.4 方向角旋转与图标朝向移动点的图标朝向也是一个细节体验点。车辆类的设备上报数据里通常带direction方向角字段可以把它直接用在图标旋转上。用自定义HTML做icon时旋转通过CSS实现function updateDirection(marker, direction) { const iconEl marker.getContent(); iconEl.style.transform rotate(${direction}deg); }这里有个坑CSS的rotate是围绕元素中心旋转的。如果你的图标本来就设计成车头朝上那么方向角0度对应车头朝北90度对应车头朝东。后端上报的direction如果是地理方位角正北为0度顺时针递增直接赋值给rotate就能对上。但有些硬件设备上报的角度是设备自身的安装角度不是地理方位角需要先做校准换算。我在项目里就遇到过一批终端上报的direction完全反了排查了半个多小时才发现是硬件角度的定义问题。7. 常见问题排查实录最后整理一份高频问题排查清单都是我实际项目中遇到过的。7.1 地图加载空白现象页面打开后地图区域一片空白或者只显示灰色网格底图。排查步骤打开浏览器控制台看有没有关于Key鉴权的报错。如果有鉴权错误先检查Key和securityJsCode是否配对正确。尤其注意不要在同一个页面里同时引用了不同版本的JS API脚本。再检查Key的域名白名单是否包含当前访问域名。本地调试记得加localhost。如果是生产环境刚上线检查域名是否在后台服务控制台的“配额管理”里做了配置。7.2 移动点不动但后端数据在更新现象控制台能看到WebSocket不断推送数据但地图上的Marker位置纹丝不动。排查思路最常见的原因是把Polyline的path更新和Marker的位置更新搞混了。代码里只更新了轨迹线的path忘了更新marker的position。两行代码缺一不可。检查新坐标的经纬度是否正常。有时候后端会对坐标做四舍五入保留位数太少比如保留3位小数会出现点几乎不动或极微跳动的现象。检查是否在坐标转换环节丢 데이터。前端如果调用了convertFrom确认回调里拿到的result.locations是否为空。7.3 坐标漂移、点在原地抖动现象车辆静止停着但地图上的移动点在一个小范围内来回飘动。排查思路先看后端上报的speed字段。如果速度几乎为0就做“静止状态判断”直接把点吸附到上一个有效点不做位置更新。检查是否做了坐标滤波。设备在高架桥下、隧道里、高楼密集区域时GPS漂移很严重如果没有异常点过滤逻辑抖动很难避免。检查移动点是否同时被多个逻辑更新。我遇到过一个问题项目里有历史回放功能回放线程和实时更新线程同时操作同一个Marker导致位置互相覆盖、来回跳。这个在代码层面注意加锁或使用独立的Marker。7.4 WebSocket断线后停止更新现象网络波动之后轨迹点停止更新过一段时间也没有恢复。排查思路WebSocket连接断掉之后不一定会自动重连。你需要做两件事。第一件事是心跳机制。前端每隔30秒发一次ping如果连续3次没收到pong就判定连接已经断掉主动断开并重连setInterval(() { if (ws.readyState WebSocket.OPEN) { ws.send(ping); pingCount; if (pingCount 3) { ws.close(); reconnect(); pingCount 0; } } }, 30000);第二件事是重连后补数据。WebSocket断线期间后端的数据是积压的或者是丢掉的。重连成功后前端通过一次HTTP请求去拉取断线期间的最近坐标点补上轨迹空缺再继续接收实时推送。7.5 轨迹线方向反了现象明明车辆是从北往南开地图上画出来的轨迹线却从南往北。排查思路一般不是地图问题是数据顺序问题。后端在补传数据和WebSocket推送时没有保证坐标的时间顺序。解决方案是后端统一按timestamp排序后再推给前端前端也做一次时间序列去重确保进入Polyline的path数组的点是有序的。7.6 高德地图JS API常见报错速查我把平时最常见的报错和控制台提示整理成一张速查表报错信息原因解决方法INVALID_USER_KEYKey无效或未激活检查Key是否正确确认服务已开通USER_KEY_PLAT_NOMATCHKey绑定的平台和应用类型不匹配Web端要用JS API的Key不能用Web服务KeyUSER_KEY_EXPIREDKey过期去平台控制台续期INVALID_USER_SCODE安全密钥错误检查securityJsCode是否匹配SERVICE_NOT_AVAILABLE服务配额耗尽或未开通检查配额调高免费额度或购买付费LngLat coordinate illegal坐标超出合法范围检查经纬度是否越界lng在-180到180lat在-90到908. 追加一些实操心得项目做完之后再回头看这个过程我想分享几个从实践里沉淀下来的体会。第一别迷信“实时”两个字。真正的实时是通过各种权衡和补偿实现的。上报间隔、动画时长、地图跟随策略每个参数背后都是体验和成本的平衡。拿到需求第一件事不是写代码而是把这些参数确认清楚设备多久报一次、用户能接受的视觉延迟是多少、服务器能不能撑住房并发。第二数据链路优先于地图渲染。地图API翻官方文档就能学会但定位上报、断线重连、坐标滤波这些“看不见”的环节才是决定项目成败的关键。你辛辛苦苦把轨迹线画漂亮了结果GPS数据链路抖动一下、断一下体验立刻崩盘。我重写这个项目时大概70%的调试时间都花在数据链路上而不是地图代码。第三动画代码一定要设计成可插拔的。实时展示和轨迹回放是两个非常相近但走了两条路的功能。回放用高德的map.moveAlong就能实现但实时平滑动画是我用requestAnimationFrame自己写的。这两个逻辑如果耦合在一起后面调试会非常痛苦。我建议把“移动点的位置更新”和“轨迹线的path更新”拆成两个独立模块各自负责各自的职责。如果要做扩展实时轨迹这个底座能玩出很多功能历史轨迹回放加一个播放速度滑块就是迷你回放器车辆进出电子围栏可以触发告警多设备同时显示可以配合设备列表切换高亮大屏模式还能把轨迹和里程、速度、停留时间等统计图表结合起来。抛开这些锦上添花的功能实时轨迹展示的核心诉求始终是一个让使用者一眼看清“那台车、那个人现在在哪刚才怎么走过来的”。把这条主线做扎实这个项目就成了。
返回列表