expo-arcgis 0.1.1 → 0.1.3
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 +3 -3
- package/android/src/main/java/expo/modules/arcgis/DynamicEntityLayerRef.kt +30 -0
- package/android/src/main/java/expo/modules/arcgis/ExpoArcgisExtrasModule.kt +102 -0
- package/android/src/main/java/expo/modules/arcgis/ExpoArcgisGeometryModule.kt +40 -0
- package/android/src/main/java/expo/modules/arcgis/ExpoArcgisMapView.kt +16 -0
- package/android/src/main/java/expo/modules/arcgis/ExpoArcgisModule.kt +21 -34
- package/android/src/main/java/expo/modules/arcgis/ExpoArcgisSceneView.kt +36 -0
- package/android/src/main/java/expo/modules/arcgis/GeocoderFunctions.kt +13 -3
- package/android/src/main/java/expo/modules/arcgis/GeometryEngineFunctions.kt +103 -0
- package/android/src/main/java/expo/modules/arcgis/GeoprocessingFunctions.kt +25 -0
- package/android/src/main/java/expo/modules/arcgis/GraphicsOverlayRef.kt +32 -0
- package/android/src/main/java/expo/modules/arcgis/LayerRef.kt +189 -7
- package/android/src/main/java/expo/modules/arcgis/OfflineFunctions.kt +19 -0
- package/android/src/main/java/expo/modules/arcgis/QueryCodec.kt +21 -0
- package/android/src/main/java/expo/modules/arcgis/RouterFunctions.kt +61 -0
- package/android/src/main/java/expo/modules/arcgis/UtilityNetworkRef.kt +24 -0
- package/build/DynamicEntityLayer.d.ts +4 -1
- package/build/DynamicEntityLayer.d.ts.map +1 -1
- package/build/DynamicEntityLayer.js +8 -1
- package/build/DynamicEntityLayer.js.map +1 -1
- package/build/ExpoArcgis.types.d.ts +364 -8
- package/build/ExpoArcgis.types.d.ts.map +1 -1
- package/build/ExpoArcgis.types.js.map +1 -1
- package/build/ExpoArcgisExtrasModule.d.ts +22 -0
- package/build/ExpoArcgisExtrasModule.d.ts.map +1 -0
- package/build/ExpoArcgisExtrasModule.js +3 -0
- package/build/ExpoArcgisExtrasModule.js.map +1 -0
- package/build/ExpoArcgisGeometryModule.d.ts +13 -1
- package/build/ExpoArcgisGeometryModule.d.ts.map +1 -1
- package/build/ExpoArcgisGeometryModule.js.map +1 -1
- package/build/ExpoArcgisModule.d.ts +19 -4
- 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/FeatureLayer.js +2 -2
- package/build/FeatureLayer.js.map +1 -1
- package/build/auth.d.ts +39 -0
- package/build/auth.d.ts.map +1 -1
- package/build/auth.js +47 -0
- package/build/auth.js.map +1 -1
- package/build/geometryEngine.d.ts +25 -1
- package/build/geometryEngine.d.ts.map +1 -1
- package/build/geometryEngine.js +24 -0
- package/build/geometryEngine.js.map +1 -1
- package/build/index.d.ts +3 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3 -1
- package/build/index.js.map +1 -1
- package/build/layers.d.ts +9 -1
- package/build/layers.d.ts.map +1 -1
- package/build/layers.js +8 -0
- package/build/layers.js.map +1 -1
- package/build/offline.d.ts +7 -1
- package/build/offline.d.ts.map +1 -1
- package/build/offline.js +7 -0
- package/build/offline.js.map +1 -1
- package/build/router.d.ts +6 -1
- package/build/router.d.ts.map +1 -1
- package/build/router.js +6 -0
- package/build/router.js.map +1 -1
- package/expo-module.config.json +6 -2
- package/ios/DynamicEntityLayerRef.swift +46 -0
- package/ios/ExpoArcgisExtrasModule.swift +104 -0
- package/ios/ExpoArcgisGeometryModule.swift +41 -0
- package/ios/ExpoArcgisMapView.swift +15 -0
- package/ios/ExpoArcgisModule.swift +18 -34
- package/ios/ExpoArcgisSceneView.swift +39 -0
- package/ios/GeocoderFunctions.swift +9 -1
- package/ios/GeometryEngineFunctions.swift +122 -0
- package/ios/GeoprocessingFunctions.swift +20 -0
- package/ios/GraphicsOverlayRef.swift +24 -0
- package/ios/LayerRef.swift +201 -7
- package/ios/OfflineFunctions.swift +14 -0
- package/ios/QueryCodec.swift +21 -1
- package/ios/RouterFunctions.swift +57 -0
- package/ios/UtilityNetworkRef.swift +21 -0
- package/package.json +1 -1
- package/src/DynamicEntityLayer.tsx +12 -1
- package/src/ExpoArcgis.types.ts +379 -9
- package/src/ExpoArcgisExtrasModule.ts +39 -0
- package/src/ExpoArcgisGeometryModule.ts +19 -0
- package/src/ExpoArcgisModule.ts +25 -3
- package/src/FeatureLayer.tsx +3 -2
- package/src/auth.ts +55 -0
- package/src/geometryEngine.ts +40 -0
- package/src/index.ts +5 -0
- package/src/layers.tsx +16 -0
- package/src/offline.ts +14 -0
- package/src/router.ts +16 -1
package/README.md
CHANGED
|
@@ -18,14 +18,14 @@ authentication.
|
|
|
18
18
|
| Area | What's covered |
|
|
19
19
|
|---|---|
|
|
20
20
|
| **2D / 3D** | `<MapView>` + `<Map>`; `<SceneView>` + `<Scene>` (surface, camera, web scenes, light/shadows) |
|
|
21
|
-
| **Layers** | Feature, Tile, MapImage, Vector-tile, Raster, WMS, WMTS, KML, Scene, IntegratedMesh, PointCloud, OGC 3D Tiles, WebTiled, OpenStreetMap, WFS, OGC API Features, DynamicEntity (stream), Annotation, Dimension, BuildingScene (3D), OrientedImagery, SubtypeFeature, **Group** (container) |
|
|
21
|
+
| **Layers** | Feature, Tile, MapImage, Vector-tile, Raster, WMS, WMTS, KML, Scene, IntegratedMesh, PointCloud, OGC 3D Tiles, WebTiled, OpenStreetMap, WFS, OGC API Features, DynamicEntity (stream), Annotation, Dimension, BuildingScene (3D), OrientedImagery, SubtypeFeature, **Group** (container), **FeatureCollection** (in-memory), **GeoPackage** (local `.gpkg`) |
|
|
22
22
|
| **Graphics** | `<GraphicsOverlay>` + `<Graphic>`, symbols (simple marker/line/fill, text, 3D scene symbol, picture-marker), renderers (simple / unique-value / class-breaks), labels, clustering |
|
|
23
23
|
| **Geometry** | `geometryEngine` (buffer, project, distance, intersect, …), `coordinateFormatter`, codec for all geometry types |
|
|
24
24
|
| **Query** | feature query / count / extent / statistics on a `<FeatureLayer>` ref; `identify` on a view ref |
|
|
25
25
|
| **Editing** | add / update / delete features, `<GeometryEditor>` (tools), feature templates |
|
|
26
26
|
| **Location** | device location, simulated location data source, `onLocationChange` |
|
|
27
27
|
| **Geocoding** | `geocoder.geocode` / `reverseGeocode` / `suggest`, offline `.loc` locators |
|
|
28
|
-
| **Routing** | `router.solveRoute` / directions, travel modes, point barriers, curb approach |
|
|
28
|
+
| **Routing** | `router.solveRoute` / directions, travel modes, point barriers, curb approach; `router.createRouteTracker` turn-by-turn navigation |
|
|
29
29
|
| **Analysis (3D)** | `<AnalysisOverlay>` + `<Viewshed>` / `<LineOfSight>` / `<DistanceMeasurement>` |
|
|
30
30
|
| **Geoprocessing** | `geoprocessor.execute` → `JobRef` (progress + cancel), typed parameters |
|
|
31
31
|
| **Utility network** | `<UtilityNetwork>` load + trace, named configs, associations, `describeNetwork` |
|
|
@@ -126,7 +126,7 @@ const [hit] = await geocoder.geocode('Los Angeles');
|
|
|
126
126
|
`IntegratedMeshLayer`, `PointCloudLayer`, `Ogc3DTilesLayer`, `WebTiledLayer`, `OpenStreetMapLayer`,
|
|
127
127
|
`WmsLayer`, `WmtsLayer`, `RasterLayer`, `KmlLayer`, `WfsLayer`, `OgcFeatureLayer`, `DynamicEntityLayer`,
|
|
128
128
|
`AnnotationLayer`, `DimensionLayer`, `BuildingSceneLayer`, `OrientedImageryLayer`, `SubtypeFeatureLayer`,
|
|
129
|
-
`GroupLayer`
|
|
129
|
+
`GroupLayer`, `FeatureCollectionLayer`, `GeoPackageLayer`
|
|
130
130
|
- **Graphics & analysis** — `GraphicsOverlay`, `Graphic`, `AnalysisOverlay`, `Viewshed`, `LineOfSight`,
|
|
131
131
|
`DistanceMeasurement`, `GeometryEditor`, `UtilityNetwork`
|
|
132
132
|
- **Namespaces** — `geometryEngine`, `coordinateFormatter`, `geocoder`, `router`, `geoprocessor`, `offline`
|
|
@@ -39,6 +39,18 @@ class DynamicEntityLayerRef(appContext: AppContext, props: Map<String, Any?>) :
|
|
|
39
39
|
emit("onConnectionStatusChange", mapOf("status" to connectionStatusString(status)))
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
+
// Emit entity-received events (new/updated observation arrived for an entity).
|
|
43
|
+
scope.launch {
|
|
44
|
+
dataSource.dynamicEntityReceivedEvent.collect { info ->
|
|
45
|
+
emit("onDynamicEntityChange", dynamicEntityPayload("received", info.dynamicEntity))
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// Emit entity-purged events (entity evicted by purge rules).
|
|
49
|
+
scope.launch {
|
|
50
|
+
dataSource.dynamicEntityPurgedEvent.collect { info ->
|
|
51
|
+
emit("onDynamicEntityChange", dynamicEntityPayload("purged", info.dynamicEntity))
|
|
52
|
+
}
|
|
53
|
+
}
|
|
42
54
|
}
|
|
43
55
|
|
|
44
56
|
/** Pushes an observation into a custom data source (no-op for a stream service). */
|
|
@@ -97,6 +109,24 @@ fun connectionStatusString(status: ConnectionStatus): String = when (status) {
|
|
|
97
109
|
is ConnectionStatus.Failed -> "failed"
|
|
98
110
|
}
|
|
99
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Builds a compact payload for the `onDynamicEntityChange` event.
|
|
114
|
+
* Only `received` and `purged` change types are emitted (observation-only updates are
|
|
115
|
+
* captured within `dynamicEntityReceivedEvent` which fires per-entity arrival, not per
|
|
116
|
+
* observation, so the event rate is bounded to entity lifecycle changes).
|
|
117
|
+
* Geometry is serialized only when present; attributes are passed as-is (the map returned
|
|
118
|
+
* by the SDK is a shallow snapshot of the current entity attributes).
|
|
119
|
+
*/
|
|
120
|
+
private fun dynamicEntityPayload(changeType: String, entity: com.arcgismaps.realtime.DynamicEntity): Map<String, Any?> {
|
|
121
|
+
val payload = mutableMapOf<String, Any?>(
|
|
122
|
+
"changeType" to changeType,
|
|
123
|
+
"entityId" to entity.id,
|
|
124
|
+
"attributes" to entity.attributes.toMap(),
|
|
125
|
+
)
|
|
126
|
+
entity.geometry?.let { payload["geometry"] = dictFromGeometry(it) }
|
|
127
|
+
return payload
|
|
128
|
+
}
|
|
129
|
+
|
|
100
130
|
/** Builds the real-time data source: a custom feed (push from JS) or a stream service. */
|
|
101
131
|
private fun buildDataSource(
|
|
102
132
|
props: Map<String, Any?>,
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
package expo.modules.arcgis
|
|
2
|
+
|
|
3
|
+
import com.arcgismaps.ArcGISEnvironment
|
|
4
|
+
import com.arcgismaps.httpcore.authentication.TokenCredential
|
|
5
|
+
import expo.modules.kotlin.functions.Coroutine
|
|
6
|
+
import expo.modules.kotlin.modules.Module
|
|
7
|
+
import expo.modules.kotlin.modules.ModuleDefinition
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Third native module, hosting the heavier operational-layer SharedObject classes (currently
|
|
11
|
+
* [FeatureLayerRef]), exposed to JS as `ExpoArcgisExtras`. Split out of [ExpoArcgisGeometryModule]
|
|
12
|
+
* so that no module's `definition()` exceeds the JVM 64 KB method-size limit. SharedObjects are
|
|
13
|
+
* global, so a ref constructed here attaches to a `<MapView>` from the main module fine.
|
|
14
|
+
*/
|
|
15
|
+
class ExpoArcgisExtrasModule : Module() {
|
|
16
|
+
override fun definition() = ModuleDefinition {
|
|
17
|
+
Name("ExpoArcgisExtras")
|
|
18
|
+
|
|
19
|
+
Class(FeatureLayerRef::class) {
|
|
20
|
+
Constructor { props: Map<String, Any?> ->
|
|
21
|
+
FeatureLayerRef(appContext, props).also { it.applyProps(props) }
|
|
22
|
+
}
|
|
23
|
+
Function("applyProps") { ref: FeatureLayerRef, changed: Map<String, Any?> ->
|
|
24
|
+
ref.applyProps(changed)
|
|
25
|
+
}
|
|
26
|
+
AsyncFunction("queryFeatures") Coroutine { ref: FeatureLayerRef, query: Map<String, Any?>? ->
|
|
27
|
+
ref.queryFeatures(query)
|
|
28
|
+
}
|
|
29
|
+
AsyncFunction("queryFeatureCount") Coroutine { ref: FeatureLayerRef, query: Map<String, Any?>? ->
|
|
30
|
+
ref.queryFeatureCount(query)
|
|
31
|
+
}
|
|
32
|
+
AsyncFunction("queryExtent") Coroutine { ref: FeatureLayerRef, query: Map<String, Any?>? ->
|
|
33
|
+
ref.queryExtent(query)
|
|
34
|
+
}
|
|
35
|
+
AsyncFunction("queryStatistics") Coroutine { ref: FeatureLayerRef, query: Map<String, Any?> ->
|
|
36
|
+
ref.queryStatistics(query)
|
|
37
|
+
}
|
|
38
|
+
AsyncFunction("queryFeatureTemplates") Coroutine { ref: FeatureLayerRef ->
|
|
39
|
+
ref.queryFeatureTemplates()
|
|
40
|
+
}
|
|
41
|
+
AsyncFunction("addFeature") Coroutine { ref: FeatureLayerRef, attributes: Map<String, Any?>, geometry: Map<String, Any?>?, apply: Boolean? ->
|
|
42
|
+
ref.addFeature(attributes, geometry, apply)
|
|
43
|
+
}
|
|
44
|
+
AsyncFunction("updateFeature") Coroutine { ref: FeatureLayerRef, objectId: Long, changes: Map<String, Any?>, apply: Boolean? ->
|
|
45
|
+
ref.updateFeature(objectId, changes, apply)
|
|
46
|
+
}
|
|
47
|
+
AsyncFunction("deleteFeature") Coroutine { ref: FeatureLayerRef, objectId: Long, apply: Boolean? ->
|
|
48
|
+
ref.deleteFeature(objectId, apply)
|
|
49
|
+
}
|
|
50
|
+
AsyncFunction("applyEdits") Coroutine { ref: FeatureLayerRef ->
|
|
51
|
+
ref.applyEdits()
|
|
52
|
+
}
|
|
53
|
+
AsyncFunction("undoLocalEdits") Coroutine { ref: FeatureLayerRef ->
|
|
54
|
+
ref.undoLocalEdits()
|
|
55
|
+
}
|
|
56
|
+
AsyncFunction("queryRelatedFeatures") Coroutine { ref: FeatureLayerRef, objectId: Long ->
|
|
57
|
+
ref.queryRelatedFeatures(objectId)
|
|
58
|
+
}
|
|
59
|
+
AsyncFunction("queryAttachments") Coroutine { ref: FeatureLayerRef, objectId: Long ->
|
|
60
|
+
ref.queryAttachments(objectId)
|
|
61
|
+
}
|
|
62
|
+
AsyncFunction("addAttachment") Coroutine { ref: FeatureLayerRef, objectId: Long, name: String, contentType: String, dataBase64: String ->
|
|
63
|
+
ref.addAttachment(objectId, name, contentType, dataBase64)
|
|
64
|
+
}
|
|
65
|
+
AsyncFunction("fetchAttachment") Coroutine { ref: FeatureLayerRef, objectId: Long, attachmentId: Long ->
|
|
66
|
+
ref.fetchAttachment(objectId, attachmentId)
|
|
67
|
+
}
|
|
68
|
+
AsyncFunction("deleteAttachment") Coroutine { ref: FeatureLayerRef, objectId: Long, attachmentId: Long ->
|
|
69
|
+
ref.deleteAttachment(objectId, attachmentId)
|
|
70
|
+
}
|
|
71
|
+
AsyncFunction("updateAttachment") Coroutine { ref: FeatureLayerRef, objectId: Long, attachmentId: Long, name: String, contentType: String, dataBase64: String ->
|
|
72
|
+
ref.updateAttachment(objectId, attachmentId, name, contentType, dataBase64)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Per-service token credential — mint a token for a specific URL and add it to the store.
|
|
77
|
+
AsyncFunction("setServiceCredential") Coroutine { serviceUrl: String, username: String, password: String, tokenExpirationMinutes: Int? ->
|
|
78
|
+
val credential = TokenCredential.create(serviceUrl, username, password, tokenExpirationMinutes)
|
|
79
|
+
.getOrThrow()
|
|
80
|
+
ArcGISEnvironment.authenticationManager.arcGISCredentialStore.add(credential, serviceUrl)
|
|
81
|
+
.getOrThrow()
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Tile-cache size estimation — quick estimate before committing to a download.
|
|
85
|
+
AsyncFunction("estimateTileCacheSize") Coroutine { tileServiceUrl: String, areaOfInterest: Map<String, Any?>, options: Map<String, Any?>? ->
|
|
86
|
+
estimateTileCacheSize(tileServiceUrl, areaOfInterest, options)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Turn-by-turn navigation — solve a route and track device locations against it.
|
|
90
|
+
AsyncFunction("createRouteTracker") Coroutine { stops: List<Map<String, Any?>>, params: Map<String, Any?> ->
|
|
91
|
+
createRouteTracker(appContext, stops, params)
|
|
92
|
+
}
|
|
93
|
+
Class(RouteTrackerRef::class) {
|
|
94
|
+
AsyncFunction("trackLocation") Coroutine { ref: RouteTrackerRef, location: Map<String, Any?> ->
|
|
95
|
+
ref.trackLocation(location)
|
|
96
|
+
}
|
|
97
|
+
AsyncFunction("switchToNextDestination") Coroutine { ref: RouteTrackerRef ->
|
|
98
|
+
ref.switchToNextDestination()
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
package expo.modules.arcgis
|
|
2
2
|
|
|
3
|
+
import com.arcgismaps.ArcGISEnvironment
|
|
4
|
+
import com.arcgismaps.httpcore.authentication.ArcGISCredentialStore
|
|
3
5
|
import expo.modules.kotlin.functions.Coroutine
|
|
4
6
|
import expo.modules.kotlin.modules.Module
|
|
5
7
|
import expo.modules.kotlin.modules.ModuleDefinition
|
|
@@ -30,6 +32,12 @@ class ExpoArcgisGeometryModule : Module() {
|
|
|
30
32
|
Function("geClip", ::geClip)
|
|
31
33
|
Function("geCut", ::geCut)
|
|
32
34
|
Function("geConvexHull", ::geConvexHull)
|
|
35
|
+
Function("geLabelPoint", ::geLabelPoint)
|
|
36
|
+
Function("geNormalizeCentralMeridian", ::geNormalizeCentralMeridian)
|
|
37
|
+
Function("geReshape", ::geReshape)
|
|
38
|
+
Function("geIntersections", ::geIntersections)
|
|
39
|
+
Function("geExtend", ::geExtend)
|
|
40
|
+
Function("geAutoComplete", ::geAutoComplete)
|
|
33
41
|
Function("geBoundary", ::geBoundary)
|
|
34
42
|
Function("geSimplify", ::geSimplify)
|
|
35
43
|
Function("geDensify", ::geDensify)
|
|
@@ -51,6 +59,8 @@ class ExpoArcgisGeometryModule : Module() {
|
|
|
51
59
|
Function("geMove", ::geMove)
|
|
52
60
|
Function("geRotate", ::geRotate)
|
|
53
61
|
Function("geScale", ::geScale)
|
|
62
|
+
Function("geEllipseGeodesic", ::geEllipseGeodesic)
|
|
63
|
+
Function("geSectorGeodesic", ::geSectorGeodesic)
|
|
54
64
|
|
|
55
65
|
// CoordinateFormatter — point <-> notation strings, exposed as the JS `coordinateFormatter` namespace.
|
|
56
66
|
Function("cfToLatLong", ::cfToLatLong)
|
|
@@ -132,6 +142,36 @@ class ExpoArcgisGeometryModule : Module() {
|
|
|
132
142
|
Function("addLayer") { ref: GroupLayerRef, layer: LayerRef -> ref.addLayer(layer) }
|
|
133
143
|
Function("removeLayer") { ref: GroupLayerRef, layer: LayerRef -> ref.removeLayer(layer) }
|
|
134
144
|
}
|
|
145
|
+
// FeatureLayerRef moved to the third module (ExpoArcgisExtras) to keep this module's
|
|
146
|
+
// definition() under the 64 KB limit. SharedObjects are global, so it stays cross-module.
|
|
147
|
+
// In-memory FeatureCollectionLayer — built from a client-side schema + features (no service).
|
|
148
|
+
Class(FeatureCollectionLayerRef::class) {
|
|
149
|
+
Constructor { props: Map<String, Any?> ->
|
|
150
|
+
FeatureCollectionLayerRef(appContext, props).also { it.applyProps(props) }
|
|
151
|
+
}
|
|
152
|
+
Function("applyProps") { ref: FeatureCollectionLayerRef, changed: Map<String, Any?> -> ref.applyProps(changed) }
|
|
153
|
+
}
|
|
154
|
+
// GeoPackage layer — async-loads a local .gpkg, picks the feature table, wraps it in a FeatureLayer.
|
|
155
|
+
Class(GeoPackageLayerRef::class) {
|
|
156
|
+
Constructor { props: Map<String, Any?> ->
|
|
157
|
+
GeoPackageLayerRef(
|
|
158
|
+
appContext,
|
|
159
|
+
props["path"] as? String ?: "",
|
|
160
|
+
props["tableName"] as? String,
|
|
161
|
+
).also { it.applyProps(props) }
|
|
162
|
+
}
|
|
163
|
+
Function("applyProps") { ref: GeoPackageLayerRef, changed: Map<String, Any?> -> ref.applyProps(changed) }
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Auth — persistent credential store (survives app restarts via Android encrypted storage).
|
|
167
|
+
// Registered here (not in the main module) because the main module is at the JVM 64 KB limit.
|
|
168
|
+
AsyncFunction("enablePersistentCredentialStore") Coroutine { ->
|
|
169
|
+
val store = ArcGISCredentialStore.createWithPersistence().getOrThrow()
|
|
170
|
+
ArcGISEnvironment.authenticationManager.arcGISCredentialStore = store
|
|
171
|
+
}
|
|
172
|
+
AsyncFunction("clearCredentialStore") Coroutine { ->
|
|
173
|
+
ArcGISEnvironment.authenticationManager.arcGISCredentialStore.removeAll()
|
|
174
|
+
}
|
|
135
175
|
|
|
136
176
|
// Offline — take maps/data offline, exposed as the JS `offline` namespace.
|
|
137
177
|
AsyncFunction("generateOfflineMap") Coroutine { portalItemId: String, areaOfInterest: Map<String, Any?>, downloadName: String ->
|
|
@@ -196,6 +196,22 @@ class ExpoArcgisMapView(context: Context, appContext: AppContext) : ExpoView(con
|
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
+
/** Identifies popups under a screen point — evaluates each and returns `{ title, fields }`. */
|
|
200
|
+
fun identifyPopups(screenPoint: Map<String, Any?>, options: Map<String, Any?>?, promise: Promise) {
|
|
201
|
+
val x = (screenPoint["x"] as? Number)?.toDouble() ?: 0.0
|
|
202
|
+
val y = (screenPoint["y"] as? Number)?.toDouble() ?: 0.0
|
|
203
|
+
val tolerance = (options?.get("tolerance") as? Number)?.toDouble() ?: 12.0
|
|
204
|
+
val maxResults = (options?.get("maxResults") as? Number)?.toInt() ?: 1
|
|
205
|
+
scope.launch {
|
|
206
|
+
try {
|
|
207
|
+
val results = mapView.identifyLayers(ScreenCoordinate(x, y), tolerance, false, maxResults).getOrThrow()
|
|
208
|
+
promise.resolve(serializePopups(results))
|
|
209
|
+
} catch (e: Exception) {
|
|
210
|
+
promise.reject("IDENTIFY_ERROR", e.message ?: "Identify failed", e)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
199
215
|
/** Retries loading the map (Loadable pattern) — useful after a network outage. Re-emits the result. */
|
|
200
216
|
fun retryLoad(promise: Promise) {
|
|
201
217
|
val map = mapView.map ?: run { promise.resolve(null); return }
|
|
@@ -96,38 +96,8 @@ class ExpoArcgisModule : Module() {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
// Operational layers — SharedObjects the JS <FeatureLayer>/<TileLayer> construct.
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
FeatureLayerRef(appContext, props).also { it.applyProps(props) }
|
|
102
|
-
}
|
|
103
|
-
Function("applyProps") { ref: FeatureLayerRef, changed: Map<String, Any?> ->
|
|
104
|
-
ref.applyProps(changed)
|
|
105
|
-
}
|
|
106
|
-
AsyncFunction("queryFeatures") Coroutine { ref: FeatureLayerRef, query: Map<String, Any?>? ->
|
|
107
|
-
ref.queryFeatures(query)
|
|
108
|
-
}
|
|
109
|
-
AsyncFunction("queryFeatureCount") Coroutine { ref: FeatureLayerRef, query: Map<String, Any?>? ->
|
|
110
|
-
ref.queryFeatureCount(query)
|
|
111
|
-
}
|
|
112
|
-
AsyncFunction("queryExtent") Coroutine { ref: FeatureLayerRef, query: Map<String, Any?>? ->
|
|
113
|
-
ref.queryExtent(query)
|
|
114
|
-
}
|
|
115
|
-
AsyncFunction("queryStatistics") Coroutine { ref: FeatureLayerRef, query: Map<String, Any?> ->
|
|
116
|
-
ref.queryStatistics(query)
|
|
117
|
-
}
|
|
118
|
-
AsyncFunction("queryFeatureTemplates") Coroutine { ref: FeatureLayerRef ->
|
|
119
|
-
ref.queryFeatureTemplates()
|
|
120
|
-
}
|
|
121
|
-
AsyncFunction("addFeature") Coroutine { ref: FeatureLayerRef, attributes: Map<String, Any?>, geometry: Map<String, Any?>? ->
|
|
122
|
-
ref.addFeature(attributes, geometry)
|
|
123
|
-
}
|
|
124
|
-
AsyncFunction("updateFeature") Coroutine { ref: FeatureLayerRef, objectId: Long, changes: Map<String, Any?> ->
|
|
125
|
-
ref.updateFeature(objectId, changes)
|
|
126
|
-
}
|
|
127
|
-
AsyncFunction("deleteFeature") Coroutine { ref: FeatureLayerRef, objectId: Long ->
|
|
128
|
-
ref.deleteFeature(objectId)
|
|
129
|
-
}
|
|
130
|
-
}
|
|
99
|
+
// FeatureLayerRef is registered on the ExpoArcgisGeometry module to keep this module's
|
|
100
|
+
// definition() under the Android JVM 64 KB method-size limit (SharedObjects cross modules).
|
|
131
101
|
|
|
132
102
|
Class(TiledLayerRef::class) {
|
|
133
103
|
Constructor { props: Map<String, Any?> ->
|
|
@@ -264,12 +234,13 @@ class ExpoArcgisModule : Module() {
|
|
|
264
234
|
Function("applyProps") { ref: OgcFeatureLayerRef, changed: Map<String, Any?> -> ref.applyProps(changed) }
|
|
265
235
|
}
|
|
266
236
|
|
|
267
|
-
// Real-time DynamicEntityLayer (stream service) — emits onConnectionStatusChange
|
|
237
|
+
// Real-time DynamicEntityLayer (stream service) — emits onConnectionStatusChange +
|
|
238
|
+
// onDynamicEntityChange (received/purged entity events).
|
|
268
239
|
Class(DynamicEntityLayerRef::class) {
|
|
269
240
|
Constructor { props: Map<String, Any?> ->
|
|
270
241
|
DynamicEntityLayerRef(appContext, props).also { it.applyProps(props) }
|
|
271
242
|
}
|
|
272
|
-
Events("onConnectionStatusChange")
|
|
243
|
+
Events("onConnectionStatusChange", "onDynamicEntityChange")
|
|
273
244
|
Function("applyProps") { ref: DynamicEntityLayerRef, changed: Map<String, Any?> ->
|
|
274
245
|
ref.applyProps(changed)
|
|
275
246
|
}
|
|
@@ -358,6 +329,10 @@ class ExpoArcgisModule : Module() {
|
|
|
358
329
|
AsyncFunction("associations") Coroutine { ref: UtilityNetworkRef, tableName: String, whereClause: String ->
|
|
359
330
|
ref.associations(tableName, whereClause)
|
|
360
331
|
}
|
|
332
|
+
AsyncFunction("getState") Coroutine { ref: UtilityNetworkRef -> ref.getState() }
|
|
333
|
+
Function("validateNetworkTopology") { ref: UtilityNetworkRef, extent: Map<String, Any?> ->
|
|
334
|
+
ref.validateNetworkTopology(extent)
|
|
335
|
+
}
|
|
361
336
|
}
|
|
362
337
|
|
|
363
338
|
// Interactive GeometryEditor — bound to a <MapView> for sketching; emits onGeometryChange.
|
|
@@ -401,6 +376,10 @@ class ExpoArcgisModule : Module() {
|
|
|
401
376
|
view.identify(screenPoint, options, promise)
|
|
402
377
|
}
|
|
403
378
|
|
|
379
|
+
AsyncFunction("identifyPopups") { view: ExpoArcgisMapView, screenPoint: Map<String, Any?>, options: Map<String, Any?>?, promise: Promise ->
|
|
380
|
+
view.identifyPopups(screenPoint, options, promise)
|
|
381
|
+
}
|
|
382
|
+
|
|
404
383
|
AsyncFunction("retryLoad") { view: ExpoArcgisMapView, promise: Promise ->
|
|
405
384
|
view.retryLoad(promise)
|
|
406
385
|
}
|
|
@@ -427,6 +406,10 @@ class ExpoArcgisModule : Module() {
|
|
|
427
406
|
view.setCamera(camera)
|
|
428
407
|
}
|
|
429
408
|
|
|
409
|
+
Prop("cameraController") { view: ExpoArcgisSceneView, value: Map<String, Any?>? ->
|
|
410
|
+
view.setCameraController(value)
|
|
411
|
+
}
|
|
412
|
+
|
|
430
413
|
Prop("sunLighting") { view: ExpoArcgisSceneView, value: String? ->
|
|
431
414
|
view.setSunLighting(value)
|
|
432
415
|
}
|
|
@@ -446,6 +429,10 @@ class ExpoArcgisModule : Module() {
|
|
|
446
429
|
AsyncFunction("identify") { view: ExpoArcgisSceneView, screenPoint: Map<String, Any?>, options: Map<String, Any?>?, promise: Promise ->
|
|
447
430
|
view.identify(screenPoint, options, promise)
|
|
448
431
|
}
|
|
432
|
+
|
|
433
|
+
AsyncFunction("identifyPopups") { view: ExpoArcgisSceneView, screenPoint: Map<String, Any?>, options: Map<String, Any?>?, promise: Promise ->
|
|
434
|
+
view.identifyPopups(screenPoint, options, promise)
|
|
435
|
+
}
|
|
449
436
|
}
|
|
450
437
|
}
|
|
451
438
|
}
|
|
@@ -9,7 +9,9 @@ import com.arcgismaps.geometry.Point
|
|
|
9
9
|
import com.arcgismaps.geometry.SpatialReference
|
|
10
10
|
import com.arcgismaps.mapping.view.AtmosphereEffect
|
|
11
11
|
import com.arcgismaps.mapping.view.Camera
|
|
12
|
+
import com.arcgismaps.mapping.view.GlobeCameraController
|
|
12
13
|
import com.arcgismaps.mapping.view.LightingMode
|
|
14
|
+
import com.arcgismaps.mapping.view.OrbitLocationCameraController
|
|
13
15
|
import com.arcgismaps.mapping.view.SceneView
|
|
14
16
|
import com.arcgismaps.mapping.view.ScreenCoordinate
|
|
15
17
|
import expo.modules.kotlin.AppContext
|
|
@@ -101,6 +103,22 @@ class ExpoArcgisSceneView(context: Context, appContext: AppContext) : ExpoView(c
|
|
|
101
103
|
}
|
|
102
104
|
}
|
|
103
105
|
|
|
106
|
+
/** Identifies popups under a screen point — evaluates each and returns `{ title, fields }`. */
|
|
107
|
+
fun identifyPopups(screenPoint: Map<String, Any?>, options: Map<String, Any?>?, promise: Promise) {
|
|
108
|
+
val x = (screenPoint["x"] as? Number)?.toDouble() ?: 0.0
|
|
109
|
+
val y = (screenPoint["y"] as? Number)?.toDouble() ?: 0.0
|
|
110
|
+
val tolerance = (options?.get("tolerance") as? Number)?.toDouble() ?: 12.0
|
|
111
|
+
val maxResults = (options?.get("maxResults") as? Number)?.toInt() ?: 1
|
|
112
|
+
scope.launch {
|
|
113
|
+
try {
|
|
114
|
+
val results = sceneView.identifyLayers(ScreenCoordinate(x, y), tolerance, false, maxResults).getOrThrow()
|
|
115
|
+
promise.resolve(serializePopups(results))
|
|
116
|
+
} catch (e: Exception) {
|
|
117
|
+
promise.reject("IDENTIFY_ERROR", e.message ?: "Identify failed", e)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
104
122
|
/** Retries loading the scene (Loadable pattern) — useful after a network outage. Re-emits the result. */
|
|
105
123
|
fun retryLoad(promise: Promise) {
|
|
106
124
|
val scene = sceneView.scene ?: run { promise.resolve(null); return }
|
|
@@ -131,6 +149,24 @@ class ExpoArcgisSceneView(context: Context, appContext: AppContext) : ExpoView(c
|
|
|
131
149
|
scope.launch { sceneView.setViewpointCameraAnimated(camera, 0.5f) }
|
|
132
150
|
}
|
|
133
151
|
|
|
152
|
+
/** Sets or clears the scene's camera controller (orbit/globe). `null` restores the SDK default. */
|
|
153
|
+
fun setCameraController(c: Map<String, Any?>?) {
|
|
154
|
+
sceneView.cameraController = when (c?.get("type") as? String) {
|
|
155
|
+
"orbitLocation" -> {
|
|
156
|
+
val target = c["target"] as? Map<*, *>
|
|
157
|
+
val x = (target?.get("x") as? Number)?.toDouble() ?: 0.0
|
|
158
|
+
val y = (target?.get("y") as? Number)?.toDouble() ?: 0.0
|
|
159
|
+
val z = (target?.get("z") as? Number)?.toDouble()
|
|
160
|
+
val point = if (z != null) Point(x, y, z, SpatialReference.wgs84())
|
|
161
|
+
else Point(x, y, SpatialReference.wgs84())
|
|
162
|
+
val distance = (c["distance"] as? Number)?.toDouble() ?: 1500.0
|
|
163
|
+
OrbitLocationCameraController(point, distance)
|
|
164
|
+
}
|
|
165
|
+
"globe" -> GlobeCameraController()
|
|
166
|
+
else -> GlobeCameraController() // null/absent → restore SDK default (GlobeCameraController)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
134
170
|
/** Sun lighting mode (shadows). */
|
|
135
171
|
fun setSunLighting(s: String?) {
|
|
136
172
|
sceneView.sunLighting = when (s) {
|
|
@@ -25,9 +25,19 @@ private fun locatorTask(params: Map<String, Any?>): LocatorTask {
|
|
|
25
25
|
return locators.getOrPut(url) { LocatorTask(url) }
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
internal suspend fun geocode(searchText: String, params: Map<String, Any?>): List<Map<String, Any?>>
|
|
29
|
-
locatorTask(params)
|
|
30
|
-
|
|
28
|
+
internal suspend fun geocode(searchText: String, params: Map<String, Any?>): List<Map<String, Any?>> {
|
|
29
|
+
val locator = locatorTask(params)
|
|
30
|
+
val parameters = buildGeocodeParameters(params)
|
|
31
|
+
@Suppress("UNCHECKED_CAST")
|
|
32
|
+
val searchValues = (params["searchValues"] as? Map<*, *>)
|
|
33
|
+
?.mapNotNull { (k, v) -> if (k is String && v is String) k to v else null }
|
|
34
|
+
?.toMap()
|
|
35
|
+
return if (!searchValues.isNullOrEmpty()) {
|
|
36
|
+
locator.geocode(searchValues, parameters).getOrThrow()
|
|
37
|
+
} else {
|
|
38
|
+
locator.geocode(searchText, parameters).getOrThrow()
|
|
39
|
+
}.map { serializeGeocodeResult(it) }
|
|
40
|
+
}
|
|
31
41
|
|
|
32
42
|
internal suspend fun reverseGeocode(point: Map<String, Any?>, params: Map<String, Any?>): List<Map<String, Any?>> {
|
|
33
43
|
val location = geometryFromDict(point) as? Point ?: return emptyList()
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
package expo.modules.arcgis
|
|
2
2
|
|
|
3
3
|
import com.arcgismaps.geometry.Envelope
|
|
4
|
+
import com.arcgismaps.geometry.GeodesicEllipseParameters
|
|
5
|
+
import com.arcgismaps.geometry.GeodesicSectorParameters
|
|
4
6
|
import com.arcgismaps.geometry.Geometry
|
|
5
7
|
import com.arcgismaps.geometry.GeometryEngine
|
|
8
|
+
import com.arcgismaps.geometry.Multipart
|
|
6
9
|
import com.arcgismaps.geometry.Point
|
|
10
|
+
import com.arcgismaps.geometry.Polygon
|
|
7
11
|
import com.arcgismaps.geometry.Polyline
|
|
8
12
|
|
|
9
13
|
/**
|
|
@@ -104,6 +108,39 @@ internal fun geCut(g: Map<String, Any?>, cutter: Map<String, Any?>): List<Map<St
|
|
|
104
108
|
internal fun geConvexHull(g: Map<String, Any?>): Map<String, Any?>? =
|
|
105
109
|
parseGeo(g)?.let { encode(GeometryEngine.convexHullOrNull(it)) }
|
|
106
110
|
|
|
111
|
+
internal fun geLabelPoint(g: Map<String, Any?>): Map<String, Any?>? =
|
|
112
|
+
(parseGeo(g) as? Polygon)?.let { encode(GeometryEngine.labelPointOrNull(it)) }
|
|
113
|
+
|
|
114
|
+
internal fun geNormalizeCentralMeridian(g: Map<String, Any?>): Map<String, Any?>? =
|
|
115
|
+
parseGeo(g)?.let { encode(GeometryEngine.normalizeCentralMeridian(it)) }
|
|
116
|
+
|
|
117
|
+
internal fun geReshape(g: Map<String, Any?>, reshaper: Map<String, Any?>): Map<String, Any?>? {
|
|
118
|
+
val multipart = parseGeo(g) as? Multipart ?: return null
|
|
119
|
+
val line = parseGeo(reshaper) as? Polyline ?: return null
|
|
120
|
+
return encode(GeometryEngine.reshape(multipart, line))
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
internal fun geIntersections(a: Map<String, Any?>, b: Map<String, Any?>): List<Map<String, Any?>> {
|
|
124
|
+
val g1 = parseGeo(a) ?: return emptyList()
|
|
125
|
+
val g2 = parseGeo(b) ?: return emptyList()
|
|
126
|
+
return GeometryEngine.tryIntersections(g1, g2).mapNotNull { encode(it) }
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
internal fun geExtend(p: Map<String, Any?>, extender: Map<String, Any?>): Map<String, Any?>? {
|
|
130
|
+
val polyline = parseGeo(p) as? Polyline ?: return null
|
|
131
|
+
val ext = parseGeo(extender) as? Polyline ?: return null
|
|
132
|
+
return encode(GeometryEngine.extend(polyline, ext, emptySet()))
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
internal fun geAutoComplete(
|
|
136
|
+
existing: List<Map<String, Any?>>,
|
|
137
|
+
boundaries: List<Map<String, Any?>>,
|
|
138
|
+
): List<Map<String, Any?>> {
|
|
139
|
+
val polygons = existing.mapNotNull { parseGeo(it) as? Polygon }
|
|
140
|
+
val lines = boundaries.mapNotNull { parseGeo(it) as? Polyline }
|
|
141
|
+
return GeometryEngine.tryAutoComplete(polygons, lines).mapNotNull { encode(it) }
|
|
142
|
+
}
|
|
143
|
+
|
|
107
144
|
internal fun geBoundary(g: Map<String, Any?>): Map<String, Any?>? =
|
|
108
145
|
parseGeo(g)?.let { encode(GeometryEngine.boundaryOrNull(it)) }
|
|
109
146
|
|
|
@@ -221,3 +258,69 @@ internal fun geScale(
|
|
|
221
258
|
else GeometryEngine.scale(geometry, factorX, factorY),
|
|
222
259
|
)
|
|
223
260
|
}
|
|
261
|
+
|
|
262
|
+
// region Geodesic construction
|
|
263
|
+
|
|
264
|
+
internal fun geEllipseGeodesic(params: Map<String, Any?>): Map<String, Any?>? {
|
|
265
|
+
val centerDict = params["center"] as? Map<String, Any?> ?: return null
|
|
266
|
+
val center = parsePoint(centerDict) ?: return null
|
|
267
|
+
|
|
268
|
+
val semiAxis1Length = (params["semiAxis1Length"] as? Number)?.toDouble() ?: 0.0
|
|
269
|
+
val semiAxis2Length = (params["semiAxis2Length"] as? Number)?.toDouble() ?: 0.0
|
|
270
|
+
val axisDirection = (params["axisDirection"] as? Number)?.toDouble() ?: 0.0
|
|
271
|
+
val angUnit = angularUnit(params["angularUnit"] as? String)
|
|
272
|
+
val linUnit = linearUnit(params["linearUnit"] as? String)
|
|
273
|
+
val maxSegLen = (params["maxSegmentLength"] as? Number)?.toDouble() ?: 0.0
|
|
274
|
+
val maxPtCount = (params["maxPointCount"] as? Number)?.toLong() ?: 10L
|
|
275
|
+
val geoType = params["geometryType"] as? String
|
|
276
|
+
|
|
277
|
+
val p: GeodesicEllipseParameters = when (geoType) {
|
|
278
|
+
"polyline" -> GeodesicEllipseParameters.Companion.createForPolyline()
|
|
279
|
+
"multipoint" -> GeodesicEllipseParameters.Companion.createForMultipoint()
|
|
280
|
+
else -> GeodesicEllipseParameters.Companion.createForPolygon()
|
|
281
|
+
}
|
|
282
|
+
p.center = center
|
|
283
|
+
p.semiAxis1Length = semiAxis1Length
|
|
284
|
+
p.semiAxis2Length = semiAxis2Length
|
|
285
|
+
p.axisDirection = axisDirection
|
|
286
|
+
p.angularUnit = angUnit
|
|
287
|
+
p.linearUnit = linUnit
|
|
288
|
+
p.maxSegmentLength = maxSegLen
|
|
289
|
+
p.maxPointCount = maxPtCount
|
|
290
|
+
|
|
291
|
+
return encode(GeometryEngine.ellipseGeodesicOrNull(p))
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
internal fun geSectorGeodesic(params: Map<String, Any?>): Map<String, Any?>? {
|
|
295
|
+
val centerDict = params["center"] as? Map<String, Any?> ?: return null
|
|
296
|
+
val center = parsePoint(centerDict) ?: return null
|
|
297
|
+
|
|
298
|
+
val semiAxis1Length = (params["semiAxis1Length"] as? Number)?.toDouble() ?: 0.0
|
|
299
|
+
val semiAxis2Length = (params["semiAxis2Length"] as? Number)?.toDouble() ?: 0.0
|
|
300
|
+
val axisDirection = (params["axisDirection"] as? Number)?.toDouble() ?: 0.0
|
|
301
|
+
val sectorAngle = (params["sectorAngle"] as? Number)?.toDouble() ?: 0.0
|
|
302
|
+
val startDirection = (params["startDirection"] as? Number)?.toDouble() ?: 0.0
|
|
303
|
+
val angUnit = angularUnit(params["angularUnit"] as? String)
|
|
304
|
+
val linUnit = linearUnit(params["linearUnit"] as? String)
|
|
305
|
+
val maxSegLen = (params["maxSegmentLength"] as? Number)?.toDouble() ?: 0.0
|
|
306
|
+
val maxPtCount = (params["maxPointCount"] as? Number)?.toLong() ?: 10L
|
|
307
|
+
val geoType = params["geometryType"] as? String
|
|
308
|
+
|
|
309
|
+
val p: GeodesicSectorParameters = when (geoType) {
|
|
310
|
+
"polyline" -> GeodesicSectorParameters.Companion.createForPolyline()
|
|
311
|
+
"multipoint" -> GeodesicSectorParameters.Companion.createForMultipoint()
|
|
312
|
+
else -> GeodesicSectorParameters.Companion.createForPolygon()
|
|
313
|
+
}
|
|
314
|
+
p.center = center
|
|
315
|
+
p.semiAxis1Length = semiAxis1Length
|
|
316
|
+
p.semiAxis2Length = semiAxis2Length
|
|
317
|
+
p.axisDirection = axisDirection
|
|
318
|
+
p.sectorAngle = sectorAngle
|
|
319
|
+
p.startDirection = startDirection
|
|
320
|
+
p.angularUnit = angUnit
|
|
321
|
+
p.linearUnit = linUnit
|
|
322
|
+
p.maxSegmentLength = maxSegLen
|
|
323
|
+
p.maxPointCount = maxPtCount
|
|
324
|
+
|
|
325
|
+
return encode(GeometryEngine.sectorGeodesicOrNull(p))
|
|
326
|
+
}
|
|
@@ -4,12 +4,15 @@ import com.arcgismaps.data.FeatureCollectionTable
|
|
|
4
4
|
import com.arcgismaps.mapping.view.Graphic
|
|
5
5
|
import com.arcgismaps.tasks.geoprocessing.GeoprocessingTask
|
|
6
6
|
import com.arcgismaps.tasks.geoprocessing.geoprocessingparameters.GeoprocessingBoolean
|
|
7
|
+
import com.arcgismaps.tasks.geoprocessing.geoprocessingparameters.GeoprocessingDataFile
|
|
7
8
|
import com.arcgismaps.tasks.geoprocessing.geoprocessingparameters.GeoprocessingDate
|
|
8
9
|
import com.arcgismaps.tasks.geoprocessing.geoprocessingparameters.GeoprocessingDouble
|
|
9
10
|
import com.arcgismaps.tasks.geoprocessing.geoprocessingparameters.GeoprocessingFeatures
|
|
10
11
|
import com.arcgismaps.tasks.geoprocessing.geoprocessingparameters.GeoprocessingLinearUnit
|
|
11
12
|
import com.arcgismaps.tasks.geoprocessing.geoprocessingparameters.GeoprocessingLong
|
|
13
|
+
import com.arcgismaps.tasks.geoprocessing.geoprocessingparameters.GeoprocessingMultiValue
|
|
12
14
|
import com.arcgismaps.tasks.geoprocessing.geoprocessingparameters.GeoprocessingParameter
|
|
15
|
+
import com.arcgismaps.tasks.geoprocessing.geoprocessingparameters.GeoprocessingParameterType
|
|
13
16
|
import com.arcgismaps.tasks.geoprocessing.geoprocessingparameters.GeoprocessingString
|
|
14
17
|
import expo.modules.kotlin.AppContext
|
|
15
18
|
import java.time.Instant
|
|
@@ -60,6 +63,28 @@ private fun buildGeoprocessingParameter(d: Map<*, *>): GeoprocessingParameter? =
|
|
|
60
63
|
?.map { Graphic().apply { geometry = it } } ?: emptyList()
|
|
61
64
|
GeoprocessingFeatures(FeatureCollectionTable(graphics, emptyList()))
|
|
62
65
|
}
|
|
66
|
+
"multiValue" -> {
|
|
67
|
+
// JS numbers → GeoprocessingDouble, JS strings → GeoprocessingString.
|
|
68
|
+
val rawValues = d["values"] as? List<*> ?: emptyList<Any>()
|
|
69
|
+
val elements: List<GeoprocessingParameter> = rawValues.mapNotNull { v ->
|
|
70
|
+
when (v) {
|
|
71
|
+
is Number -> GeoprocessingDouble(v.toDouble())
|
|
72
|
+
is String -> GeoprocessingString(v)
|
|
73
|
+
else -> null
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Use the element type of the first item to determine the multiValue's parameterType;
|
|
77
|
+
// fall back to GeoprocessingParameterType.GeoprocessingString when the list is empty.
|
|
78
|
+
val paramType = if (elements.firstOrNull() is GeoprocessingDouble)
|
|
79
|
+
GeoprocessingParameterType.GeoprocessingDouble
|
|
80
|
+
else
|
|
81
|
+
GeoprocessingParameterType.GeoprocessingString
|
|
82
|
+
GeoprocessingMultiValue(paramType, elements)
|
|
83
|
+
}
|
|
84
|
+
"dataFile" -> {
|
|
85
|
+
val url = d["url"] as? String ?: return null
|
|
86
|
+
GeoprocessingDataFile.Companion.createWithUrl(url)
|
|
87
|
+
}
|
|
63
88
|
else -> null
|
|
64
89
|
}
|
|
65
90
|
|