expo-gaode-map 2.2.30-next.0 → 2.2.30
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/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapModule.kt +4 -2
- package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapView.kt +117 -57
- package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapViewModule.kt +8 -15
- package/android/src/main/java/expo/modules/gaodemap/managers/UIManager.kt +20 -6
- package/android/src/main/java/expo/modules/gaodemap/overlays/ClusterView.kt +24 -13
- package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerBitmapRenderer.kt +351 -0
- package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerView.kt +94 -310
- package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerViewModule.kt +3 -3
- package/build/ExpoGaodeMapModule.d.ts +13 -5
- package/build/ExpoGaodeMapModule.d.ts.map +1 -1
- package/build/ExpoGaodeMapModule.js +166 -34
- package/build/ExpoGaodeMapModule.js.map +1 -1
- package/build/ExpoGaodeMapView.d.ts.map +1 -1
- package/build/ExpoGaodeMapView.js +12 -0
- package/build/ExpoGaodeMapView.js.map +1 -1
- package/build/components/AreaMaskOverlay.d.ts +5 -0
- package/build/components/AreaMaskOverlay.d.ts.map +1 -0
- package/build/components/AreaMaskOverlay.js +20 -0
- package/build/components/AreaMaskOverlay.js.map +1 -0
- package/build/components/FoldableMapView.d.ts.map +1 -1
- package/build/components/FoldableMapView.js +115 -104
- package/build/components/FoldableMapView.js.map +1 -1
- package/build/components/RouteOverlay.d.ts +5 -0
- package/build/components/RouteOverlay.d.ts.map +1 -0
- package/build/components/RouteOverlay.js +20 -0
- package/build/components/RouteOverlay.js.map +1 -0
- package/build/components/overlays/Cluster.d.ts.map +1 -1
- package/build/components/overlays/Cluster.js +12 -0
- package/build/components/overlays/Cluster.js.map +1 -1
- package/build/components/overlays/Marker.d.ts.map +1 -1
- package/build/components/overlays/Marker.js +86 -3
- package/build/components/overlays/Marker.js.map +1 -1
- package/build/hooks/useRoutePlayback.d.ts +4 -0
- package/build/hooks/useRoutePlayback.d.ts.map +1 -0
- package/build/hooks/useRoutePlayback.js +310 -0
- package/build/hooks/useRoutePlayback.js.map +1 -0
- package/build/index.d.ts +4 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +4 -2
- package/build/index.js.map +1 -1
- package/build/types/common.types.d.ts +29 -5
- package/build/types/common.types.d.ts.map +1 -1
- package/build/types/common.types.js +5 -5
- package/build/types/common.types.js.map +1 -1
- package/build/types/index.d.ts +3 -2
- package/build/types/index.d.ts.map +1 -1
- package/build/types/index.js.map +1 -1
- package/build/types/location.types.d.ts +28 -0
- package/build/types/location.types.d.ts.map +1 -1
- package/build/types/location.types.js +5 -0
- package/build/types/location.types.js.map +1 -1
- package/build/types/map-view.types.d.ts +22 -22
- package/build/types/map-view.types.d.ts.map +1 -1
- package/build/types/map-view.types.js.map +1 -1
- package/build/types/native-module.types.d.ts +2 -2
- package/build/types/native-module.types.d.ts.map +1 -1
- package/build/types/native-module.types.js.map +1 -1
- package/build/types/overlays.types.d.ts +14 -0
- package/build/types/overlays.types.d.ts.map +1 -1
- package/build/types/overlays.types.js.map +1 -1
- package/build/types/route-playback.types.d.ts +118 -0
- package/build/types/route-playback.types.d.ts.map +1 -0
- package/build/types/route-playback.types.js +2 -0
- package/build/types/route-playback.types.js.map +1 -0
- package/build/utils/RouteUtils.d.ts +8 -0
- package/build/utils/RouteUtils.d.ts.map +1 -0
- package/build/utils/RouteUtils.js +140 -0
- package/build/utils/RouteUtils.js.map +1 -0
- package/ios/ExpoGaodeMapModule.swift +41 -22
- package/ios/ExpoGaodeMapView.swift +236 -241
- package/ios/ExpoGaodeMapViewModule.swift +16 -11
- package/ios/managers/UIManager.swift +5 -4
- package/ios/modules/LocationManager.swift +32 -9
- package/ios/overlays/ClusterView.swift +114 -12
- package/ios/overlays/ClusterViewModule.swift +5 -1
- package/ios/overlays/MarkerView.swift +195 -18
- package/ios/overlays/MarkerViewModule.swift +7 -7
- package/package.json +6 -6
- package/build/utils/throttle.d.ts +0 -10
- package/build/utils/throttle.d.ts.map +0 -1
- package/build/utils/throttle.js +0 -19
- package/build/utils/throttle.js.map +0 -1
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
package expo.modules.gaodemap.overlays
|
|
2
|
+
|
|
3
|
+
import android.graphics.Bitmap
|
|
4
|
+
import android.graphics.Canvas
|
|
5
|
+
import android.graphics.Color
|
|
6
|
+
import android.graphics.Rect
|
|
7
|
+
import android.os.Handler
|
|
8
|
+
import android.os.Looper
|
|
9
|
+
import android.view.View
|
|
10
|
+
import android.view.ViewGroup
|
|
11
|
+
import android.widget.ImageView
|
|
12
|
+
import android.widget.TextView
|
|
13
|
+
import androidx.core.graphics.createBitmap
|
|
14
|
+
import expo.modules.gaodemap.companion.IconBitmapCache
|
|
15
|
+
import java.util.concurrent.CountDownLatch
|
|
16
|
+
import java.util.concurrent.TimeUnit
|
|
17
|
+
import kotlin.text.StringBuilder
|
|
18
|
+
|
|
19
|
+
internal data class MarkerBitmapSnapshot(
|
|
20
|
+
val keyPart: String,
|
|
21
|
+
val width: Int,
|
|
22
|
+
val height: Int,
|
|
23
|
+
) {
|
|
24
|
+
val fullCacheKey: String
|
|
25
|
+
get() = "$keyPart|${width}x${height}"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
internal object MarkerBitmapRenderer {
|
|
29
|
+
fun hasPendingAsyncImageContent(view: View?): Boolean {
|
|
30
|
+
view ?: return false
|
|
31
|
+
if (view.visibility != View.VISIBLE) return false
|
|
32
|
+
|
|
33
|
+
if (view is ImageView) {
|
|
34
|
+
val resolvedWidth = view.measuredWidth.takeIf { it > 0 } ?: view.width
|
|
35
|
+
val resolvedHeight = view.measuredHeight.takeIf { it > 0 } ?: view.height
|
|
36
|
+
if (resolvedWidth > 0 && resolvedHeight > 0 && view.drawable == null) {
|
|
37
|
+
return true
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (view is ViewGroup) {
|
|
42
|
+
for (index in 0 until view.childCount) {
|
|
43
|
+
if (hasPendingAsyncImageContent(view.getChildAt(index))) {
|
|
44
|
+
return true
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return false
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
fun resolveSnapshot(
|
|
53
|
+
container: ViewGroup,
|
|
54
|
+
customViewWidth: Int,
|
|
55
|
+
customViewHeight: Int,
|
|
56
|
+
cacheKey: String?,
|
|
57
|
+
): MarkerBitmapSnapshot? {
|
|
58
|
+
if (container.childCount == 0) {
|
|
59
|
+
return null
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
val child = container.getChildAt(0) ?: return null
|
|
63
|
+
if (hasPendingAsyncImageContent(child)) {
|
|
64
|
+
return null
|
|
65
|
+
}
|
|
66
|
+
val contentView = resolveRenderableContentView(child)
|
|
67
|
+
val contentBounds = computeContentBounds(child)
|
|
68
|
+
val measuredWidth =
|
|
69
|
+
contentBounds?.width()
|
|
70
|
+
?: contentView?.measuredWidth
|
|
71
|
+
?: child.measuredWidth
|
|
72
|
+
?: 0
|
|
73
|
+
val measuredHeight =
|
|
74
|
+
contentBounds?.height()
|
|
75
|
+
?: contentView?.measuredHeight
|
|
76
|
+
?: child.measuredHeight
|
|
77
|
+
?: 0
|
|
78
|
+
|
|
79
|
+
val finalWidth = if (measuredWidth > 0) measuredWidth else customViewWidth
|
|
80
|
+
val finalHeight = if (measuredHeight > 0) measuredHeight else customViewHeight
|
|
81
|
+
|
|
82
|
+
if (finalWidth <= 0 || finalHeight <= 0) {
|
|
83
|
+
return null
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
val fingerprint = computeViewFingerprint(container)
|
|
87
|
+
|
|
88
|
+
return MarkerBitmapSnapshot(
|
|
89
|
+
keyPart = cacheKey?.let { "$it|$fingerprint" } ?: fingerprint,
|
|
90
|
+
width = finalWidth,
|
|
91
|
+
height = finalHeight,
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
fun createBitmap(
|
|
96
|
+
container: ViewGroup,
|
|
97
|
+
snapshot: MarkerBitmapSnapshot,
|
|
98
|
+
customViewWidth: Int,
|
|
99
|
+
customViewHeight: Int,
|
|
100
|
+
mainHandler: Handler,
|
|
101
|
+
): Bitmap? {
|
|
102
|
+
IconBitmapCache.get(snapshot.fullCacheKey)?.let { return it }
|
|
103
|
+
|
|
104
|
+
val bitmap =
|
|
105
|
+
if (Looper.myLooper() == Looper.getMainLooper()) {
|
|
106
|
+
renderViewToBitmapInternal(
|
|
107
|
+
container = container,
|
|
108
|
+
finalWidth = snapshot.width,
|
|
109
|
+
finalHeight = snapshot.height,
|
|
110
|
+
customViewWidth = customViewWidth,
|
|
111
|
+
customViewHeight = customViewHeight,
|
|
112
|
+
)
|
|
113
|
+
} else {
|
|
114
|
+
val latch = CountDownLatch(1)
|
|
115
|
+
var result: Bitmap? = null
|
|
116
|
+
mainHandler.post {
|
|
117
|
+
try {
|
|
118
|
+
result =
|
|
119
|
+
renderViewToBitmapInternal(
|
|
120
|
+
container = container,
|
|
121
|
+
finalWidth = snapshot.width,
|
|
122
|
+
finalHeight = snapshot.height,
|
|
123
|
+
customViewWidth = customViewWidth,
|
|
124
|
+
customViewHeight = customViewHeight,
|
|
125
|
+
)
|
|
126
|
+
} finally {
|
|
127
|
+
latch.countDown()
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
latch.await(200, TimeUnit.MILLISECONDS)
|
|
132
|
+
} catch (_: InterruptedException) {
|
|
133
|
+
}
|
|
134
|
+
result
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
bitmap?.let { IconBitmapCache.put(snapshot.fullCacheKey, it) }
|
|
138
|
+
return bitmap
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
fun computeContentBounds(view: View?): Rect? {
|
|
142
|
+
view ?: return null
|
|
143
|
+
if (view.visibility != View.VISIBLE) return null
|
|
144
|
+
|
|
145
|
+
var resolvedBounds: Rect? = null
|
|
146
|
+
|
|
147
|
+
if (view is ViewGroup && view.childCount > 0) {
|
|
148
|
+
for (i in 0 until view.childCount) {
|
|
149
|
+
val child = view.getChildAt(i) ?: continue
|
|
150
|
+
val childBounds = computeContentBounds(child) ?: continue
|
|
151
|
+
val shiftedBounds = Rect(childBounds)
|
|
152
|
+
shiftedBounds.offset(child.left, child.top)
|
|
153
|
+
resolvedBounds =
|
|
154
|
+
if (resolvedBounds == null) {
|
|
155
|
+
shiftedBounds
|
|
156
|
+
} else {
|
|
157
|
+
Rect(resolvedBounds).apply { union(shiftedBounds) }
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
val hasOwnVisualBounds =
|
|
163
|
+
view.background != null ||
|
|
164
|
+
view.paddingLeft != 0 ||
|
|
165
|
+
view.paddingTop != 0 ||
|
|
166
|
+
view.paddingRight != 0 ||
|
|
167
|
+
view.paddingBottom != 0 ||
|
|
168
|
+
view !is ViewGroup
|
|
169
|
+
|
|
170
|
+
val ownWidth = view.measuredWidth.takeIf { it > 0 } ?: view.width
|
|
171
|
+
val ownHeight = view.measuredHeight.takeIf { it > 0 } ?: view.height
|
|
172
|
+
|
|
173
|
+
if (hasOwnVisualBounds && ownWidth > 0 && ownHeight > 0) {
|
|
174
|
+
val ownBounds = Rect(0, 0, ownWidth, ownHeight)
|
|
175
|
+
resolvedBounds =
|
|
176
|
+
if (resolvedBounds == null) {
|
|
177
|
+
ownBounds
|
|
178
|
+
} else {
|
|
179
|
+
Rect(resolvedBounds).apply { union(ownBounds) }
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return resolvedBounds
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
fun resolveRenderableContentView(view: View?): View? {
|
|
187
|
+
var current = view ?: return null
|
|
188
|
+
|
|
189
|
+
while (current is ViewGroup && current.childCount == 1) {
|
|
190
|
+
val next = current.getChildAt(0) ?: break
|
|
191
|
+
current = next
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return current
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
fun computeViewFingerprint(view: View?): String {
|
|
198
|
+
if (view == null) return "null"
|
|
199
|
+
|
|
200
|
+
val sb = StringBuilder()
|
|
201
|
+
val tag = view.tag
|
|
202
|
+
if (tag != null) {
|
|
203
|
+
sb.append("tag=").append(tag.toString()).append(";")
|
|
204
|
+
return sb.toString()
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
val contentDesc = view.contentDescription
|
|
208
|
+
if (!contentDesc.isNullOrEmpty()) {
|
|
209
|
+
sb.append("cdesc=").append(contentDesc.toString()).append(";")
|
|
210
|
+
return sb.toString()
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
fun appendFor(v: View) {
|
|
214
|
+
sb.append(v.javaClass.simpleName)
|
|
215
|
+
when (v) {
|
|
216
|
+
is TextView -> {
|
|
217
|
+
val text = v.text?.toString() ?: ""
|
|
218
|
+
if (text.isNotEmpty()) {
|
|
219
|
+
sb.append("[text=").append(text).append("]")
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
is ImageView -> {
|
|
224
|
+
val resId = v.tag
|
|
225
|
+
if (resId is Int && resId != 0) {
|
|
226
|
+
sb.append("[imgRes=").append(resId).append("]")
|
|
227
|
+
} else {
|
|
228
|
+
val drawable = v.drawable
|
|
229
|
+
if (drawable != null) {
|
|
230
|
+
sb.append("[drawableHash=").append(drawable.hashCode()).append("]")
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
sb.append(";")
|
|
236
|
+
if (v is ViewGroup) {
|
|
237
|
+
for (i in 0 until v.childCount) {
|
|
238
|
+
appendFor(v.getChildAt(i))
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
appendFor(view)
|
|
244
|
+
return sb.toString().take(1024)
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
private fun renderViewToBitmapInternal(
|
|
248
|
+
container: ViewGroup,
|
|
249
|
+
finalWidth: Int,
|
|
250
|
+
finalHeight: Int,
|
|
251
|
+
customViewWidth: Int,
|
|
252
|
+
customViewHeight: Int,
|
|
253
|
+
): Bitmap? {
|
|
254
|
+
try {
|
|
255
|
+
val childView = container.getChildAt(0) ?: return null
|
|
256
|
+
|
|
257
|
+
if (childView.width != finalWidth || childView.height != finalHeight) {
|
|
258
|
+
if (childView.width == 0 || childView.height == 0) {
|
|
259
|
+
return null
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
val widthSpec = View.MeasureSpec.makeMeasureSpec(finalWidth, View.MeasureSpec.EXACTLY)
|
|
263
|
+
val heightSpec = View.MeasureSpec.makeMeasureSpec(finalHeight, View.MeasureSpec.EXACTLY)
|
|
264
|
+
childView.measure(widthSpec, heightSpec)
|
|
265
|
+
childView.layout(0, 0, finalWidth, finalHeight)
|
|
266
|
+
} else if (childView.left != 0 || childView.top != 0) {
|
|
267
|
+
childView.layout(0, 0, finalWidth, finalHeight)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
val bitmap = createBitmap(finalWidth, finalHeight)
|
|
271
|
+
val canvas = Canvas(bitmap)
|
|
272
|
+
childView.draw(canvas)
|
|
273
|
+
|
|
274
|
+
val shouldTrimTransparentPadding = customViewWidth <= 0 && customViewHeight <= 0
|
|
275
|
+
return if (shouldTrimTransparentPadding) trimTransparentPadding(bitmap) else bitmap
|
|
276
|
+
} catch (_: Exception) {
|
|
277
|
+
return null
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
private fun trimTransparentPadding(bitmap: Bitmap): Bitmap {
|
|
282
|
+
if (bitmap.width <= 1 || bitmap.height <= 1) {
|
|
283
|
+
return bitmap
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (hasOpaquePixelsOnAllBitmapEdges(bitmap)) {
|
|
287
|
+
return bitmap
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
var minX = bitmap.width
|
|
291
|
+
var minY = bitmap.height
|
|
292
|
+
var maxX = -1
|
|
293
|
+
var maxY = -1
|
|
294
|
+
|
|
295
|
+
for (y in 0 until bitmap.height) {
|
|
296
|
+
for (x in 0 until bitmap.width) {
|
|
297
|
+
if (Color.alpha(bitmap.getPixel(x, y)) != 0) {
|
|
298
|
+
if (x < minX) minX = x
|
|
299
|
+
if (y < minY) minY = y
|
|
300
|
+
if (x > maxX) maxX = x
|
|
301
|
+
if (y > maxY) maxY = y
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (maxX < minX || maxY < minY) {
|
|
307
|
+
return bitmap
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
val trimmedWidth = maxX - minX + 1
|
|
311
|
+
val trimmedHeight = maxY - minY + 1
|
|
312
|
+
if (trimmedWidth == bitmap.width && trimmedHeight == bitmap.height) {
|
|
313
|
+
return bitmap
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return Bitmap.createBitmap(bitmap, minX, minY, trimmedWidth, trimmedHeight)
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
private fun hasOpaquePixelsOnAllBitmapEdges(bitmap: Bitmap): Boolean {
|
|
320
|
+
var topEdgeHasPixel = false
|
|
321
|
+
var bottomEdgeHasPixel = false
|
|
322
|
+
var leftEdgeHasPixel = false
|
|
323
|
+
var rightEdgeHasPixel = false
|
|
324
|
+
|
|
325
|
+
for (x in 0 until bitmap.width) {
|
|
326
|
+
if (!topEdgeHasPixel && Color.alpha(bitmap.getPixel(x, 0)) != 0) {
|
|
327
|
+
topEdgeHasPixel = true
|
|
328
|
+
}
|
|
329
|
+
if (!bottomEdgeHasPixel && Color.alpha(bitmap.getPixel(x, bitmap.height - 1)) != 0) {
|
|
330
|
+
bottomEdgeHasPixel = true
|
|
331
|
+
}
|
|
332
|
+
if (topEdgeHasPixel && bottomEdgeHasPixel) {
|
|
333
|
+
break
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
for (y in 0 until bitmap.height) {
|
|
338
|
+
if (!leftEdgeHasPixel && Color.alpha(bitmap.getPixel(0, y)) != 0) {
|
|
339
|
+
leftEdgeHasPixel = true
|
|
340
|
+
}
|
|
341
|
+
if (!rightEdgeHasPixel && Color.alpha(bitmap.getPixel(bitmap.width - 1, y)) != 0) {
|
|
342
|
+
rightEdgeHasPixel = true
|
|
343
|
+
}
|
|
344
|
+
if (leftEdgeHasPixel && rightEdgeHasPixel) {
|
|
345
|
+
break
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
return topEdgeHasPixel && bottomEdgeHasPixel && leftEdgeHasPixel && rightEdgeHasPixel
|
|
350
|
+
}
|
|
351
|
+
}
|