1. 适用场景
面向 国内 App(uni-app + renderjs) 的农场地图:
- 展示农场地块多边形、阀门/网关设备点
- 手绘圈地、删除地块、点击地块拉设备列表
- 安装设备时在地图上选址(GCJ02)
- 长按设备调整安装位置
2. 为什么在 uni-app 里必须用 renderjs?
Vue 逻辑层运行在 App 的 JS 引擎里,不能直接操作 WebView 里的 DOM。高德 AMap.Map 必须跑在浏览器环境。
因此采用 双 Script 分层:

模板桥接:
javascript
<view :prop="propList" :change:prop="mapView.receiveAllProps" />
receiveAllProps 是 renderjs 侧的唯一入口,根据 editMode、drawStatus、isAddDevice 等切换地图行为。
3. 与父页面的数据契约(allProps)
index.vue 通过 updateAllPropsData 推送:
| 字段 | 含义 |
|---|---|
farmFloorData |
地块列表(坐标已在父层转为地图可用格式) |
valve |
当前地块设备列表 |
centerPoint |
农场中心 [lng, lat] |
drawStatus |
2 进入手绘地块 |
editMode |
1 正常 / 3 删除地块 |
isAddDevice |
是否开启安装选址 |
showScale / showGeolocation |
控件显隐 |
向父组件抛出的事件(与 Mapbox 版一致):
polygonData--- 手绘完成坐标(GCJ02)valveMarkerClick/valvePositionUpdatepositionSelected--- 安装选址handleDeviceListByZone/deleteFloor/updateFloorData
设计要点:地图组件只做「渲染 + 交互」,农场/设备业务仍在 index.vue。
4. 坐标系策略(高德方案的关键)
- 接口、uni 定位、
addFarm:GCJ-02 - 高德地图实例内部:也按 GCJ-02 使用(与国标一致,显示上最省事)
- 父页面
getAllFloor时会把接口 GCJ02 转成 WGS84 再传给地图
安装选址时,PositionPicker 返回的 positionResult.position 在代码里又做了一次:
javascript
coordtransform.wgs84togcj02(positionResult.position.lng, positionResult.position.lat)
统一坐标系标准:上报父组件、写库一律 GCJ02。
定位控件里则将高德定位结果 gcj02towgs84 后 panTo,用于在地图上标蓝点。
5. 地图初始化:高德引擎 + 非高德底图
initAMap() 并非默认高德卫星,而是 自定义 TileLayer 叠瓦片:
- 天地图影像
img_w(WMTS,TILEMATRIXSET=w) - Mapbox 卫星(
AMap.TileLayer,默认visible: false) - 天地图注记
cia_w
javascript
map = new AMap.Map("container", {
viewMode: '3D',
zoom: 17,
center: centerPointData,
layers: [tiandituImgLayer, mapboxSatelliteLayer, tiandituRoadLayer],
})
缩放分级切换(zoomchange):
zoom <= 17.5:天地图影像zoom > 17.5:隐藏天地图,显示 Mapbox 卫星
思路:日常用合规国内影像,放大看田块细节时用高清卫星。引擎仍是高德,底图可插拔。
还需配置:
javascript
window._AMapSecurityConfig = { securityJsCode: '...' }
AMapLoader.load({ key, version: '2.0', plugins: [...] })
插件包括 PolygonEditor、Geolocation、Scale 等。
6. 功能实现思路(按模块)
6.1 地块展示 initPolygon
map.remove(polygons)清旧多边形- 遍历
FloorList,coordinates→path,首尾闭合 new AMap.Polygon({ path, fillOpacity, strokeColor, extData })getBounds().getCenter()得到中心,再AMap.Marker显示地块名- 绑定
polygon.on('click')→handlePolygonClick
删除模式 edit === 3:红色虚线边框、加粗 stroke,提高可点区域。
选中逻辑:setOptions 改填充/描边,隐藏当前地块名称 Marker,调用 handleDeviceListByZone。
6.2 手绘地块 drawPolygon
map.on('click')采点 →polygonSaveTemp- 每点一个
AMap.Marker(红点) < 3点:AMap.Polyline虚线;>= 3点:AMap.Polygon预览- 页面 DOM
#point-next/#point-cancel(在index.vue)完成/撤销 - 完成 →
callMethod('drawFloor', polygonSaveTemp)→ 逻辑层 wgs84togcj02 →emit('polygonData')
撤销时用 map.clearMap() 再重绘临时图形(注意会清掉其它覆盖物,需之后 initPolygon 恢复)。
6.3 设备点 initValves / addMarker
AMap.Marker+ 自定义contentHTML(图标、状态角标、灌溉动画)- 点击 →
onValveMarkerClick - 长按 3s → 进入位置调整(需处理与
dragstart/zoomstart冲突,代码里用 document 级 touch 监听取消误触)
6.4 安装选址 initPositionPicker
动态加载 AMapUI + misc/PositionPicker:
javascript
positionPicker = new PositionPicker({ mode: 'dragMap', map })
positionPicker.start()
positionPicker.on('success', ...) // → onPositionSelected(GCJ02)
mode: 'dragMap':拖地图、中心不动
进入选址时 marker.setClickable(false),避免误点设备。
6.5 定位
AMap.Geolocation + complete 事件更新 locationMarker;error → 逻辑层 Toast。
7. 高德方案优缺点
优点
- 国内文档、示例、社区成熟
- GCJ02 与国标、微信/高德定位一致,少一层转换错误
Polygon、Marker、PositionPicker封装高,开发快- 可用
PolygonEditor做顶点编辑(插件已引入)
缺点
- 强依赖高德 Key + 安全密钥,商业条款与配额需单独评估
- 自定义底图(天地图 + Mapbox)仍绑在高德引擎上,架构略「拧」
clearMap()、多实例 Editor 容易造成状态难控- App WebView 里同时拉高德 UI、AMapUI、外部瓦片,包体与网络请求较多
8. 落地检查清单
- Key / securityJsCode / 域名白名单(H5)/ 包名(App)
- 确认存入地图的坐标系与接口一致(GCJ02)
- 手绘完成、选址、拖拽提交三条链路都做 GCJ02 输出
zoomchange切换底图时测试 17.5 临界闪烁- 删除模式与名称 Marker、polygon 点击去重(
FLOOR_POLYGON_CLICK_DEDUP_MS)