expo-arcgis 0.2.6 → 0.3.0
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/arcgis/ExpoArcgisExtrasModule.kt +3 -5
- package/android/src/main/java/expo/modules/arcgis/ExpoArcgisGeometryModule.kt +8 -0
- package/android/src/main/java/expo/modules/arcgis/ExpoArcgisMapView.kt +9 -0
- package/android/src/main/java/expo/modules/arcgis/ExpoArcgisModule.kt +20 -1
- package/android/src/main/java/expo/modules/arcgis/ExpoArcgisSceneView.kt +10 -0
- package/android/src/main/java/expo/modules/arcgis/GraphicsOverlayRef.kt +14 -0
- package/android/src/main/java/expo/modules/arcgis/LayerRef.kt +85 -6
- package/android/src/main/java/expo/modules/arcgis/NetworkTrustHandler.kt +26 -0
- package/android/src/main/java/expo/modules/arcgis/OfflineFunctions.kt +12 -4
- package/android/src/main/java/expo/modules/arcgis/ServiceAreaFunctions.kt +61 -0
- package/build/DynamicEntityLayer.d.ts.map +1 -1
- package/build/ExpoArcgis.types.d.ts +101 -2
- package/build/ExpoArcgis.types.d.ts.map +1 -1
- package/build/ExpoArcgis.types.js.map +1 -1
- package/build/ExpoArcgisGeometryModule.d.ts +3 -1
- package/build/ExpoArcgisGeometryModule.d.ts.map +1 -1
- package/build/ExpoArcgisGeometryModule.js.map +1 -1
- package/build/ExpoArcgisModule.d.ts +23 -1
- package/build/ExpoArcgisModule.d.ts.map +1 -1
- package/build/ExpoArcgisModule.js.map +1 -1
- package/build/FeatureLayer.d.ts.map +1 -1
- package/build/auth.d.ts +12 -0
- package/build/auth.d.ts.map +1 -1
- package/build/auth.js +14 -0
- package/build/auth.js.map +1 -1
- package/build/index.d.ts +2 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +2 -1
- package/build/index.js.map +1 -1
- package/build/layers.d.ts +1 -0
- package/build/layers.d.ts.map +1 -1
- package/build/offline.d.ts +10 -2
- package/build/offline.d.ts.map +1 -1
- package/build/offline.js +5 -2
- package/build/offline.js.map +1 -1
- package/build/serviceArea.d.ts +15 -0
- package/build/serviceArea.d.ts.map +1 -0
- package/build/serviceArea.js +15 -0
- package/build/serviceArea.js.map +1 -0
- package/ios/ExpoArcgisExtrasModule.swift +3 -5
- package/ios/ExpoArcgisGeometryModule.swift +8 -0
- package/ios/ExpoArcgisMapView.swift +19 -1
- package/ios/ExpoArcgisModule.swift +22 -1
- package/ios/ExpoArcgisSceneView.swift +14 -0
- package/ios/GraphicsOverlayRef.swift +15 -0
- package/ios/LayerRef.swift +85 -5
- package/ios/NetworkTrustHandler.swift +18 -0
- package/ios/OfflineFunctions.swift +15 -4
- package/ios/ServiceAreaFunctions.swift +68 -0
- package/package.json +1 -1
- package/src/ExpoArcgis.types.ts +103 -2
- package/src/ExpoArcgisGeometryModule.ts +12 -0
- package/src/ExpoArcgisModule.ts +20 -1
- package/src/auth.ts +15 -0
- package/src/index.ts +2 -0
- package/src/offline.ts +16 -7
- package/src/serviceArea.ts +17 -0
|
@@ -47,6 +47,9 @@ class ExpoArcgisExtrasModule : Module() {
|
|
|
47
47
|
AsyncFunction("addFeatureWithSubtype") Coroutine { ref: FeatureLayerRef, subtypeName: String, attributes: Map<String, Any?>?, geometry: Map<String, Any?>?, apply: Boolean? ->
|
|
48
48
|
ref.addFeatureWithSubtype(subtypeName, attributes, geometry, apply)
|
|
49
49
|
}
|
|
50
|
+
AsyncFunction("contingentValues") Coroutine { ref: FeatureLayerRef, attributes: Map<String, Any?>, fieldName: String ->
|
|
51
|
+
ref.contingentValues(attributes, fieldName)
|
|
52
|
+
}
|
|
50
53
|
AsyncFunction("getContingentValues") Coroutine { ref: FeatureLayerRef, objectId: Long, fieldName: String ->
|
|
51
54
|
ref.getContingentValues(objectId, fieldName)
|
|
52
55
|
}
|
|
@@ -93,11 +96,6 @@ class ExpoArcgisExtrasModule : Module() {
|
|
|
93
96
|
.getOrThrow()
|
|
94
97
|
}
|
|
95
98
|
|
|
96
|
-
// Tile-cache size estimation — quick estimate before committing to a download.
|
|
97
|
-
AsyncFunction("estimateTileCacheSize") Coroutine { tileServiceUrl: String, areaOfInterest: Map<String, Any?>, options: Map<String, Any?>? ->
|
|
98
|
-
estimateTileCacheSize(tileServiceUrl, areaOfInterest, options)
|
|
99
|
-
}
|
|
100
|
-
|
|
101
99
|
// Turn-by-turn navigation — solve a route and track device locations against it.
|
|
102
100
|
AsyncFunction("createRouteTracker") Coroutine { stops: List<Map<String, Any?>>, params: Map<String, Any?> ->
|
|
103
101
|
createRouteTracker(appContext, stops, params)
|
|
@@ -96,6 +96,11 @@ class ExpoArcgisGeometryModule : Module() {
|
|
|
96
96
|
solveRoute(stops, params)
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
// Service Area — compute reachable areas from facilities, exposed as the JS `serviceArea` namespace.
|
|
100
|
+
AsyncFunction("serviceAreaSolve") Coroutine { params: Map<String, Any?> ->
|
|
101
|
+
serviceAreaSolve(params)
|
|
102
|
+
}
|
|
103
|
+
|
|
99
104
|
// Geoprocessing — run a geoprocessing service, exposed as the JS `geoprocessor` namespace.
|
|
100
105
|
AsyncFunction("executeGeoprocessing") Coroutine { serviceUrl: String, inputs: Map<String, Any?> ->
|
|
101
106
|
executeGeoprocessing(appContext, serviceUrl, inputs)
|
|
@@ -215,5 +220,8 @@ class ExpoArcgisGeometryModule : Module() {
|
|
|
215
220
|
AsyncFunction("exportVectorTiles") Coroutine { vectorTileServiceUrl: String, areaOfInterest: Map<String, Any?>, downloadName: String ->
|
|
216
221
|
exportVectorTiles(appContext, appContext.reactContext?.filesDir, vectorTileServiceUrl, areaOfInterest, downloadName)
|
|
217
222
|
}
|
|
223
|
+
AsyncFunction("estimateTileCacheSize") Coroutine { tileServiceUrl: String, areaOfInterest: Map<String, Any?>, minScale: Double?, maxScale: Double? ->
|
|
224
|
+
estimateTileCacheSize(tileServiceUrl, areaOfInterest, minScale, maxScale)
|
|
225
|
+
}
|
|
218
226
|
}
|
|
219
227
|
}
|
|
@@ -15,6 +15,7 @@ import com.arcgismaps.location.SimulatedLocationDataSource
|
|
|
15
15
|
import com.arcgismaps.location.SimulationParameters
|
|
16
16
|
import com.arcgismaps.location.SystemLocationDataSource
|
|
17
17
|
import java.time.Instant
|
|
18
|
+
import com.arcgismaps.mapping.TimeExtent
|
|
18
19
|
import com.arcgismaps.mapping.Viewpoint
|
|
19
20
|
import com.arcgismaps.mapping.view.MapView
|
|
20
21
|
import com.arcgismaps.mapping.view.ScreenCoordinate
|
|
@@ -151,6 +152,14 @@ class ExpoArcgisMapView(context: Context, appContext: AppContext) : ExpoView(con
|
|
|
151
152
|
?: com.arcgismaps.mapping.view.LatitudeLongitudeGrid().apply { isVisible = false }
|
|
152
153
|
}
|
|
153
154
|
|
|
155
|
+
/** Filters time-aware layers to a time window from JS (null shows all time steps). */
|
|
156
|
+
fun setTimeExtent(config: Map<String, Any?>?) {
|
|
157
|
+
if (config == null) { mapView.setTimeExtent(null); return }
|
|
158
|
+
val startMs = (config["startTime"] as? Number)?.toLong() ?: return
|
|
159
|
+
val endMs = (config["endTime"] as? Number)?.toLong() ?: return
|
|
160
|
+
mapView.setTimeExtent(TimeExtent(Instant.ofEpochMilli(startMs), Instant.ofEpochMilli(endMs)))
|
|
161
|
+
}
|
|
162
|
+
|
|
154
163
|
/** Enables/configures the device location display from JS (null disables it). */
|
|
155
164
|
fun setLocationDisplay(config: Map<String, Any?>?) {
|
|
156
165
|
val locationDisplay = mapView.locationDisplay
|
|
@@ -40,6 +40,13 @@ class ExpoArcgisModule : Module() {
|
|
|
40
40
|
AuthChallengeHandler.setCredentials(username, password, tokenExpirationMinutes)
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
// Network-layer server-trust override — for on-prem ArcGIS Enterprise with self-signed certs.
|
|
44
|
+
// NEVER enable in production: disabling TLS validation exposes connections to MITM attacks.
|
|
45
|
+
Function("setAllowUntrustedHosts") { allow: Boolean ->
|
|
46
|
+
ArcGISEnvironment.authenticationManager.networkAuthenticationChallengeHandler =
|
|
47
|
+
if (allow) NetworkTrustHandler else null
|
|
48
|
+
}
|
|
49
|
+
|
|
43
50
|
// Revokes any OAuth user credentials on the server, then clears all cached credentials.
|
|
44
51
|
AsyncFunction("signOut") Coroutine { ->
|
|
45
52
|
val store = ArcGISEnvironment.authenticationManager.arcGISCredentialStore
|
|
@@ -210,7 +217,8 @@ class ExpoArcgisModule : Module() {
|
|
|
210
217
|
Constructor { props: Map<String, Any?> ->
|
|
211
218
|
@Suppress("UNCHECKED_CAST")
|
|
212
219
|
val source = props["source"] as? Map<String, Any?> ?: emptyMap()
|
|
213
|
-
|
|
220
|
+
val rasterFunctionJson = props["rasterFunction"] as? String
|
|
221
|
+
RasterLayerRef(appContext, source, rasterFunctionJson).also { it.applyProps(props) }
|
|
214
222
|
}
|
|
215
223
|
Function("applyProps") { ref: RasterLayerRef, changed: Map<String, Any?> ->
|
|
216
224
|
ref.applyProps(changed)
|
|
@@ -225,6 +233,9 @@ class ExpoArcgisModule : Module() {
|
|
|
225
233
|
ref.applyProps(changed)
|
|
226
234
|
}
|
|
227
235
|
AsyncFunction("getNodes") Coroutine { ref: KmlLayerRef -> ref.getNodes() }
|
|
236
|
+
Function("playTour") { ref: KmlLayerRef -> ref.playTour() }
|
|
237
|
+
Function("pauseTour") { ref: KmlLayerRef -> ref.pauseTour() }
|
|
238
|
+
Function("resetTour") { ref: KmlLayerRef -> ref.resetTour() }
|
|
228
239
|
}
|
|
229
240
|
|
|
230
241
|
// WFS (Web Feature Service) + OGC API - Features — feature layers over async-populating tables.
|
|
@@ -385,6 +396,10 @@ class ExpoArcgisModule : Module() {
|
|
|
385
396
|
view.setGrid(grid)
|
|
386
397
|
}
|
|
387
398
|
|
|
399
|
+
Prop("timeExtent") { view: ExpoArcgisMapView, value: Map<String, Any?>? ->
|
|
400
|
+
view.setTimeExtent(value)
|
|
401
|
+
}
|
|
402
|
+
|
|
388
403
|
AsyncFunction("identify") { view: ExpoArcgisMapView, screenPoint: Map<String, Any?>, options: Map<String, Any?>?, promise: Promise ->
|
|
389
404
|
view.identify(screenPoint, options, promise)
|
|
390
405
|
}
|
|
@@ -451,6 +466,10 @@ class ExpoArcgisModule : Module() {
|
|
|
451
466
|
view.setSunTime(value)
|
|
452
467
|
}
|
|
453
468
|
|
|
469
|
+
Prop("timeExtent") { view: ExpoArcgisSceneView, value: Map<String, Any?>? ->
|
|
470
|
+
view.setTimeExtent(value)
|
|
471
|
+
}
|
|
472
|
+
|
|
454
473
|
AsyncFunction("retryLoad") { view: ExpoArcgisSceneView, promise: Promise ->
|
|
455
474
|
view.retryLoad(promise)
|
|
456
475
|
}
|
|
@@ -7,7 +7,9 @@ import androidx.lifecycle.findViewTreeLifecycleOwner
|
|
|
7
7
|
import com.arcgismaps.geometry.GeometryEngine
|
|
8
8
|
import com.arcgismaps.geometry.Point
|
|
9
9
|
import com.arcgismaps.geometry.SpatialReference
|
|
10
|
+
import com.arcgismaps.mapping.TimeExtent
|
|
10
11
|
import com.arcgismaps.mapping.view.AtmosphereEffect
|
|
12
|
+
import java.time.Instant
|
|
11
13
|
import com.arcgismaps.mapping.view.Camera
|
|
12
14
|
import com.arcgismaps.mapping.view.GlobeCameraController
|
|
13
15
|
import com.arcgismaps.mapping.view.LightingMode
|
|
@@ -230,6 +232,14 @@ class ExpoArcgisSceneView(context: Context, appContext: AppContext) : ExpoView(c
|
|
|
230
232
|
sceneView.sunTime = java.time.Instant.ofEpochMilli(ms.toLong())
|
|
231
233
|
}
|
|
232
234
|
|
|
235
|
+
/** Filters time-aware layers to a time window from JS (null shows all time steps). */
|
|
236
|
+
fun setTimeExtent(config: Map<String, Any?>?) {
|
|
237
|
+
if (config == null) { sceneView.setTimeExtent(null); return }
|
|
238
|
+
val startMs = (config["startTime"] as? Number)?.toLong() ?: return
|
|
239
|
+
val endMs = (config["endTime"] as? Number)?.toLong() ?: return
|
|
240
|
+
sceneView.setTimeExtent(TimeExtent(Instant.ofEpochMilli(startMs), Instant.ofEpochMilli(endMs)))
|
|
241
|
+
}
|
|
242
|
+
|
|
233
243
|
override fun onAttachedToWindow() {
|
|
234
244
|
super.onAttachedToWindow()
|
|
235
245
|
val lifecycle = findViewTreeLifecycleOwner()?.lifecycle
|
|
@@ -18,8 +18,10 @@ import com.arcgismaps.mapping.symbology.SimpleLineSymbol
|
|
|
18
18
|
import com.arcgismaps.mapping.symbology.SimpleLineSymbolStyle
|
|
19
19
|
import com.arcgismaps.mapping.symbology.DistanceCompositeSceneSymbol
|
|
20
20
|
import com.arcgismaps.mapping.symbology.DistanceSymbolRange
|
|
21
|
+
import com.arcgismaps.mapping.symbology.ModelSceneSymbol
|
|
21
22
|
import com.arcgismaps.mapping.symbology.SimpleMarkerSceneSymbol
|
|
22
23
|
import com.arcgismaps.mapping.symbology.SimpleMarkerSceneSymbolStyle
|
|
24
|
+
import com.arcgismaps.mapping.symbology.SymbolSizeUnits
|
|
23
25
|
import com.arcgismaps.mapping.symbology.MultilayerPointSymbol
|
|
24
26
|
import com.arcgismaps.mapping.symbology.MultilayerPolygonSymbol
|
|
25
27
|
import com.arcgismaps.mapping.symbology.MultilayerPolylineSymbol
|
|
@@ -346,6 +348,18 @@ private fun buildSymbol(s: Map<*, *>): Symbol? = when (s["type"]) {
|
|
|
346
348
|
num(s["depth"], 100.0),
|
|
347
349
|
sceneSymbolAnchor(s["anchor"]),
|
|
348
350
|
)
|
|
351
|
+
"model-scene" -> (s["url"] as? String)?.let { uri ->
|
|
352
|
+
// ModelSceneSymbol(uri, scale) — 3D glTF/model marker. Set heading/pitch/roll (Float)
|
|
353
|
+
// and symbolSizeUnits after construction; the symbol is Loadable.
|
|
354
|
+
val scale = (s["scale"] as? Number)?.toFloat() ?: 1f
|
|
355
|
+
ModelSceneSymbol(uri, scale).apply {
|
|
356
|
+
symbolSizeUnits = if (s["sizeUnits"] == "meters") SymbolSizeUnits.Meters else SymbolSizeUnits.Dips
|
|
357
|
+
heading = (s["heading"] as? Number)?.toFloat() ?: 0f
|
|
358
|
+
pitch = (s["pitch"] as? Number)?.toFloat() ?: 0f
|
|
359
|
+
roll = (s["roll"] as? Number)?.toFloat() ?: 0f
|
|
360
|
+
anchorPosition = sceneSymbolAnchor(s["anchor"])
|
|
361
|
+
}
|
|
362
|
+
}
|
|
349
363
|
"picture-marker" -> (s["url"] as? String)?.let { url ->
|
|
350
364
|
PictureMarkerSymbol(url).apply {
|
|
351
365
|
(s["width"] as? Number)?.toFloat()?.let { width = it }
|
|
@@ -57,9 +57,12 @@ import com.arcgismaps.mapping.layers.WmtsLayer
|
|
|
57
57
|
import com.arcgismaps.mapping.kml.KmlContainer
|
|
58
58
|
import com.arcgismaps.mapping.kml.KmlDataset
|
|
59
59
|
import com.arcgismaps.mapping.kml.KmlNode
|
|
60
|
+
import com.arcgismaps.mapping.kml.KmlTour
|
|
61
|
+
import com.arcgismaps.mapping.kml.KmlTourController
|
|
60
62
|
import com.arcgismaps.mapping.view.Graphic
|
|
61
63
|
import com.arcgismaps.raster.ImageServiceRaster
|
|
62
64
|
import com.arcgismaps.raster.Raster
|
|
65
|
+
import com.arcgismaps.raster.RasterFunction
|
|
63
66
|
import expo.modules.kotlin.AppContext
|
|
64
67
|
import expo.modules.kotlin.sharedobjects.SharedObject
|
|
65
68
|
|
|
@@ -290,6 +293,38 @@ class FeatureLayerRef(appContext: AppContext, private val table: FeatureTable) :
|
|
|
290
293
|
persistEdits()
|
|
291
294
|
}
|
|
292
295
|
|
|
296
|
+
/**
|
|
297
|
+
* Returns the valid coded values for [fieldName] given a feature's current [attributes].
|
|
298
|
+
* Use this to drive editing-form dropdowns: pass the feature's current attribute state and the
|
|
299
|
+
* name of the field being edited; returns `[{ name, code }]` for coded values that satisfy all
|
|
300
|
+
* contingent-value constraints defined on the table.
|
|
301
|
+
*
|
|
302
|
+
* Loads the table and its [ContingentValuesDefinition], builds a temporary [ArcGISFeature] from
|
|
303
|
+
* [attributes] (via `FeatureTable.createFeature(attributes, null)` + `applyAttributes`), then
|
|
304
|
+
* calls `getContingentValuesOrNull(feature, fieldName)`.
|
|
305
|
+
* Non-coded contingent values ([ContingentRangeValue], null, any) are omitted — only
|
|
306
|
+
* [ContingentCodedValue] entries are returned.
|
|
307
|
+
*
|
|
308
|
+
* Requires an [ArcGISFeatureTable]; throws for shapefiles and WFS tables.
|
|
309
|
+
* Returns an empty list when no constraints are defined for [fieldName].
|
|
310
|
+
*/
|
|
311
|
+
suspend fun contingentValues(attributes: Map<String, Any?>, fieldName: String): List<Map<String, Any?>> {
|
|
312
|
+
table.load().getOrThrow()
|
|
313
|
+
val arcGISTable = table as? ArcGISFeatureTable
|
|
314
|
+
?: throw IllegalStateException("contingentValues requires an ArcGIS feature table (not a shapefile or WFS table)")
|
|
315
|
+
arcGISTable.contingentValuesDefinition.load().getOrThrow()
|
|
316
|
+
val feature = table.createFeature(attributes, null) as ArcGISFeature
|
|
317
|
+
val result = arcGISTable.getContingentValuesOrNull(feature, fieldName)
|
|
318
|
+
?: return emptyList()
|
|
319
|
+
return result.byFieldGroup.flatMap { (_, values) ->
|
|
320
|
+
values.mapNotNull { cv ->
|
|
321
|
+
if (cv !is ContingentCodedValue) return@mapNotNull null
|
|
322
|
+
val coded = cv.codedValue
|
|
323
|
+
mapOf("name" to coded.name, "code" to coded.code)
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
293
328
|
/**
|
|
294
329
|
* Returns the valid contingent values for [fieldName] on the feature with [objectId].
|
|
295
330
|
* Requires the table to be an [ArcGISFeatureTable]; throws otherwise. Returns an empty list when
|
|
@@ -537,21 +572,41 @@ class WmtsLayerRef(appContext: AppContext, url: String, layerId: String) : Layer
|
|
|
537
572
|
}
|
|
538
573
|
|
|
539
574
|
/** Operational raster layer from a remote image service or a local raster file. */
|
|
540
|
-
class RasterLayerRef(
|
|
541
|
-
|
|
575
|
+
class RasterLayerRef(
|
|
576
|
+
appContext: AppContext,
|
|
577
|
+
source: Map<String, Any?>,
|
|
578
|
+
rasterFunctionJson: String? = null,
|
|
579
|
+
) : LayerRef(appContext) {
|
|
580
|
+
override val layer: RasterLayer = RasterLayer(rasterFromSource(source, rasterFunctionJson))
|
|
542
581
|
|
|
543
582
|
override fun applyProps(changed: Map<String, Any?>) = applyCommonProps(changed)
|
|
544
583
|
}
|
|
545
584
|
|
|
546
|
-
/**
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
585
|
+
/**
|
|
586
|
+
* Builds a [Raster] from a JS source dict: `{type:"imageService",url}` or `{type:"file",path}`.
|
|
587
|
+
* When [rasterFunctionJson] is supplied, wraps the base raster in a [RasterFunction] pipeline:
|
|
588
|
+
* `RasterFunction.fromJsonOrNull` → wire source raster as first raster argument →
|
|
589
|
+
* `Raster.createWithRasterFunction`. Falls back to the plain source raster if parsing fails
|
|
590
|
+
* or no raster argument is found.
|
|
591
|
+
*/
|
|
592
|
+
private fun rasterFromSource(s: Map<String, Any?>, rasterFunctionJson: String? = null): Raster {
|
|
593
|
+
val base: Raster =
|
|
594
|
+
if (s["type"] == "file") Raster.createWithPath(s["path"] as? String ?: "")
|
|
595
|
+
else ImageServiceRaster(s["url"] as? String ?: "")
|
|
596
|
+
if (rasterFunctionJson == null) return base
|
|
597
|
+
val fn = RasterFunction.fromJsonOrNull(rasterFunctionJson) ?: return base
|
|
598
|
+
val args = fn.arguments ?: return base
|
|
599
|
+
val firstName = args.rasterNames.firstOrNull() ?: return base
|
|
600
|
+
args.setRaster(firstName, base)
|
|
601
|
+
return Raster.createWithRasterFunction(fn)
|
|
602
|
+
}
|
|
550
603
|
|
|
551
604
|
/** Operational KML layer from a remote .kml/.kmz URL or local file. */
|
|
552
605
|
class KmlLayerRef(appContext: AppContext, url: String) : LayerRef(appContext) {
|
|
553
606
|
private val dataset = KmlDataset(url)
|
|
554
607
|
override val layer: KmlLayer = KmlLayer(dataset)
|
|
608
|
+
/** Lazily-created controller; held for the lifetime of the ref so play/pause/reset are idempotent. */
|
|
609
|
+
private var tourController: KmlTourController? = null
|
|
555
610
|
|
|
556
611
|
override fun applyProps(changed: Map<String, Any?>) = applyCommonProps(changed)
|
|
557
612
|
|
|
@@ -560,6 +615,21 @@ class KmlLayerRef(appContext: AppContext, url: String) : LayerRef(appContext) {
|
|
|
560
615
|
dataset.load().getOrThrow()
|
|
561
616
|
return dataset.rootNodes.map { serializeKmlNode(it) }
|
|
562
617
|
}
|
|
618
|
+
|
|
619
|
+
/** Returns the existing controller, or creates one attached to the first [KmlTour] in the node tree.
|
|
620
|
+
* Returns `null` if the dataset has no tour. */
|
|
621
|
+
private fun controller(): KmlTourController? {
|
|
622
|
+
tourController?.let { return it }
|
|
623
|
+
val tour = findFirstTour(dataset.rootNodes) ?: return null
|
|
624
|
+
return KmlTourController().also { it.tour = tour; tourController = it }
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
/** Starts or resumes playback of the first KML tour. No-ops if no tour exists. */
|
|
628
|
+
fun playTour() { controller()?.play() }
|
|
629
|
+
/** Pauses playback of the first KML tour. No-ops if no tour exists. */
|
|
630
|
+
fun pauseTour() { controller()?.pause() }
|
|
631
|
+
/** Resets playback of the first KML tour to the beginning. No-ops if no tour exists. */
|
|
632
|
+
fun resetTour() { controller()?.reset() }
|
|
563
633
|
}
|
|
564
634
|
|
|
565
635
|
/** Serializes a KML node, recursing into container nodes (documents / folders). */
|
|
@@ -575,6 +645,15 @@ private fun serializeKmlNode(node: KmlNode): Map<String, Any?> {
|
|
|
575
645
|
return dict
|
|
576
646
|
}
|
|
577
647
|
|
|
648
|
+
/** Depth-first search for the first [KmlTour] in a list of KML nodes. */
|
|
649
|
+
private fun findFirstTour(nodes: List<KmlNode>): KmlTour? {
|
|
650
|
+
for (node in nodes) {
|
|
651
|
+
if (node is KmlTour) return node
|
|
652
|
+
if (node is KmlContainer) findFirstTour(node.childNodes)?.let { return it }
|
|
653
|
+
}
|
|
654
|
+
return null
|
|
655
|
+
}
|
|
656
|
+
|
|
578
657
|
/** Operational WFS layer — a [FeatureLayer] over a [WfsFeatureTable] (Web Feature Service). */
|
|
579
658
|
class WfsLayerRef(appContext: AppContext, url: String, tableName: String) : LayerRef(appContext) {
|
|
580
659
|
override val layer: FeatureLayer = FeatureLayer.createWithFeatureTable(
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
package expo.modules.arcgis
|
|
2
|
+
|
|
3
|
+
import com.arcgismaps.httpcore.authentication.NetworkAuthenticationChallenge
|
|
4
|
+
import com.arcgismaps.httpcore.authentication.NetworkAuthenticationChallengeHandler
|
|
5
|
+
import com.arcgismaps.httpcore.authentication.NetworkAuthenticationChallengeResponse
|
|
6
|
+
import com.arcgismaps.httpcore.authentication.NetworkAuthenticationType
|
|
7
|
+
import com.arcgismaps.httpcore.authentication.ServerTrust
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Network-layer trust handler that accepts every server-trust challenge unconditionally.
|
|
11
|
+
* Only install this for development or on-prem ArcGIS Enterprise with self-signed certificates —
|
|
12
|
+
* it disables TLS certificate validation, which makes the connection vulnerable to
|
|
13
|
+
* man-in-the-middle attacks. Never enable in production.
|
|
14
|
+
*/
|
|
15
|
+
object NetworkTrustHandler : NetworkAuthenticationChallengeHandler {
|
|
16
|
+
override suspend fun handleNetworkAuthenticationChallenge(
|
|
17
|
+
challenge: NetworkAuthenticationChallenge,
|
|
18
|
+
): NetworkAuthenticationChallengeResponse {
|
|
19
|
+
if (challenge.networkAuthenticationType is NetworkAuthenticationType.ServerTrust) {
|
|
20
|
+
return NetworkAuthenticationChallengeResponse.ContinueWithCredential(ServerTrust)
|
|
21
|
+
}
|
|
22
|
+
// Other challenge kinds (basic / digest / NTLM / client-cert) aren't ours to satisfy — continue
|
|
23
|
+
// without a credential (mirrors Swift's `.continueWithoutCredential`) instead of cancelling them.
|
|
24
|
+
return NetworkAuthenticationChallengeResponse.ContinueAndFail
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -209,20 +209,28 @@ internal suspend fun exportTileCache(
|
|
|
209
209
|
|
|
210
210
|
/**
|
|
211
211
|
* Estimates the on-disk file size and tile count for an [exportTileCache] download WITHOUT
|
|
212
|
-
* downloading.
|
|
212
|
+
* downloading. Passes [minScale]/[maxScale] (0.0 = no limit) to
|
|
213
|
+
* [ExportTileCacheTask.createDefaultExportTileCacheParameters] to narrow the estimation to the
|
|
214
|
+
* same scale window that [exportTileCache] would use. Runs the [EstimateTileCacheSizeJob] to
|
|
215
|
+
* completion and returns `{fileSizeBytes, tileCount}`.
|
|
213
216
|
*/
|
|
214
217
|
internal suspend fun estimateTileCacheSize(
|
|
215
218
|
tileServiceUrl: String,
|
|
216
219
|
areaOfInterest: Map<String, Any?>,
|
|
217
|
-
|
|
220
|
+
minScale: Double?,
|
|
221
|
+
maxScale: Double?,
|
|
218
222
|
): Map<String, Any?> {
|
|
219
223
|
val area = geometryFromDict(areaOfInterest) ?: throw IllegalArgumentException("Invalid area of interest")
|
|
220
224
|
val task = ExportTileCacheTask(tileServiceUrl)
|
|
221
|
-
val parameters = task.createDefaultExportTileCacheParameters(
|
|
225
|
+
val parameters = task.createDefaultExportTileCacheParameters(
|
|
226
|
+
area,
|
|
227
|
+
minScale ?: 0.0,
|
|
228
|
+
maxScale ?: 0.0,
|
|
229
|
+
).getOrThrow()
|
|
222
230
|
val job = task.createEstimateTileCacheSizeJob(parameters)
|
|
223
231
|
job.start()
|
|
224
232
|
val estimate = job.result().getOrThrow()
|
|
225
|
-
return mapOf("
|
|
233
|
+
return mapOf("fileSizeBytes" to estimate.fileSize.toDouble(), "tileCount" to estimate.tileCount.toDouble())
|
|
226
234
|
}
|
|
227
235
|
|
|
228
236
|
internal suspend fun exportVectorTiles(
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
package expo.modules.arcgis
|
|
2
|
+
|
|
3
|
+
import com.arcgismaps.tasks.networkanalysis.ServiceAreaFacility
|
|
4
|
+
import com.arcgismaps.tasks.networkanalysis.ServiceAreaPolygon
|
|
5
|
+
import com.arcgismaps.tasks.networkanalysis.ServiceAreaResult
|
|
6
|
+
import com.arcgismaps.tasks.networkanalysis.ServiceAreaTask
|
|
7
|
+
import com.arcgismaps.geometry.Point
|
|
8
|
+
import java.util.concurrent.ConcurrentHashMap
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Free functions backing the JS `serviceArea` namespace — computing reachable areas from
|
|
12
|
+
* facilities via a [ServiceAreaTask]. Registered as an `AsyncFunction` in
|
|
13
|
+
* `ExpoArcgisGeometryModule`.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** Caches one [ServiceAreaTask] per service URL so repeated solves don't reload service metadata. */
|
|
17
|
+
private val serviceAreaTasks = ConcurrentHashMap<String, ServiceAreaTask>()
|
|
18
|
+
|
|
19
|
+
private fun serviceAreaTask(url: String): ServiceAreaTask =
|
|
20
|
+
serviceAreaTasks.getOrPut(url) { ServiceAreaTask(url) }
|
|
21
|
+
|
|
22
|
+
internal suspend fun serviceAreaSolve(params: Map<String, Any?>): Map<String, Any?> {
|
|
23
|
+
val serviceUrl = params["serviceUrl"] as? String
|
|
24
|
+
?: error("serviceUrl is required")
|
|
25
|
+
val task = serviceAreaTask(serviceUrl)
|
|
26
|
+
// createDefaultParameters() loads the task so the service metadata is populated afterwards.
|
|
27
|
+
val parameters = task.createDefaultParameters().getOrThrow()
|
|
28
|
+
val facilitiesDicts = params["facilities"] as? List<*> ?: emptyList<Any?>()
|
|
29
|
+
parameters.setFacilities(buildFacilities(facilitiesDicts))
|
|
30
|
+
(params["cutoffs"] as? List<*>)?.let { rawCutoffs ->
|
|
31
|
+
val cutoffs = rawCutoffs.mapNotNull { (it as? Number)?.toDouble() }
|
|
32
|
+
if (cutoffs.isNotEmpty()) {
|
|
33
|
+
// ServiceAreaParameters.defaultImpedanceCutoffs is a mutable live list (no setter / add API).
|
|
34
|
+
parameters.defaultImpedanceCutoffs.clear()
|
|
35
|
+
parameters.defaultImpedanceCutoffs.addAll(cutoffs)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
val result = task.solveServiceArea(parameters).getOrThrow()
|
|
39
|
+
return serializeServiceAreaResult(result)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private fun buildFacilities(dicts: List<*>): List<ServiceAreaFacility> =
|
|
43
|
+
dicts.filterIsInstance<Map<*, *>>().mapNotNull { dict ->
|
|
44
|
+
(geometryFromDict(dict) as? Point)?.let { ServiceAreaFacility(it) }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private fun serializeServiceAreaResult(result: ServiceAreaResult): Map<String, Any?> {
|
|
48
|
+
val polygons = mutableListOf<Map<String, Any?>>()
|
|
49
|
+
for ((index, _) in result.facilities.withIndex()) {
|
|
50
|
+
for (polygon in result.getResultPolygons(index)) {
|
|
51
|
+
polygons.add(serializeServiceAreaPolygon(polygon))
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return mapOf("polygons" to polygons)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private fun serializeServiceAreaPolygon(polygon: ServiceAreaPolygon): Map<String, Any?> = mapOf(
|
|
58
|
+
"geometry" to dictFromGeometry(polygon.geometry),
|
|
59
|
+
"fromCutoff" to polygon.fromImpedanceCutoff,
|
|
60
|
+
"toCutoff" to polygon.toImpedanceCutoff,
|
|
61
|
+
)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DynamicEntityLayer.d.ts","sourceRoot":"","sources":["../src/DynamicEntityLayer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAChB,mBAAmB,EACnB,wBAAwB,EAEzB,MAAM,oBAAoB,CAAC;AAQ5B;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB;;;;;
|
|
1
|
+
{"version":3,"file":"DynamicEntityLayer.d.ts","sourceRoot":"","sources":["../src/DynamicEntityLayer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAChB,mBAAmB,EACnB,wBAAwB,EAEzB,MAAM,oBAAoB,CAAC;AAQ5B;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB;;;;;mBAwDoguC,CAAC;gBAAkB,CAAC;;;;;;;4DADtjuC,CAAC"}
|
|
@@ -131,6 +131,15 @@ export type MapViewProps = {
|
|
|
131
131
|
viewpoint?: Viewpoint;
|
|
132
132
|
/** Device-location display. When set, the view shows the device's GPS location. */
|
|
133
133
|
locationDisplay?: LocationDisplay;
|
|
134
|
+
/**
|
|
135
|
+
* Filters time-aware layers to this time window. Both values are epoch milliseconds (UTC).
|
|
136
|
+
* Pass `null` / omit to show all time steps (no filter). Maps to `GeoView.timeExtent` /
|
|
137
|
+
* `MapView(timeExtent:)` on both platforms.
|
|
138
|
+
*/
|
|
139
|
+
timeExtent?: {
|
|
140
|
+
startTime: number;
|
|
141
|
+
endTime: number;
|
|
142
|
+
} | null;
|
|
134
143
|
/** Called once the map has finished loading successfully. */
|
|
135
144
|
onMapLoaded?: (event: {
|
|
136
145
|
nativeEvent: MapLoadedEventPayload;
|
|
@@ -640,6 +649,26 @@ export type FeatureLayerHandle = {
|
|
|
640
649
|
* feature layer. The same handle is returned on repeat calls.
|
|
641
650
|
*/
|
|
642
651
|
getServiceGeodatabase(): Promise<ServiceGeodatabaseHandle>;
|
|
652
|
+
/**
|
|
653
|
+
* Returns the valid coded values for `fieldName` given the feature's current `attributes`.
|
|
654
|
+
* Use this to drive editing-form dropdowns: pass the feature's current attribute state and the
|
|
655
|
+
* name of the field being edited; returns `[{ name, code }]` for coded values that satisfy all
|
|
656
|
+
* contingent-value constraints defined on the table.
|
|
657
|
+
*
|
|
658
|
+
* The table and its `ContingentValuesDefinition` are loaded automatically. A temporary feature
|
|
659
|
+
* is built from `attributes` (no server round-trip for the feature itself); only `ArcGISFeature`
|
|
660
|
+
* tables are supported — rejects for shapefiles and WFS tables.
|
|
661
|
+
*
|
|
662
|
+
* @example
|
|
663
|
+
* ```ts
|
|
664
|
+
* const options = await layer.current.contingentValues({ habitat: 'oak' }, 'species');
|
|
665
|
+
* // options → [{ name: 'Red Oak', code: 1 }, { name: 'White Oak', code: 2 }]
|
|
666
|
+
* ```
|
|
667
|
+
*/
|
|
668
|
+
contingentValues(attributes: Record<string, unknown>, fieldName: string): Promise<{
|
|
669
|
+
name: string;
|
|
670
|
+
code: unknown;
|
|
671
|
+
}[]>;
|
|
643
672
|
/**
|
|
644
673
|
* Returns the valid contingent values for `fieldName` on the feature with `objectId`, given
|
|
645
674
|
* the feature's current attribute state. Contingent values constrain which attribute values
|
|
@@ -811,6 +840,14 @@ export type RasterSource = {
|
|
|
811
840
|
/** Props for a `<RasterLayer>` — mirror the native `RasterLayer` (image service or local raster). */
|
|
812
841
|
export type RasterLayerProps = LayerProps & {
|
|
813
842
|
source: RasterSource;
|
|
843
|
+
/**
|
|
844
|
+
* On-the-fly raster function chain to apply to the layer's raster, serialised as JSON
|
|
845
|
+
* (e.g. a hillshade / colormap / NDVI chain). When set, the SDK builds a
|
|
846
|
+
* `RasterFunction.fromJSON` → `Raster(rasterFunction:)` pipeline with the source raster
|
|
847
|
+
* wired in as the first raster argument. Construction-time only — changing this prop
|
|
848
|
+
* requires remounting the layer.
|
|
849
|
+
*/
|
|
850
|
+
rasterFunction?: string;
|
|
814
851
|
};
|
|
815
852
|
/** Props for a `<KmlLayer>` — mirror `KMLLayer` (remote `.kml`/`.kmz` URL or local file). */
|
|
816
853
|
export type KmlLayerProps = LayerProps & {
|
|
@@ -1058,6 +1095,12 @@ export type KmlNodeInfo = {
|
|
|
1058
1095
|
export type KmlLayerHandle = {
|
|
1059
1096
|
/** Loads the KML and returns its node tree (recursing into container nodes). */
|
|
1060
1097
|
getNodes(): Promise<KmlNodeInfo[]>;
|
|
1098
|
+
/** Starts or resumes playback of the first KML tour found in the layer. No-ops if no tour exists. */
|
|
1099
|
+
playTour(): void;
|
|
1100
|
+
/** Pauses playback of the first KML tour found in the layer. No-ops if no tour exists. */
|
|
1101
|
+
pauseTour(): void;
|
|
1102
|
+
/** Resets playback of the first KML tour found in the layer to the beginning. No-ops if no tour exists. */
|
|
1103
|
+
resetTour(): void;
|
|
1061
1104
|
};
|
|
1062
1105
|
/**
|
|
1063
1106
|
* A geometry value. The `type` discriminator mirrors the ArcGIS web API
|
|
@@ -1343,6 +1386,32 @@ export type RouteTrackerHandle = {
|
|
|
1343
1386
|
trackLocation(location: TrackedLocation): Promise<RouteTrackingStatus>;
|
|
1344
1387
|
switchToNextDestination(): Promise<void>;
|
|
1345
1388
|
};
|
|
1389
|
+
/** Parameters for `serviceArea.solve`. */
|
|
1390
|
+
export type ServiceAreaSolveParams = {
|
|
1391
|
+
/** URL of the network analysis service (e.g. the ArcGIS World Service Areas service). */
|
|
1392
|
+
serviceUrl: string;
|
|
1393
|
+
/** Facility locations to compute service areas from. */
|
|
1394
|
+
facilities: PointGeometry[];
|
|
1395
|
+
/**
|
|
1396
|
+
* Impedance cutoff values (e.g. travel-time minutes or distance) that define each polygon ring.
|
|
1397
|
+
* When omitted the service's default cutoffs are used.
|
|
1398
|
+
*/
|
|
1399
|
+
cutoffs?: number[];
|
|
1400
|
+
};
|
|
1401
|
+
/** One service-area polygon returned from `serviceArea.solve`. Mirrors the native `ServiceAreaPolygon`. */
|
|
1402
|
+
export type ServiceAreaPolygon = {
|
|
1403
|
+
/** The polygon geometry of the reachable area. */
|
|
1404
|
+
geometry: Geometry;
|
|
1405
|
+
/** Lower impedance bound for this polygon ring. */
|
|
1406
|
+
fromCutoff: number;
|
|
1407
|
+
/** Upper impedance bound for this polygon ring. */
|
|
1408
|
+
toCutoff: number;
|
|
1409
|
+
};
|
|
1410
|
+
/** Result of `serviceArea.solve`. */
|
|
1411
|
+
export type ServiceAreaResult = {
|
|
1412
|
+
/** All result polygons across all facilities, ordered by facility then cutoff. */
|
|
1413
|
+
polygons: ServiceAreaPolygon[];
|
|
1414
|
+
};
|
|
1346
1415
|
/** Props for `<AnalysisOverlay>` — a container for visual analyses, hosted by a `<SceneView>`. */
|
|
1347
1416
|
export type AnalysisOverlayProps = {
|
|
1348
1417
|
/** Whether the overlay's analyses are drawn. Defaults to `true`. */
|
|
@@ -1687,7 +1756,7 @@ export type OfflineTileResult = {
|
|
|
1687
1756
|
/** Result of `offline.estimateTileCacheSize` — an estimate of the download footprint. */
|
|
1688
1757
|
export type TileCacheSizeEstimate = {
|
|
1689
1758
|
/** Estimated on-disk size of the tile cache in bytes. */
|
|
1690
|
-
|
|
1759
|
+
fileSizeBytes: number;
|
|
1691
1760
|
/** Estimated number of tiles in the tile cache. */
|
|
1692
1761
|
tileCount: number;
|
|
1693
1762
|
};
|
|
@@ -1818,6 +1887,27 @@ export type SimpleMarkerSceneSymbol = {
|
|
|
1818
1887
|
/** Which part of the solid sits on the point. Defaults to `bottom`. */
|
|
1819
1888
|
anchor?: 'center' | 'bottom' | 'top' | 'origin';
|
|
1820
1889
|
};
|
|
1890
|
+
/**
|
|
1891
|
+
* A 3D model symbol (glTF / `.glb`) for point graphics in a `<SceneView>`. Mirrors the native
|
|
1892
|
+
* `ModelSceneSymbol` (loads the model at `url` at runtime — symbol is `Loadable`).
|
|
1893
|
+
*/
|
|
1894
|
+
export type ModelSceneSymbol = {
|
|
1895
|
+
type: 'model-scene';
|
|
1896
|
+
/** URL of the glTF / `.glb` model file. Required. */
|
|
1897
|
+
url: string;
|
|
1898
|
+
/** Uniform scale factor applied to the model. Defaults to `1`. */
|
|
1899
|
+
scale?: number;
|
|
1900
|
+
/** Whether the model dimensions are expressed in device-independent pixels or geographic meters. Defaults to `dips`. */
|
|
1901
|
+
sizeUnits?: 'dips' | 'meters';
|
|
1902
|
+
/** Rotation around the vertical (z) axis, in degrees. Defaults to `0`. */
|
|
1903
|
+
heading?: number;
|
|
1904
|
+
/** Rotation around the lateral (x) axis, in degrees. Defaults to `0`. */
|
|
1905
|
+
pitch?: number;
|
|
1906
|
+
/** Rotation around the longitudinal (y) axis, in degrees. Defaults to `0`. */
|
|
1907
|
+
roll?: number;
|
|
1908
|
+
/** Which part of the model sits on the point. Defaults to `bottom`. */
|
|
1909
|
+
anchor?: 'center' | 'bottom' | 'top' | 'origin';
|
|
1910
|
+
};
|
|
1821
1911
|
/** A marker drawn from an image at a URL. Mirrors `PictureMarkerSymbol`. */
|
|
1822
1912
|
export type PictureMarkerSymbol = {
|
|
1823
1913
|
type: 'picture-marker';
|
|
@@ -1982,7 +2072,7 @@ export type MultilayerPointSymbolType = {
|
|
|
1982
2072
|
symbolLayers: SymbolLayerSpec[];
|
|
1983
2073
|
};
|
|
1984
2074
|
/** Any symbol usable by a `<Graphic>`. Mirrors the native `Symbol` hierarchy. */
|
|
1985
|
-
export type Symbol = SimpleMarkerSymbol | SimpleLineSymbol | SimpleFillSymbol | TextSymbol | SimpleMarkerSceneSymbol | PictureMarkerSymbol | PictureFillSymbol | DistanceCompositeSceneSymbol | CompositeSymbolType | MultilayerPointSymbolType;
|
|
2075
|
+
export type Symbol = SimpleMarkerSymbol | SimpleLineSymbol | SimpleFillSymbol | TextSymbol | SimpleMarkerSceneSymbol | ModelSceneSymbol | PictureMarkerSymbol | PictureFillSymbol | DistanceCompositeSceneSymbol | CompositeSymbolType | MultilayerPointSymbolType;
|
|
1986
2076
|
/** One stop in a `SizeVisualVariable` stops array. */
|
|
1987
2077
|
export type SizeStop = {
|
|
1988
2078
|
value: number;
|
|
@@ -2228,6 +2318,15 @@ export type SceneViewProps = {
|
|
|
2228
2318
|
atmosphereEffect?: AtmosphereEffect;
|
|
2229
2319
|
/** Sun position, as epoch milliseconds (affects shadow direction). */
|
|
2230
2320
|
sunTime?: number;
|
|
2321
|
+
/**
|
|
2322
|
+
* Filters time-aware layers to this time window. Both values are epoch milliseconds (UTC).
|
|
2323
|
+
* Pass `null` / omit to show all time steps (no filter). Maps to `GeoView.timeExtent` /
|
|
2324
|
+
* `SceneView(timeExtent:)` on both platforms.
|
|
2325
|
+
*/
|
|
2326
|
+
timeExtent?: {
|
|
2327
|
+
startTime: number;
|
|
2328
|
+
endTime: number;
|
|
2329
|
+
} | null;
|
|
2231
2330
|
/** Called once the scene has finished loading successfully. */
|
|
2232
2331
|
onSceneLoaded?: (event: {
|
|
2233
2332
|
nativeEvent: MapLoadedEventPayload;
|