尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

天地图打点实战:自定义图标、文字备注与批量性能优化

天地图打点实战:自定义图标、文字备注与批量性能优化 1. 打点之前先把天地图这套东西的地基摸清楚做天地图打点这件事很多人一上来就复制一段示例代码把 marker 往地图上一扔跑起来发现图标是默认的蓝色水滴想换成自己的图标就卡住了想加个文字备注更是到处贴 div。问题不在代码写得多复杂而在于没搞清楚天地图 API 里几个对象之间的关系。我用天地图做过几个物流网点和设备监控的看板前期也踩了不少坑这篇文章就把自定义图标 文字备注这条件链路上的每个环节拆开讲从 Key 申请、坐标系校对到图标锚点算法、Label 偏移量计算再到上千点位时的性能取舍都会给出可以直接抄的代码和参数。适合刚接手 GIS 看板的前端、做设备管理系统的后端同学以及需要在地图上标点但不想引入重型 GIS 框架的开发者。1.1 一个 Key 背后要过的三道关天地图的所有服务都绕不开一个东西——tk也就是我们常说的 Key。它在天地图官网的控制台里申请申请的时候要选应用类型浏览器端一般选浏览器端服务端选服务端。这里有三道关必须过不然你会拿到一串莫名其妙的错误码。第一道是域名绑定。浏览器端 Key 是要绑定调用来源的你填了www.example.com那本地localhost:8080调试的时候就可能被拦。我的做法是申请两个 Key一个给测试环境域名写localhost和测试域名一个给生产环境别混用。第二道是服务授权申请的时候勾选的服务类型决定了你能调哪些接口如果你勾的是地图API但实际调的是地理编码一样会被拒。第三道是配额天地图的免费额度对大多数中小项目够用但如果你在循环里疯狂请求逆地理编码很容易触发限流表现就是一片点位突然加载不出来。引入方式上4.0 版本是这样写的script srchttps://api.tianditu.gov.cn/api?v4.0tk你的KEY/script注意v4.0和tk的顺序不重要但tk千万别写在 URL 的 hash 后面不然解析不到。另外如果你的站点本身是 HTTPS天地图的脚本也建议走 HTTPS否则浏览器会拦混合内容地图直接白屏。1.2 坐标系不对图标再好也白搭这是我在一个项目上花了整整一上午才想明白的问题。地图上明明标的是北京国贸结果图标落在了天津方向的海里差了大概一百多公里。原因很简单数据源给的是 GCJ02 坐标也就是高德、腾讯那套而天地图用的是 CGCS2000两者之间有几条街到几百米的非线性偏移量级取决于位置。反过来如果你的原始数据来自手机 GPS 或北斗设备那大概率是 WGS84直接丢到天地图上基本是对得上的因为 CGCS2000 和 WGS84 在民用精度下差异在厘米级到米级肉眼看不出。真正要处理的是这两种情况数据来源坐标系直接标在天地图上处理建议手机 GPS / 定位模块WGS84基本对齐直接用高德 / 腾讯 / 微信GCJ02偏移几百米先转 WGS84 再标百度BD09偏移更多先转 GCJ02 再转 WGS84天地图坐标拾取工具CGCS2000完全对齐直接用手工从地图上点出来的跟随底图对齐直接用转换的逻辑网上有现成的开源实现核心就是那套偏移算法。我不建议自己手写容易在边界处出问题直接用验证过的库更稳。判断数据到底对不对有个土办法挑一个地标建筑比如某个高铁站把坐标填到天地图官网的坐标拾取工具里看落点是不是在正确的建筑上一眼就能确认。1.3 Marker、Label、Overlay 三者的分工与边界天地图 4.0 里地图上的东西都叫覆盖物通过map.addOverLay()挂上去注意这个方法是OverLay而不是Overlay大小写写错了方法就不存在这是新手最常犯的低级错误之一。T.Marker点是点负责一个图标。可以自定义图标、可以拖拽、可以绑定点击事件。它本身不带文字除非你用title属性但那个只在鼠标悬停时出原生提示样式不可控。T.Label专门显示文字位置独立可以设置背景色、边框、字号、字体。它和 Marker 之间没有绑定关系你要么手动对齐要么在数据层把两者用同一个坐标生成。T.DivOverlay用一段 HTML 自定义内容灵活性最高但也最容易失控因为一个点位就是一个 DOM 节点上百个之后布局和重绘的开销就上来了。我的建议是图标和文字分开处理Marker 管图标Label 管文字两者用同一个T.LngLat创建这样后续要单独控制文字显隐或者单独换图标都很方便。不要为了省事用 DivOverlay 把图标和文字塞一起除非你的点位数量在两位数以内。提示天地图 API 里addOverLay、removeOverLay、clearOverLays这几个方法的名词拼写是固定的别按英文习惯改成 Overlay改了就报不是一个函数。2. 自定义图标让 Marker 从默认水滴变成你要的样子默认图标是个蓝色水滴几乎没有一个真实项目会用它。自定义图标看起来只是换个 URL实际上涉及尺寸、锚点、缓存、跨域、高清屏适配好几个点每一项没处理好都会让你的点位看起来怪怪的。2.1 图标资源怎么准备才不糊、不歪、不闪先说尺寸。常见的图标设计稿是 32×44、34×48、48×64 这几种比例长宽比保持在 1:1.35 左右最接近传统地图针的形状。如果你用的是方形图标比如圆形头像或者方形设备图标那锚点就要重新算不能照抄针形图标的参数。分辨率上现在大部分设备是 2 倍甚至 3 倍屏你只准备一张 32×44 的 PNG在高分屏上就会被拉大边缘发虚。我的做法是准备两套marker.png是 32×44marker2x.png是 64×88然后根据window.devicePixelRatio决定用哪张同时把iconSize写成逻辑尺寸。这样在普通屏和高分屏上的视觉大小是一致的只是清晰度不同。格式选择上纯色或简单图形优先用 SVG 或者 PNG-8复杂的立体图标用 PNG-24。JPG 千万不要用因为图标基本都有透明区域JPG 会把透明部分变成白块贴在地图上就是一个个白方块非常难看。文件大小尽量控制在 5KB 以内点位多了之后图标体积直接影响首次渲染时间。2.2 T.Icon 三个核心参数的含义与取值算法自定义图标的核心就三个参数iconUrl、iconSize、iconAnchor。前两个好理解第三个是最容易搞错的。var icon new T.Icon({ iconUrl: ./images/device2x.png, iconSize: new T.Point(32, 44), iconAnchor: new T.Point(16, 44) });iconSize是图标显示的逻辑尺寸宽 32 高 44。iconAnchor是图标的锚点指的是图标内部的哪一个像素点会和地理坐标重合。默认锚点在左上角也就是 (0,0)这会导致图标整体向右下偏移坐标点跑到图标的左上角去了视觉上就像图标没扎在点上。针形图标的标准锚点是底部中心也就是(width/2, height)代入上面就是 (16, 44)。这样图标的下尖端正好压在地理坐标上符合人的直觉。圆形图标的锚点则是中心点(width/2, height/2)也就是 (16, 22)。这个必须根据你的图形来定没有万能值。如果你用的是iconSize缩放锚点也要等比例缩放。比如原始图是 128×176你想显示成 32×44缩放系数是 4原始锚点如果是 (64, 176)那显示锚点就是 (16, 44)。很多人直接把原始像素坐标填进去结果图标飞出去老远就是这个原因。2.3 一套图标管多种业务状态的写法真实项目里图标不会只有一种。设备有在线、离线、告警三种状态网点有正常、停业两种状态如果不做映射代码里会到处都是 if-else。我的做法是建一张类型到图标的映射表数据里只存类型字符串。var ICON_MAP { online: { url: ./images/online.png, size: [28, 38], anchor: [14, 38] }, offline: { url: ./images/offline.png, size: [28, 38], anchor: [14, 38] }, warning: { url: ./images/warning.png, size: [32, 42], anchor: [16, 42] } }; function buildIcon(type) { var cfg ICON_MAP[type] || ICON_MAP.offline; var dpr window.devicePixelRatio 1 ? 2x : ; return new T.Icon({ iconUrl: cfg.url.replace(.png, dpr .png), iconSize: new T.Point(cfg.size[0], cfg.size[1]), iconAnchor: new T.Point(cfg.anchor[0], cfg.anchor[1]) }); }这样上层只需要传type: warning图标的 URL、尺寸、锚点全部自动匹配。好处是后续设计要改图标只改这一张表不用翻遍业务代码。另外这套写法天然支持动态切换已经创建好的 marker 可以用marker.setIcon(buildIcon(online))换图标用于做实时状态刷新。2.4 图标加载失败与跨域的那些坑图标不显示除了路径写错还有两个隐蔽的原因。一个是跨域如果你的图标放在 CDN 上而 CDN 没有返回Access-Control-Allow-Origin再加上你把地图配置成了需要读取像素的模式图标就渲染不出来。解决办法是把图标和页面放同域或者给 CDN 加上跨域头。另一个是图标数量太多导致的加载抖动。假设你有 500 个点位每个点位的图标第一次渲染时都要发起一次请求虽然浏览器有缓存但首屏那一瞬间会看到一片空白然后图标逐个蹦出来。我一般的处理是提前把图标用new Image()预热一遍等onload之后再批量创建 markerfunction preloadIcons(list, callback) { var loaded 0; list.forEach(function(src) { var img new Image(); img.onload img.onerror function() { loaded; if (loaded list.length) callback(); }; img.src src; }); }onerror也要算进去否则某个图标 404 了回调永远不触发整个地图就卡在这儿了。这个细节我踩过一次排查了半天才发现是图标路径大小写在服务器上不区分、本地区分导致的。3. 文字备注把名字稳稳贴在图标旁边图标解决了点在哪文字备注解决的是这是什么。天地图里做文字备注有两条路用 T.Label或者用 T.DivOverlay 自己画。前者轻量、性能好但样式能力有限后者灵活但点位多了会卡。我的经验是纯文字、样式简单的用 Label需要卡片、需要多行、需要按钮的用 DivOverlay并且严格限制数量。3.1 T.Label 的基础配置与样式方法先看最基础的写法var label new T.Label({ text: 北京南站, position: new T.LngLat(116.37865, 39.86523), offset: new T.Point(-30, -56) }); label.setFontColor(#ffffff); label.setBackgroundColor(#1a73e8); label.setFontSize(12); label.setBorderColor(#1a73e8); label.setBorderWidth(1); map.addOverLay(label);这里要注意position是文字框的位置offset是在这个位置基础上的偏移。天地图的 Label 默认定位点在左下角附近跟你想要的效果往往差一截所以 offset 基本是必调的。样式方法上setBackgroundColor和setBorderColor设成同一个颜色就能得到一个圆角感觉的胶囊标签实际是方角天地图 Label 不支持圆角。如果你想要更圆润的效果就得用 DivOverlay 加 CSS 的border-radius。字号方面12px 是移动端和桌面端都比较舒服的值14px 适合桌面端大屏看板10px 以下在缩放后会糊成一片不建议。还有一个容易被忽略的点Label 的层级。它和 marker 的 zIndex 是各自独立的如果你发现文字被图标盖住了可以调label.setZIndex()或者通过调整 offset 让它错开图标区域别去硬调 marker 的层级容易引起其他问题。3.2 offset 偏移量的计算过程含公式和实例这是整篇文章里最需要算一算的地方。假设我们要做一个图标在上、文字在下的布局图标尺寸 32×44锚点在底部中心文字想显示在图标下方 4px 的位置并且水平居中对齐。文字框的宽度取决于文字内容天地图 Label 没有一个直接的方法拿到渲染后的宽度所以只能估算。中文字符在当前字号下大约占 1 个字号宽度英文字符大约占 0.5 到 0.6 个字号宽度。假设文字是北京南站四个中文字号 12px加上左右各 6px 的内边距总宽度约为4×12 12 60px。高度约为12 8 20px。现在算 offset。Label 的定位点默认在文字框的左下角实际表现会随版本略有差异建议先用 (0,0) 试一次看它落在哪再反推我们按左下角处理水平方向图标中心在坐标点上文字框要居中所以文字框左下角的 x 坐标应该往左退半个文字宽度即-60/2 -30。垂直方向图标底边在坐标点上文字框要出现在图标下方但屏幕坐标 y 轴向下为正所以要向下偏移图标高度加间距。等等这里方向容易绕实际测试下来天地图 Label 的 offset 是相对于定位点做屏幕像素偏移y 值为负是向上。所以要让文字出现在图标下方应该用正值。但实际做出来文字在图标下方的布局很少因为图标本身占位文字压在地图上的可读性反而更好的是放在图标上方。我常用的布局是图标在上文字紧贴图标上沿上方。垂直方向-图标高度 间距 -(44 4) -48水平方向-30所以 offset 是new T.Point(-30, -48)。这个数字不是拍脑袋来的你可以写个小工具函数自动算function calcLabelOffset(text, fontSize, iconH, gap) { var textW 0; for (var i 0; i text.length; i) { textW /[\u4e00-\u9fa5]/.test(text[i]) ? fontSize : fontSize * 0.55; } textW 12; // 左右内边距 return new T.Point(-Math.round(textW / 2), -(iconH gap)); }用这个函数文字长短变化时偏移量会自动跟着变不用一个个手工调。我在一个网点看板里就是这么干的几十个点位一次性对齐视觉上很整齐。3.3 多行文字、带背景卡片式的备注T.Label 对多行支持比较弱text里塞\n在部分版本里不换行。如果你确实需要两行以上比如第一行是名称、第二行是状态那就上 DivOverlayvar html div classpoi-card div classpoi-name北京南站/div div classpoi-status在线 · 12:30/div /div; var overlay new T.DivOverlay(html, new T.LngLat(116.37865, 39.86523)); map.addOverLay(overlay);配合 CSS.poi-card { background: rgba(255,255,255,0.95); border: 1px solid #d0d7de; border-radius: 6px; padding: 6px 10px; font-size: 12px; box-shadow: 0 2px 6px rgba(0,0,0,0.15); white-space: nowrap; transform: translate(-50%, -100%); } .poi-name { font-weight: 600; color: #222; } .poi-status { color: #1a73e8; margin-top: 2px; }这里用 CSS 的transform: translate(-50%, -100%)来做居中上移比自己算 offset 更直观而且文字长度变化时自动适应这是 DivOverlay 相比 Label 最大的优势。代价就是每个卡片都是一个真实 DOM我实测下来超过 200 个卡片页面滚动和缩放就开始有轻微掉帧超过 500 个就明显卡了。注意DivOverlay 的 HTML 内容里不要放用户直接输入的文本必须做转义否则会引入脚本注入风险。这个在后台系统的点位备注里特别容易出事因为备注往往是运营人员手填的。3.4 按缩放级别控制备注显隐点位一多文字全挤在一起就是一团糊。合理的做法是按缩放级别分级显示。地图的zoom从 1 到 18我们可以约定 zoom 小于 10 只显示图标10 到 13 显示重要点位文字13 以上全部显示。map.addEventListener(zoomend, function() { var z map.getZoom(); labelList.forEach(function(item) { var visible z item.minZoom; if (visible !item.added) { map.addOverLay(item.label); item.added true; } else if (!visible item.added) { map.removeOverLay(item.label); item.added false; } }); });不要把 Label 创建出来只是设成透明那样 DOM 还在性能没省下来。要用removeOverLay真正摘掉。另外zoomend事件在连续滚动时会触发很多次建议加一个节流间隔 150 毫秒以上不然缩放过程中会有一阵阵的卡顿。4. 批量打点与交互从几十个到上千个点单个点位的写法会了接下来是真刀真枪的项目场景一屏几百个点还要能点、能悬停、能区分状态。这一块的做法和单点完全不同讲究的是数据组织和渲染策略。4.1 数据组织与图标的映射策略后端返回的数据结构往往五花八门前端最好先归一化成一个统一的结构再去渲染。我一般会转成这样var poiList [ { id: D001, name: 一号设备, lng: 116.37865, lat: 39.86523, type: online, minZoom: 10, extra: { speed: 32, updated: 12:30 } } ];统一结构的好处是渲染逻辑只有一份图标类型、文字内容、显隐阈值全部从这里读。渲染时用一个工厂函数把 marker 和 label 一起建出来并且把两者的引用挂在数据对象上方便后续更新和删除function renderPoi(item, map) { var lnglat new T.LngLat(item.lng, item.lat); var marker new T.Marker(lnglat, { icon: buildIcon(item.type) }); map.addOverLay(marker); var label new T.Label({ text: item.name, position: lnglat, offset: calcLabelOffset(item.name, 12, 38, 4) }); label.setFontColor(#ffffff); label.setBackgroundColor(#333333); label.setFontSize(12); item._marker marker; item._label label; marker.addEventListener(click, function() { showDetail(item); }); }把_marker和_label挂在数据上删除时直接map.removeOverLay(item._marker)不用再去遍历地图的覆盖物列表。地图的getOverlays()返回的数组顺序不一定和你的数据顺序一致靠索引删很容易删错。4.2 点击弹窗、悬停高亮、右键菜单点击弹窗用T.InfoWindow这是标准做法var infoWin new T.InfoWindow(, { offset: new T.Point(0, -40) }); marker.addEventListener(click, function() { var html div stylefont-size:13px;line-height:1.6; b escapeHtml(item.name) /bbr 状态 escapeHtml(item.type) br 更新时间 escapeHtml(item.extra.updated) /div; infoWin.setContent(html); infoWin.setLngLat(item._marker.getLngLat()); map.openInfoWindow(infoWin); });offset设成(0, -40)是让弹窗出现在图标上方不然它会盖住图标。悬停高亮有两种做法一种是换图标一种是把图标放大一点点我更推荐换图标因为尺寸变化会引起重排视觉上有轻微跳动。右键菜单天地图的 Marker 没有直接支持需要监听地图的contextmenu事件再配合mouseover判断当前鼠标下面是不是你的点位。这套逻辑稍微绕简单项目里其实用点击弹窗就够了别为了右键菜单引入一堆状态判断。4.3 点位多了之后的三层优化手段第一层是数据量的裁剪。视野外的点位不用渲染监听moveend和zoomend只渲染当前视野范围外扩 20% 的点位。这个改动很简单但效果立竿见影1000 个点可能实际只渲染 100 个。第二层是网格聚合。当 zoom 比较小时把地图按一定网格切分同一格里的点合并成一个带数字的聚合图标。天地图 API 本身不提供聚合可以自己算function gridKey(lng, lat, zoom) { var size 0.02 * Math.pow(2, 12 - zoom); return Math.floor(lng / size) _ Math.floor(lat / size); }把 key 相同的点归到一组用组内第一个点作为聚合点的位置图标换成一个圆形的数字标记。这个算法的网格大小需要根据 zoom 调整不然小比例尺下全挤一块大比例尺下又不起作用。第三层是减少 Label 数量。Label 是纯 DOM 节点开销比 Marker 大得多。我的原则是同一屏内可见 Label 不超过 50 个超了就按重要性排序截断或者只在鼠标悬停时临时显示。点位数量建议策略大致帧率表现1 - 50直接渲染Label 全显流畅50 - 200Label 按 zoom 分级显示流畅200 - 800视野裁剪 网格聚合基本流畅800 以上裁剪 聚合 Label 悬停显示需要实测调优4.4 坐标拾取与数据核对流程数据从哪来常见的有三种后端数据库里存的经纬度、从其他地图平台导出的坐标、人工在地图上点出来的。前两种都要做坐标系核对第三种可以用天地图官网的坐标拾取工具。我的核对流程是这样的从数据集里随机抽 5 个点把它们在天地图上标出来同时在地图底图上找到对应的实际地物看落点是否吻合。如果发现有系统性偏移那大概率是坐标系问题需要整体转换如果是个别偏移那可能是数据录入错误需要单独修。还有一个小技巧如果你要人工采集坐标天地图的坐标拾取工具返回的就是 CGCS2000可以直接用省去转换这一步。采集的时候记得同时记录点位名称和类型我当时用表格批量采集了 200 多个点导出成 CSV 再转 JSON比一个个手写代码快得多。5. 常见报错与疑难问题的排查实录这一节是我在实际项目里遇到过的真实问题按现象分类整理方便你对照排查。5.1 key 相关的返回码与排查路径301001这个返回码基本就是 Key 的问题但它背后有好几种原因要一个个排查。第一种是 Key 根本不存在或者写错了比如大小写、多了空格。天地图的 Key 是一串 32 位字符串直接放进 URL 里如果是从文档里复制的很可能带了不可见字符建议用trim()处理一下。第二种是域名不匹配。浏览器端 Key 申请时绑了域名你在本地跑就会返回这个码。最快的验证方法是把 Key 换到官方示例页面试一次如果示例页正常那基本就是你的域名没绑对。第三种是服务类型没勾。地图 API 和地理编码 API 是分开授权的你以为申请了一个 Key 就万事大吉其实只勾了其中一项。第四种是配额耗尽。天地图的个人开发者有日调用量限制超了之后不一定返回明确的限流码有时也表现为这个错误。排查方法是在浏览器网络面板里看请求的响应体里面有详细信息。现象可能原因排查动作地图白屏控制台 301001Key 错误或域名未绑换官方示例页测试底图能出注记不出服务类型未勾选检查控制台授权项上午正常下午失败配额耗尽查看响应体详细信息本地失败线上正常域名绑定不含 localhost单独申请测试 Key5.2 图标不显示、位置偏移、重叠图标不显示先看网络面板有没有 404再看iconSize和iconAnchor是不是传成了数组而不是T.Point对象。天地图对参数类型比较严格传数组不会报错但图标就是不出来这个坑很隐蔽。位置偏移基本是锚点问题把iconAnchor设成图标底部中心再试。如果图标整体偏上或偏下一点点那可能是你的 PNG 图片本身四周有透明边距切图的时候没切干净这时候要么重新切图要么手动微调锚点。图标重叠分两种情况。如果是同一坐标的多个点完全重合那需要在数据层面做去重或者偏移处理常见做法是让重合的点按圆形散开每个偏移几个像素。如果是图标太大导致的视觉重叠那就按 zoom 分级缩小图标尺寸或者干脆在低 zoom 时只显示聚合点。5.3 文字备注显示异常文字被截断一般是 Label 的宽度限制或者 offset 把它推到了地图容器外调整 offset 或者用 DivOverlay 就解决了。文字模糊原因是高分屏下浏览器对 Label 的文字做了缩放。可以尝试把setFontSize调大一级或者改用 DivOverlay 让 CSS 接管。文字被底图注记淹没这是配色问题。底图注记一般是灰色或白色你的文字如果也是浅色在密集注记区域就会看不清。我通常给 Label 加一个深色半透明背景对比度立刻就上来了。5.4 移动端与高分屏表现移动端最大的差异是触摸事件和devicePixelRatio。触摸方面Marker 的点击在移动端会有 300 毫秒左右的延迟感建议给图标设置一个稍大的点击热区或者用T.Marker的draggable之外监听地图层面的click事件做坐标反查。高分屏方面前面已经提过两套图标的做法。另外要注意的是如果你在 CSS 里对地图容器做了缩放那图标的实际像素尺寸也会跟着变锚点算出来的位置就会有偏差所以地图容器尽量不要做transform: scale()。6. 我个人踩过的一些坑和给你的一份检查清单写到这儿关键的代码和参数都过了一遍。最后说点真实感受和几个不那么标准的经验。6.1 上线前我每次都会过一遍的检查清单这份清单是我打完包之后一定会照着走一遍的能拦下大部分低级问题Key 是否使用生产环境专用域名绑定是否覆盖所有可能的访问入口包括带 www 和不带 www 的。图标资源是否走 HTTPS路径是否是相对路径有没有被构建工具改写成绝对路径导致 404。所有图标是否预热完成网络面板里是否还有 pending 的图片请求。坐标系是否核对过随机抽 5 个点在地图上验证落点。Label 的 offset 是否在文字长度变化后仍然居中长名称有没有溢出。点位超过 200 时缩放和拖动是否卡顿视野裁剪逻辑是否真的生效了。弹窗内容是否做了 HTML 转义尤其是运营填写的备注字段。地图容器是否有明确的宽高用 flex 布局时有没有被压成 0 高度导致白屏。第八条我中招过两次页面结构里地图容器用了flex: 1但父级没有设高度结果地图高度是 0控制台没有任何报错只有一片空白排查了很久才想到是布局问题。6.2 几个真实踩坑记录含代价第一个坑是图标锚点和 CSS 的冲突。我在一个项目里为了做动画给图标外层加了 CSS 的transform: translateY(-50%)结果和iconAnchor叠加所有点位都往上飘了半个图标高度。这个问题的隐蔽之处在于它只在动画启用时出现禁用动画就正常所以一开始完全没怀疑到 CSS 上。第二个坑是 Label 的批量删除。我最初写的是遍历map.getOverlays()判断类型再删但天地图的覆盖物数组在删除过程中会动态变化导致删除时漏掉一部分。后来改成while循环不断删除第一个匹配项才干净。更稳妥的方式还是前面说的把引用自己存起来别依赖地图的返回值。第三个坑是坐标精度。后端存经纬度时用的是decimal(10,6)六位小数理论上精度到 0.1 米但我们有个数据导入流程用了float在批量计算过程中产生了累积误差某些点位偏了十几米。地图上看不出来但做距离计算时结果就不对了。后来统一改成整数存储乘以 1e6再用的时候除以 1e6彻底解决了。这些坑的共同点是都不报错都只是在特定条件下表现出来所以只能靠经验清单和充分的实测来拦住。我现在的习惯是每次地图相关的改动都要用三组数据测试一个点、五十个点、五百个点三种缩放级别各看一遍基本能覆盖大部分问题场景。
返回列表