expo-gaode-map-navigation 2.0.13 → 2.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -15
- package/android/.project +34 -0
- package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapModule.kt +54 -52
- package/build/index.d.ts +26 -126
- package/build/index.d.ts.map +1 -1
- package/build/index.js +11 -612
- package/build/index.js.map +1 -1
- package/build/route-geometry.d.ts +13 -0
- package/build/route-geometry.d.ts.map +1 -0
- package/build/route-geometry.js +154 -0
- package/build/route-geometry.js.map +1 -0
- package/build/route-planning.d.ts +21 -0
- package/build/route-planning.d.ts.map +1 -0
- package/build/route-planning.js +67 -0
- package/build/route-planning.js.map +1 -0
- package/build/web-api-fallback.d.ts +5 -0
- package/build/web-api-fallback.d.ts.map +1 -0
- package/build/web-api-fallback.js +160 -0
- package/build/web-api-fallback.js.map +1 -0
- package/build/web-route-following.d.ts +3 -0
- package/build/web-route-following.d.ts.map +1 -0
- package/build/web-route-following.js +178 -0
- package/build/web-route-following.js.map +1 -0
- package/ios/map/modules/LocationManager.swift +2 -4
- package/ios/map/overlays/MarkerView.swift +54 -30
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
- 🗺️ **地图渲染**:内置完整地图能力,支持 Marker、Polyline、Polygon、Circle、Cluster、HeatMap 等覆盖物。
|
|
8
8
|
- 🔍 **原生搜索**:内置 POI 搜索、周边搜索、沿途搜索、输入提示、逆地理编码等搜索能力。
|
|
9
9
|
- 🚗 **多模式路径规划**:支持驾车、步行、骑行、电动车、货车、摩托车等多种出行方式。
|
|
10
|
-
- 🧭 **实时导航 UI**:提供 `
|
|
10
|
+
- 🧭 **实时导航 UI**:提供 `ExpoGaodeMapNaviView` 官方嵌入视图,并暴露完整事件与原生参数,方便你自行定制导航界面。
|
|
11
11
|
- 🛣️ **独立路径规划**:支持“先算路、再导航”的高级模式,可实现多路线对比与选择。
|
|
12
12
|
- ⚙️ **策略丰富**:支持速度优先、避让拥堵、少收费、不走高速等多种算路策略。
|
|
13
13
|
- ✅ **开箱即用**:封装了 Android/iOS 原生导航 SDK,统一 JS 接口。
|
|
@@ -30,7 +30,7 @@ npm install expo-gaode-map-navigation
|
|
|
30
30
|
**⚠️ 重要提示:**
|
|
31
31
|
如果项目中已安装 `expo-gaode-map`,请务必先卸载,否则会导致 Android 端二进制冲突(`3dmap` vs `navi-3dmap`)。`expo-gaode-map` 和 `expo-gaode-map-navigation` 由于 SDK 冲突不能同时安装,二选一使用。
|
|
32
32
|
|
|
33
|
-
`expo-gaode-map-search` 的独立集成只维护到 `2.2.33
|
|
33
|
+
`expo-gaode-map-search` 的独立集成只维护到 `2.2.33`。从 `2.0.13` 开始,搜索能力随 `expo-gaode-map` / `expo-gaode-map-navigation` 一起维护;在导航包中请直接从 `expo-gaode-map-navigation` 导入搜索 API。
|
|
34
34
|
|
|
35
35
|
高德官方 Android SDK 在 `10.0.700` 之后将远程依赖由“地图 + 定位”调整为“地图 + 定位 + 搜索”,依赖地址从 `com.amap.api:3dmap:latest.integration` 调整为 `com.amap.api:3dmap-location-search:latest.integration`。继续单独维护 search 模块会带来重复合包和依赖冲突成本,因此搜索能力改为随 core / navigation 一起维护。
|
|
36
36
|
|
|
@@ -80,8 +80,8 @@ npx expo run:ios
|
|
|
80
80
|
- `enableBackgroundAudio` 仅 iOS 生效(默认随 `enableBackgroundLocation` 自动开启),用于注入 `UIBackgroundModes: audio`,保障后台导航语音持续播报。
|
|
81
81
|
- `enableIOSLiveActivity` 仅 iOS 生效,用于注入 `NSSupportsLiveActivities`。
|
|
82
82
|
- `enableIOSLiveActivityFrequentUpdates` 仅 iOS 生效,用于注入 `NSSupportsLiveActivitiesFrequentUpdates`。
|
|
83
|
-
- 运行时还需要在 `
|
|
84
|
-
- iOS 运行时还需要在 `
|
|
83
|
+
- 运行时还需要在 `ExpoGaodeMapNaviView` 里显式传 `androidBackgroundNavigationNotificationEnabled={true}` 才会在应用退到后台后显示导航常驻通知。
|
|
84
|
+
- iOS 运行时还需要在 `ExpoGaodeMapNaviView` 里显式传 `iosLiveActivityEnabled={true}` 才会持续更新 Live Activity。
|
|
85
85
|
|
|
86
86
|
## 示例工程
|
|
87
87
|
|
|
@@ -89,7 +89,7 @@ npx expo run:ios
|
|
|
89
89
|
|
|
90
90
|
推荐场景:
|
|
91
91
|
|
|
92
|
-
- 调试 `
|
|
92
|
+
- 调试 `ExpoGaodeMapNaviView` 与示例工程里的自定义 HUD / 车道 HUD / 路况光柱
|
|
93
93
|
- 对比官方黑盒页、官方嵌入式页、自绘嵌入式页
|
|
94
94
|
- 验证独立算路、多路线选择、近似跟线导航
|
|
95
95
|
|
|
@@ -170,15 +170,16 @@ export default function BasicMapScreen() {
|
|
|
170
170
|
|
|
171
171
|
### 2. 嵌入导航视图
|
|
172
172
|
|
|
173
|
-
使用 `
|
|
173
|
+
使用 `ExpoGaodeMapNaviView` 组件直接嵌入导航界面:
|
|
174
174
|
|
|
175
175
|
```tsx
|
|
176
176
|
import React, { useEffect, useRef } from 'react';
|
|
177
177
|
import { View } from 'react-native';
|
|
178
|
-
import {
|
|
178
|
+
import { ExpoGaodeMapNaviView } from 'expo-gaode-map-navigation';
|
|
179
|
+
import type { ExpoGaodeMapNaviViewRef } from 'expo-gaode-map-navigation';
|
|
179
180
|
|
|
180
181
|
export default function NavigationScreen() {
|
|
181
|
-
const naviRef = useRef<
|
|
182
|
+
const naviRef = useRef<ExpoGaodeMapNaviViewRef>(null);
|
|
182
183
|
|
|
183
184
|
useEffect(() => {
|
|
184
185
|
// 延迟 1 秒后开始导航
|
|
@@ -196,7 +197,7 @@ export default function NavigationScreen() {
|
|
|
196
197
|
|
|
197
198
|
return (
|
|
198
199
|
<View style={{ flex: 1 }}>
|
|
199
|
-
<
|
|
200
|
+
<ExpoGaodeMapNaviView
|
|
200
201
|
ref={naviRef}
|
|
201
202
|
style={{ flex: 1 }}
|
|
202
203
|
showCamera={true} // 显示摄像头
|
|
@@ -211,17 +212,17 @@ export default function NavigationScreen() {
|
|
|
211
212
|
|
|
212
213
|
### 3. 自定义嵌入式导航 UI
|
|
213
214
|
|
|
214
|
-
如果你要做“嵌入在自己页面里的导航页”,库本身提供的是底层 `
|
|
215
|
+
如果你要做“嵌入在自己页面里的导航页”,库本身提供的是底层 `ExpoGaodeMapNaviView`、导航事件和原生参数;完整的自定义 HUD / 车道 HUD / 路况光柱参考实现,已经迁移到仓库内的 [`example-navigation`](/Volumes/xinxin/expo-gaode-map/example-navigation/README.md)。
|
|
215
216
|
|
|
216
217
|
建议做法:
|
|
217
218
|
|
|
218
|
-
- 用 `
|
|
219
|
+
- 用 `ExpoGaodeMapNaviView` 负责底层导航地图、语音、车道事件、路况事件、路口大图事件
|
|
219
220
|
- 用 `onNaviInfoUpdate`、`onLaneInfoUpdate`、`onTrafficStatusesUpdate`、`onNaviVisualStateChange` 在业务侧自绘 HUD
|
|
220
221
|
- 直接参考 `example-navigation/lib/navigation-ui/EmbeddedNaviView.tsx` 及配套 UI 文件,按你的产品需求裁剪
|
|
221
222
|
|
|
222
223
|
注意:
|
|
223
224
|
|
|
224
|
-
- Android 官方嵌入式 `
|
|
225
|
+
- Android 官方嵌入式 `ExpoGaodeMapNaviView` 在部分 React Native / Expo 宿主中,顶部信息区、车道条、路口大图联动效果可能与高德官方 Demo 不完全一致
|
|
225
226
|
- 如果你要验证官方嵌入式 UI 本身,请直接跑 `example-navigation` 里的 `official-embedded` 示例页
|
|
226
227
|
- 如果你要交付稳定的嵌入式导航页,建议以示例工程里的“自定义 UI 导航界面”作为起点
|
|
227
228
|
|
|
@@ -494,6 +495,13 @@ const result = await calculateTransitRoute({
|
|
|
494
495
|
- 可共享的范围仅限纯 TS 的 route / AOI 数据适配工具、文档和测试思路
|
|
495
496
|
- 原生地图桥接、overlay 宿主逻辑、MapView facade 不会和核心包合并
|
|
496
497
|
|
|
498
|
+
### 导入入口
|
|
499
|
+
|
|
500
|
+
- 运行时能力优先使用命名导出,例如 `calculateRoute`、`ExpoGaodeMapNaviView`、`openOfficialNaviPage`
|
|
501
|
+
- 类型请用 `import type`,例如 `RouteOptions`、`FollowWebPlannedRouteResult`
|
|
502
|
+
- 默认导出保留给需要整包挂载的场景,内容与常用路径规划和导航函数一致
|
|
503
|
+
- `NaviView` / `NaviViewRef` 仍作为兼容别名保留,新代码建议使用 `ExpoGaodeMapNaviView` / `ExpoGaodeMapNaviViewRef`
|
|
504
|
+
|
|
497
505
|
## API 参考
|
|
498
506
|
|
|
499
507
|
### DriveStrategy (驾车策略)
|
|
@@ -527,7 +535,7 @@ const result = await calculateTransitRoute({
|
|
|
527
535
|
- 基于 `onTrafficStatusesUpdate` 的自绘路况光柱
|
|
528
536
|
- “全览 / 锁车”与路况开关等浮层控制按钮
|
|
529
537
|
|
|
530
|
-
###
|
|
538
|
+
### ExpoGaodeMapNaviView Props
|
|
531
539
|
|
|
532
540
|
| 属性 | 类型 | 说明 |
|
|
533
541
|
|---|---|---|
|
|
@@ -569,7 +577,7 @@ const result = await calculateTransitRoute({
|
|
|
569
577
|
| `onNaviInfoUpdate` | function | 导航信息更新(剩余距离、时间等) |
|
|
570
578
|
| `onLaneInfoUpdate` | function | Android / iOS 车道信息更新,用于自绘车道 HUD |
|
|
571
579
|
|
|
572
|
-
###
|
|
580
|
+
### ExpoGaodeMapNaviView UI 能力清单
|
|
573
581
|
|
|
574
582
|
已开放且两端都有实现:
|
|
575
583
|
|
|
@@ -641,7 +649,7 @@ const result = await calculateTransitRoute({
|
|
|
641
649
|
2. **Web API**:如果需要更灵活的 HTTP 算路(如公交跨城规划、Web端展示),推荐配合 `expo-gaode-map-web-api` 使用。
|
|
642
650
|
3. **权限**:使用导航功能前,请确保应用已获取定位权限(`ACCESS_FINE_LOCATION`)。
|
|
643
651
|
4. **Android 状态栏兼容性**:`naviStatusBarEnabled` 依赖高德 Android 导航 SDK 某些版本才提供的 `AMapNaviViewOptions.setNaviStatusBarEnabled(...)`。当前封装已做兼容处理:若宿主工程解析到的 SDK 不包含该方法,则不会再编译失败,而是在运行时跳过该设置并输出 warning。此时该 prop 在 Android 上等价于 no-op。
|
|
644
|
-
5. **嵌入式 UI 边界**:库导出的是底层 `
|
|
652
|
+
5. **嵌入式 UI 边界**:库导出的是底层 `ExpoGaodeMapNaviView` 能力;完整自定义导航界面请参考 `example-navigation` 里的示例实现,它也不是高德官方黑盒导航页的 UI 替代品。
|
|
645
653
|
|
|
646
654
|
|
|
647
655
|
## 📚 文档与资源
|
package/android/.project
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<projectDescription>
|
|
3
|
+
<name>expo-gaode-map-navigation</name>
|
|
4
|
+
<comment>Project example-navigation-android-expo-gaode-map-navigation created by Buildship.</comment>
|
|
5
|
+
<projects>
|
|
6
|
+
</projects>
|
|
7
|
+
<buildSpec>
|
|
8
|
+
<buildCommand>
|
|
9
|
+
<name>org.eclipse.jdt.core.javabuilder</name>
|
|
10
|
+
<arguments>
|
|
11
|
+
</arguments>
|
|
12
|
+
</buildCommand>
|
|
13
|
+
<buildCommand>
|
|
14
|
+
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
|
|
15
|
+
<arguments>
|
|
16
|
+
</arguments>
|
|
17
|
+
</buildCommand>
|
|
18
|
+
</buildSpec>
|
|
19
|
+
<natures>
|
|
20
|
+
<nature>org.eclipse.jdt.core.javanature</nature>
|
|
21
|
+
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
|
|
22
|
+
</natures>
|
|
23
|
+
<filteredResources>
|
|
24
|
+
<filter>
|
|
25
|
+
<id>1778483172220</id>
|
|
26
|
+
<name></name>
|
|
27
|
+
<type>30</type>
|
|
28
|
+
<matcher>
|
|
29
|
+
<id>org.eclipse.core.resources.regexFilterMatcher</id>
|
|
30
|
+
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
|
|
31
|
+
</matcher>
|
|
32
|
+
</filter>
|
|
33
|
+
</filteredResources>
|
|
34
|
+
</projectDescription>
|
|
@@ -27,6 +27,8 @@ class ExpoGaodeMapModule : Module() {
|
|
|
27
27
|
/** 定位管理器实例 */
|
|
28
28
|
private var locationManager: LocationManager? = null
|
|
29
29
|
|
|
30
|
+
private fun jsValue(value: Any?): Any? = value
|
|
31
|
+
|
|
30
32
|
override fun definition() = ModuleDefinition {
|
|
31
33
|
Name("ExpoGaodeMap")
|
|
32
34
|
|
|
@@ -93,7 +95,7 @@ class ExpoGaodeMapModule : Module() {
|
|
|
93
95
|
}
|
|
94
96
|
|
|
95
97
|
Function("getPrivacyStatus") {
|
|
96
|
-
SDKInitializer.getPrivacyStatus()
|
|
98
|
+
jsValue(SDKInitializer.getPrivacyStatus())
|
|
97
99
|
}
|
|
98
100
|
|
|
99
101
|
/**
|
|
@@ -109,14 +111,14 @@ class ExpoGaodeMapModule : Module() {
|
|
|
109
111
|
* @return SDK 版本号
|
|
110
112
|
*/
|
|
111
113
|
Function("getVersion") {
|
|
112
|
-
SDKInitializer.getVersion()
|
|
114
|
+
jsValue(SDKInitializer.getVersion())
|
|
113
115
|
}
|
|
114
116
|
|
|
115
117
|
/**
|
|
116
118
|
* 检查原生 SDK 是否已配置 API Key
|
|
117
119
|
*/
|
|
118
120
|
Function("isNativeSDKConfigured") {
|
|
119
|
-
try {
|
|
121
|
+
jsValue(try {
|
|
120
122
|
val context = appContext.reactContext!!
|
|
121
123
|
val apiKey = context.packageManager
|
|
122
124
|
.getApplicationInfo(context.packageName, android.content.pm.PackageManager.GET_META_DATA)
|
|
@@ -124,7 +126,7 @@ class ExpoGaodeMapModule : Module() {
|
|
|
124
126
|
!apiKey.isNullOrEmpty()
|
|
125
127
|
} catch (_: Exception) {
|
|
126
128
|
false
|
|
127
|
-
}
|
|
129
|
+
})
|
|
128
130
|
}
|
|
129
131
|
|
|
130
132
|
|
|
@@ -187,11 +189,11 @@ class ExpoGaodeMapModule : Module() {
|
|
|
187
189
|
Function("distanceBetweenCoordinates") { p1: Map<String, Any>?, p2: Map<String, Any>? ->
|
|
188
190
|
val coord1 = LatLngParser.parseLatLng(p1)
|
|
189
191
|
val coord2 = LatLngParser.parseLatLng(p2)
|
|
190
|
-
if (coord1 != null && coord2 != null) {
|
|
192
|
+
jsValue(if (coord1 != null && coord2 != null) {
|
|
191
193
|
GeometryUtils.calculateDistance(coord1, coord2)
|
|
192
194
|
} else {
|
|
193
195
|
0.0
|
|
194
|
-
}
|
|
196
|
+
})
|
|
195
197
|
}
|
|
196
198
|
|
|
197
199
|
/**
|
|
@@ -213,16 +215,16 @@ class ExpoGaodeMapModule : Module() {
|
|
|
213
215
|
val normalized = LatLngParser.parseLatLngList(points)
|
|
214
216
|
val safeMinZoom = minZoom ?: 3
|
|
215
217
|
val safeMaxZoom = maxZoom ?: 20
|
|
216
|
-
if (normalized.isEmpty()) return@Function safeMinZoom.toDouble()
|
|
218
|
+
if (normalized.isEmpty()) return@Function jsValue(safeMinZoom.toDouble())
|
|
217
219
|
|
|
218
|
-
GeometryUtils.calculateFitZoom(
|
|
220
|
+
jsValue(GeometryUtils.calculateFitZoom(
|
|
219
221
|
normalized,
|
|
220
222
|
viewportWidthPx ?: 390.0,
|
|
221
223
|
viewportHeightPx ?: 844.0,
|
|
222
224
|
paddingPx ?: 48.0,
|
|
223
225
|
safeMinZoom,
|
|
224
226
|
safeMaxZoom
|
|
225
|
-
)
|
|
227
|
+
))
|
|
226
228
|
}
|
|
227
229
|
|
|
228
230
|
/**
|
|
@@ -232,7 +234,7 @@ class ExpoGaodeMapModule : Module() {
|
|
|
232
234
|
*/
|
|
233
235
|
Function("calculatePolygonArea") { points: List<Any>? ->
|
|
234
236
|
val rings = LatLngParser.parseLatLngListList(points)
|
|
235
|
-
if (rings.isEmpty()) return@Function 0.0
|
|
237
|
+
if (rings.isEmpty()) return@Function jsValue(0.0)
|
|
236
238
|
|
|
237
239
|
// 第一项是外轮廓
|
|
238
240
|
var totalArea = GeometryUtils.calculatePolygonArea(rings[0])
|
|
@@ -245,7 +247,7 @@ class ExpoGaodeMapModule : Module() {
|
|
|
245
247
|
}
|
|
246
248
|
|
|
247
249
|
// 确保面积不为负数
|
|
248
|
-
max(0.0, totalArea)
|
|
250
|
+
jsValue(max(0.0, totalArea))
|
|
249
251
|
}
|
|
250
252
|
|
|
251
253
|
/**
|
|
@@ -255,24 +257,24 @@ class ExpoGaodeMapModule : Module() {
|
|
|
255
257
|
* @return 是否在多边形内
|
|
256
258
|
*/
|
|
257
259
|
Function("isPointInPolygon") { point: Map<String, Any>?, polygon: List<Any>? ->
|
|
258
|
-
val pt = LatLngParser.parseLatLng(point) ?: return@Function false
|
|
260
|
+
val pt = LatLngParser.parseLatLng(point) ?: return@Function jsValue(false)
|
|
259
261
|
val rings = LatLngParser.parseLatLngListList(polygon)
|
|
260
|
-
if (rings.isEmpty()) return@Function false
|
|
262
|
+
if (rings.isEmpty()) return@Function jsValue(false)
|
|
261
263
|
|
|
262
264
|
// 点必须在外轮廓内
|
|
263
265
|
val inOuter = GeometryUtils.isPointInPolygon(pt, rings[0])
|
|
264
|
-
if (!inOuter) return@Function false
|
|
266
|
+
if (!inOuter) return@Function jsValue(false)
|
|
265
267
|
|
|
266
268
|
// 点不能在任何内孔内
|
|
267
269
|
if (rings.size > 1) {
|
|
268
270
|
for (i in 1 until rings.size) {
|
|
269
271
|
if (GeometryUtils.isPointInPolygon(pt, rings[i])) {
|
|
270
|
-
return@Function false
|
|
272
|
+
return@Function jsValue(false)
|
|
271
273
|
}
|
|
272
274
|
}
|
|
273
275
|
}
|
|
274
276
|
|
|
275
|
-
true
|
|
277
|
+
jsValue(true)
|
|
276
278
|
}
|
|
277
279
|
|
|
278
280
|
/**
|
|
@@ -285,11 +287,11 @@ class ExpoGaodeMapModule : Module() {
|
|
|
285
287
|
Function("isPointInCircle") { point: Map<String, Any>?, center: Map<String, Any>?, radius: Double ->
|
|
286
288
|
val pt = LatLngParser.parseLatLng(point)
|
|
287
289
|
val cn = LatLngParser.parseLatLng(center)
|
|
288
|
-
if (pt != null && cn != null) {
|
|
290
|
+
jsValue(if (pt != null && cn != null) {
|
|
289
291
|
GeometryUtils.isPointInCircle(pt, cn, radius)
|
|
290
292
|
} else {
|
|
291
293
|
false
|
|
292
|
-
}
|
|
294
|
+
})
|
|
293
295
|
}
|
|
294
296
|
|
|
295
297
|
/**
|
|
@@ -301,11 +303,11 @@ class ExpoGaodeMapModule : Module() {
|
|
|
301
303
|
Function("calculateRectangleArea") { southWest: Map<String, Any>?, northEast: Map<String, Any>? ->
|
|
302
304
|
val sw = LatLngParser.parseLatLng(southWest)
|
|
303
305
|
val ne = LatLngParser.parseLatLng(northEast)
|
|
304
|
-
if (sw != null && ne != null) {
|
|
306
|
+
jsValue(if (sw != null && ne != null) {
|
|
305
307
|
GeometryUtils.calculateRectangleArea(sw, ne)
|
|
306
308
|
} else {
|
|
307
309
|
0.0
|
|
308
|
-
}
|
|
310
|
+
})
|
|
309
311
|
}
|
|
310
312
|
|
|
311
313
|
/**
|
|
@@ -318,7 +320,7 @@ class ExpoGaodeMapModule : Module() {
|
|
|
318
320
|
val pathPoints = LatLngParser.parseLatLngList(path)
|
|
319
321
|
val targetPoint = LatLngParser.parseLatLng(target)
|
|
320
322
|
|
|
321
|
-
if (targetPoint != null && pathPoints.isNotEmpty()) {
|
|
323
|
+
jsValue(if (targetPoint != null && pathPoints.isNotEmpty()) {
|
|
322
324
|
val result = GeometryUtils.getNearestPointOnPath(pathPoints, targetPoint)
|
|
323
325
|
if (result != null) {
|
|
324
326
|
mapOf(
|
|
@@ -332,7 +334,7 @@ class ExpoGaodeMapModule : Module() {
|
|
|
332
334
|
}
|
|
333
335
|
} else {
|
|
334
336
|
null
|
|
335
|
-
}
|
|
337
|
+
})
|
|
336
338
|
}
|
|
337
339
|
|
|
338
340
|
/**
|
|
@@ -342,16 +344,16 @@ class ExpoGaodeMapModule : Module() {
|
|
|
342
344
|
*/
|
|
343
345
|
Function("calculateCentroid") { polygon: List<Any>? ->
|
|
344
346
|
val rings = LatLngParser.parseLatLngListList(polygon)
|
|
345
|
-
if (rings.isEmpty()) return@Function null
|
|
347
|
+
if (rings.isEmpty()) return@Function jsValue(null)
|
|
346
348
|
|
|
347
349
|
if (rings.size == 1) {
|
|
348
350
|
val result = GeometryUtils.calculateCentroid(rings[0])
|
|
349
|
-
return@Function result?.let {
|
|
351
|
+
return@Function jsValue(result?.let {
|
|
350
352
|
mapOf(
|
|
351
353
|
"latitude" to it.latitude,
|
|
352
354
|
"longitude" to it.longitude
|
|
353
355
|
)
|
|
354
|
-
}
|
|
356
|
+
})
|
|
355
357
|
}
|
|
356
358
|
|
|
357
359
|
// 带孔多边形的质心计算: Σ(Area_i * Centroid_i) / Σ(Area_i)
|
|
@@ -376,14 +378,14 @@ class ExpoGaodeMapModule : Module() {
|
|
|
376
378
|
}
|
|
377
379
|
}
|
|
378
380
|
|
|
379
|
-
if (abs(totalArea) > 1e-9) {
|
|
381
|
+
jsValue(if (abs(totalArea) > 1e-9) {
|
|
380
382
|
mapOf(
|
|
381
383
|
"latitude" to sumLat / totalArea,
|
|
382
384
|
"longitude" to sumLon / totalArea
|
|
383
385
|
)
|
|
384
386
|
} else {
|
|
385
387
|
null
|
|
386
|
-
}
|
|
388
|
+
})
|
|
387
389
|
}
|
|
388
390
|
|
|
389
391
|
/**
|
|
@@ -393,10 +395,10 @@ class ExpoGaodeMapModule : Module() {
|
|
|
393
395
|
*/
|
|
394
396
|
Function("calculatePathBounds") { pointsList: List<Any>? ->
|
|
395
397
|
val points = LatLngParser.parseLatLngList(pointsList)
|
|
396
|
-
if (points.isEmpty()) return@Function null
|
|
398
|
+
if (points.isEmpty()) return@Function jsValue(null)
|
|
397
399
|
|
|
398
400
|
val result = GeometryUtils.calculatePathBounds(points)
|
|
399
|
-
result?.let {
|
|
401
|
+
jsValue(result?.let {
|
|
400
402
|
mapOf(
|
|
401
403
|
"north" to it.north,
|
|
402
404
|
"south" to it.south,
|
|
@@ -407,7 +409,7 @@ class ExpoGaodeMapModule : Module() {
|
|
|
407
409
|
"longitude" to it.centerLon
|
|
408
410
|
)
|
|
409
411
|
)
|
|
410
|
-
}
|
|
412
|
+
})
|
|
411
413
|
}
|
|
412
414
|
|
|
413
415
|
/**
|
|
@@ -418,11 +420,11 @@ class ExpoGaodeMapModule : Module() {
|
|
|
418
420
|
*/
|
|
419
421
|
Function("encodeGeoHash") { coordinate: Map<String, Any>?, precision: Int ->
|
|
420
422
|
val latLng = LatLngParser.parseLatLng(coordinate)
|
|
421
|
-
if (latLng != null) {
|
|
423
|
+
jsValue(if (latLng != null) {
|
|
422
424
|
GeometryUtils.encodeGeoHash(latLng, precision)
|
|
423
425
|
} else {
|
|
424
426
|
""
|
|
425
|
-
}
|
|
427
|
+
})
|
|
426
428
|
}
|
|
427
429
|
|
|
428
430
|
/**
|
|
@@ -434,12 +436,12 @@ class ExpoGaodeMapModule : Module() {
|
|
|
434
436
|
Function("simplifyPolyline") { points: List<Any>?, tolerance: Double ->
|
|
435
437
|
val poly = LatLngParser.parseLatLngList(points)
|
|
436
438
|
val simplified = GeometryUtils.simplifyPolyline(poly, tolerance)
|
|
437
|
-
simplified.map {
|
|
439
|
+
jsValue(simplified.map {
|
|
438
440
|
mapOf(
|
|
439
441
|
"latitude" to it.latitude,
|
|
440
442
|
"longitude" to it.longitude
|
|
441
443
|
)
|
|
442
|
-
}
|
|
444
|
+
})
|
|
443
445
|
}
|
|
444
446
|
|
|
445
447
|
/**
|
|
@@ -449,7 +451,7 @@ class ExpoGaodeMapModule : Module() {
|
|
|
449
451
|
*/
|
|
450
452
|
Function("calculatePathLength") { points: List<Any>? ->
|
|
451
453
|
val poly = LatLngParser.parseLatLngList(points)
|
|
452
|
-
GeometryUtils.calculatePathLength(poly)
|
|
454
|
+
jsValue(GeometryUtils.calculatePathLength(poly))
|
|
453
455
|
}
|
|
454
456
|
|
|
455
457
|
/**
|
|
@@ -459,12 +461,12 @@ class ExpoGaodeMapModule : Module() {
|
|
|
459
461
|
*/
|
|
460
462
|
Function("parsePolyline") { polylineStr: String? ->
|
|
461
463
|
val result = GeometryUtils.parsePolyline(polylineStr)
|
|
462
|
-
result.map {
|
|
464
|
+
jsValue(result.map {
|
|
463
465
|
mapOf(
|
|
464
466
|
"latitude" to it.latitude,
|
|
465
467
|
"longitude" to it.longitude
|
|
466
468
|
)
|
|
467
|
-
}
|
|
469
|
+
})
|
|
468
470
|
}
|
|
469
471
|
|
|
470
472
|
/**
|
|
@@ -476,7 +478,7 @@ class ExpoGaodeMapModule : Module() {
|
|
|
476
478
|
Function("getPointAtDistance") { points: List<Any>?, distance: Double ->
|
|
477
479
|
val poly = LatLngParser.parseLatLngList(points)
|
|
478
480
|
val result = GeometryUtils.getPointAtDistance(poly, distance)
|
|
479
|
-
if (result != null) {
|
|
481
|
+
jsValue(if (result != null) {
|
|
480
482
|
mapOf(
|
|
481
483
|
"latitude" to result.point.latitude,
|
|
482
484
|
"longitude" to result.point.longitude,
|
|
@@ -484,7 +486,7 @@ class ExpoGaodeMapModule : Module() {
|
|
|
484
486
|
)
|
|
485
487
|
} else {
|
|
486
488
|
null
|
|
487
|
-
}
|
|
489
|
+
})
|
|
488
490
|
}
|
|
489
491
|
|
|
490
492
|
/**
|
|
@@ -495,7 +497,7 @@ class ExpoGaodeMapModule : Module() {
|
|
|
495
497
|
*/
|
|
496
498
|
Function("latLngToTile") { coordinate: Map<String, Any>?, zoom: Int ->
|
|
497
499
|
val latLng = LatLngParser.parseLatLng(coordinate)
|
|
498
|
-
if (latLng != null) {
|
|
500
|
+
jsValue(if (latLng != null) {
|
|
499
501
|
val result = GeometryUtils.latLngToTile(latLng, zoom)
|
|
500
502
|
if (result != null && result.size >= 2) {
|
|
501
503
|
mapOf("x" to result[0], "y" to result[1])
|
|
@@ -504,7 +506,7 @@ class ExpoGaodeMapModule : Module() {
|
|
|
504
506
|
}
|
|
505
507
|
} else {
|
|
506
508
|
null
|
|
507
|
-
}
|
|
509
|
+
})
|
|
508
510
|
}
|
|
509
511
|
|
|
510
512
|
/**
|
|
@@ -517,9 +519,9 @@ class ExpoGaodeMapModule : Module() {
|
|
|
517
519
|
val y = (tile?.get("y") as? Number)?.toInt() ?: 0
|
|
518
520
|
val zoom = (tile?.get("z") as? Number)?.toInt() ?: (tile?.get("zoom") as? Number)?.toInt() ?: 0
|
|
519
521
|
val result = GeometryUtils.tileToLatLng(x, y, zoom)
|
|
520
|
-
result?.let {
|
|
522
|
+
jsValue(result?.let {
|
|
521
523
|
mapOf("latitude" to it.latitude, "longitude" to it.longitude)
|
|
522
|
-
}
|
|
524
|
+
})
|
|
523
525
|
}
|
|
524
526
|
|
|
525
527
|
/**
|
|
@@ -530,7 +532,7 @@ class ExpoGaodeMapModule : Module() {
|
|
|
530
532
|
*/
|
|
531
533
|
Function("latLngToPixel") { coordinate: Map<String, Any>?, zoom: Int ->
|
|
532
534
|
val latLng = LatLngParser.parseLatLng(coordinate)
|
|
533
|
-
if (latLng != null) {
|
|
535
|
+
jsValue(if (latLng != null) {
|
|
534
536
|
val result = GeometryUtils.latLngToPixel(latLng, zoom)
|
|
535
537
|
if (result != null && result.size >= 2) {
|
|
536
538
|
mapOf("x" to result[0], "y" to result[1])
|
|
@@ -539,7 +541,7 @@ class ExpoGaodeMapModule : Module() {
|
|
|
539
541
|
}
|
|
540
542
|
} else {
|
|
541
543
|
null
|
|
542
|
-
}
|
|
544
|
+
})
|
|
543
545
|
}
|
|
544
546
|
|
|
545
547
|
/**
|
|
@@ -552,9 +554,9 @@ class ExpoGaodeMapModule : Module() {
|
|
|
552
554
|
val x = (pixel?.get("x") as? Number)?.toDouble() ?: 0.0
|
|
553
555
|
val y = (pixel?.get("y") as? Number)?.toDouble() ?: 0.0
|
|
554
556
|
val result = GeometryUtils.pixelToLatLng(x, y, zoom)
|
|
555
|
-
result?.let {
|
|
557
|
+
jsValue(result?.let {
|
|
556
558
|
mapOf("latitude" to it.latitude, "longitude" to it.longitude)
|
|
557
|
-
}
|
|
559
|
+
})
|
|
558
560
|
}
|
|
559
561
|
|
|
560
562
|
/**
|
|
@@ -566,11 +568,11 @@ class ExpoGaodeMapModule : Module() {
|
|
|
566
568
|
Function("findPointInPolygons") { point: Map<String, Any>?, polygons: List<List<Any>>? ->
|
|
567
569
|
val pt = LatLngParser.parseLatLng(point)
|
|
568
570
|
val polys = polygons?.map { LatLngParser.parseLatLngList(it) }
|
|
569
|
-
if (pt != null && polys != null) {
|
|
571
|
+
jsValue(if (pt != null && polys != null) {
|
|
570
572
|
GeometryUtils.findPointInPolygons(pt, polys)
|
|
571
573
|
} else {
|
|
572
574
|
-1
|
|
573
|
-
}
|
|
575
|
+
})
|
|
574
576
|
}
|
|
575
577
|
|
|
576
578
|
/**
|
|
@@ -579,7 +581,7 @@ class ExpoGaodeMapModule : Module() {
|
|
|
579
581
|
* @param gridSizeMeters 网格大小(米)
|
|
580
582
|
*/
|
|
581
583
|
Function("generateHeatmapGrid") { points: List<Map<String, Any>>?, gridSizeMeters: Double ->
|
|
582
|
-
if (points == null || points.isEmpty()) return@Function emptyList<Map<String, Any>>()
|
|
584
|
+
if (points == null || points.isEmpty()) return@Function jsValue(emptyList<Map<String, Any>>())
|
|
583
585
|
|
|
584
586
|
val count = points.size
|
|
585
587
|
val latitudes = DoubleArray(count)
|
|
@@ -593,13 +595,13 @@ class ExpoGaodeMapModule : Module() {
|
|
|
593
595
|
}
|
|
594
596
|
|
|
595
597
|
val result = GeometryUtils.generateHeatmapGrid(latitudes, longitudes, weights, gridSizeMeters)
|
|
596
|
-
result.map {
|
|
598
|
+
jsValue(result.map {
|
|
597
599
|
mapOf(
|
|
598
600
|
"latitude" to it.latitude,
|
|
599
601
|
"longitude" to it.longitude,
|
|
600
602
|
"intensity" to it.intensity
|
|
601
603
|
)
|
|
602
|
-
}
|
|
604
|
+
})
|
|
603
605
|
}
|
|
604
606
|
|
|
605
607
|
// ==================== 定位配置 ====================
|