expo-arcgis 0.1.9 → 0.2.1
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 +15 -0
- package/android/src/main/java/expo/modules/arcgis/ExpoArcgisGeometryModule.kt +8 -0
- package/android/src/main/java/expo/modules/arcgis/ExpoArcgisMapView.kt +5 -0
- package/android/src/main/java/expo/modules/arcgis/ExpoArcgisModule.kt +9 -0
- package/android/src/main/java/expo/modules/arcgis/ExpoArcgisSceneView.kt +11 -0
- package/android/src/main/java/expo/modules/arcgis/GraphicsOverlayRef.kt +30 -10
- package/android/src/main/java/expo/modules/arcgis/ImageOverlayRef.kt +28 -0
- package/android/src/main/java/expo/modules/arcgis/LayerRef.kt +94 -1
- package/android/src/main/java/expo/modules/arcgis/PortalFunctions.kt +95 -0
- package/build/DynamicEntityLayer.d.ts.map +1 -1
- package/build/ExpoArcgis.types.d.ts +169 -11
- package/build/ExpoArcgis.types.d.ts.map +1 -1
- package/build/ExpoArcgis.types.js.map +1 -1
- package/build/ExpoArcgisExtrasModule.d.ts +3 -1
- package/build/ExpoArcgisExtrasModule.d.ts.map +1 -1
- package/build/ExpoArcgisExtrasModule.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 +19 -2
- package/build/ExpoArcgisModule.d.ts.map +1 -1
- package/build/ExpoArcgisModule.js.map +1 -1
- package/build/ImageOverlay.d.ts +8 -0
- package/build/ImageOverlay.d.ts.map +1 -0
- package/build/ImageOverlay.js +30 -0
- package/build/ImageOverlay.js.map +1 -0
- package/build/MapView.d.ts.map +1 -1
- package/build/MapView.js +4 -1
- package/build/MapView.js.map +1 -1
- package/build/SceneView.d.ts.map +1 -1
- package/build/SceneView.js +3 -0
- package/build/SceneView.js.map +1 -1
- package/build/contexts.d.ts +7 -2
- package/build/contexts.d.ts.map +1 -1
- package/build/contexts.js.map +1 -1
- package/build/createLayerComponent.d.ts +3 -2
- package/build/createLayerComponent.d.ts.map +1 -1
- package/build/createLayerComponent.js +9 -4
- package/build/createLayerComponent.js.map +1 -1
- package/build/index.d.ts +2 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +2 -0
- package/build/index.js.map +1 -1
- package/build/layers.d.ts +63 -20
- package/build/layers.d.ts.map +1 -1
- package/build/layers.js.map +1 -1
- package/build/portal.d.ts +42 -0
- package/build/portal.d.ts.map +1 -0
- package/build/portal.js +42 -0
- package/build/portal.js.map +1 -0
- package/ios/ExpoArcgisExtrasModule.swift +15 -0
- package/ios/ExpoArcgisGeometryModule.swift +8 -0
- package/ios/ExpoArcgisMapView.swift +10 -1
- package/ios/ExpoArcgisModule.swift +9 -0
- package/ios/ExpoArcgisSceneView.swift +6 -0
- package/ios/GraphicsOverlayRef.swift +27 -9
- package/ios/ImageOverlayRef.swift +23 -0
- package/ios/LayerRef.swift +104 -1
- package/ios/PortalFunctions.swift +88 -0
- package/package.json +1 -1
- package/src/ExpoArcgis.types.ts +173 -11
- package/src/ExpoArcgisExtrasModule.ts +8 -1
- package/src/ExpoArcgisGeometryModule.ts +8 -0
- package/src/ExpoArcgisModule.ts +28 -1
- package/src/ImageOverlay.tsx +36 -0
- package/src/MapView.tsx +14 -1
- package/src/SceneView.tsx +3 -0
- package/src/contexts.ts +11 -1
- package/src/createLayerComponent.tsx +13 -5
- package/src/index.ts +2 -0
- package/src/layers.tsx +2 -1
- package/src/portal.ts +46 -0
|
@@ -44,6 +44,12 @@ class ExpoArcgisExtrasModule : Module() {
|
|
|
44
44
|
AsyncFunction("addFeatureWithTemplate") Coroutine { ref: FeatureLayerRef, templateName: String, attributes: Map<String, Any?>?, geometry: Map<String, Any?>?, apply: Boolean? ->
|
|
45
45
|
ref.addFeatureWithTemplate(templateName, attributes, geometry, apply)
|
|
46
46
|
}
|
|
47
|
+
AsyncFunction("addFeatureWithSubtype") Coroutine { ref: FeatureLayerRef, subtypeName: String, attributes: Map<String, Any?>?, geometry: Map<String, Any?>?, apply: Boolean? ->
|
|
48
|
+
ref.addFeatureWithSubtype(subtypeName, attributes, geometry, apply)
|
|
49
|
+
}
|
|
50
|
+
AsyncFunction("getContingentValues") Coroutine { ref: FeatureLayerRef, objectId: Long, fieldName: String ->
|
|
51
|
+
ref.getContingentValues(objectId, fieldName)
|
|
52
|
+
}
|
|
47
53
|
AsyncFunction("updateFeature") Coroutine { ref: FeatureLayerRef, objectId: Long, changes: Map<String, Any?>, apply: Boolean? ->
|
|
48
54
|
ref.updateFeature(objectId, changes, apply)
|
|
49
55
|
}
|
|
@@ -180,5 +186,14 @@ class ExpoArcgisExtrasModule : Module() {
|
|
|
180
186
|
ref.validateNetworkTopology(extent)
|
|
181
187
|
}
|
|
182
188
|
}
|
|
189
|
+
|
|
190
|
+
// Georeferenced image overlay (added to a <MapView> via <ImageOverlay>).
|
|
191
|
+
Class(ImageOverlayRef::class) {
|
|
192
|
+
Constructor { ImageOverlayRef(appContext) }
|
|
193
|
+
Function("setFrame") { ref: ImageOverlayRef, imagePath: String, extent: Map<String, Any?>, opacity: Double? ->
|
|
194
|
+
ref.setFrame(imagePath, extent, opacity)
|
|
195
|
+
}
|
|
196
|
+
Function("setOpacity") { ref: ImageOverlayRef, opacity: Double -> ref.setOpacity(opacity) }
|
|
197
|
+
}
|
|
183
198
|
}
|
|
184
199
|
}
|
|
@@ -181,6 +181,14 @@ class ExpoArcgisGeometryModule : Module() {
|
|
|
181
181
|
ArcGISEnvironment.authenticationManager.arcGISCredentialStore.removeAll()
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
+
// Portal — search a Portal and fetch basemaps, exposed as the JS `portal` namespace.
|
|
185
|
+
AsyncFunction("portalFindItems") Coroutine { params: Map<String, Any?> ->
|
|
186
|
+
portalFindItems(params)
|
|
187
|
+
}
|
|
188
|
+
AsyncFunction("portalFetchBasemaps") Coroutine { params: Map<String, Any?> ->
|
|
189
|
+
portalFetchBasemaps(params)
|
|
190
|
+
}
|
|
191
|
+
|
|
184
192
|
// Offline — take maps/data offline, exposed as the JS `offline` namespace.
|
|
185
193
|
AsyncFunction("generateOfflineMap") Coroutine { portalItemId: String, areaOfInterest: Map<String, Any?>, downloadName: String, overrides: Map<String, Any?>? ->
|
|
186
194
|
generateOfflineMap(appContext, appContext.reactContext?.filesDir, portalItemId, areaOfInterest, downloadName, overrides)
|
|
@@ -131,6 +131,11 @@ class ExpoArcgisMapView(context: Context, appContext: AppContext) : ExpoView(con
|
|
|
131
131
|
mapView.graphicsOverlays.addAll(refs.map { it.overlay })
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
fun setImageOverlays(refs: List<ImageOverlayRef>) {
|
|
135
|
+
mapView.imageOverlays.clear()
|
|
136
|
+
mapView.imageOverlays.addAll(refs.map { it.overlay })
|
|
137
|
+
}
|
|
138
|
+
|
|
134
139
|
/** Animates the view to a runtime viewpoint sent from JS. */
|
|
135
140
|
fun setViewpoint(vp: Map<String, Any?>?) {
|
|
136
141
|
vp ?: return
|
|
@@ -224,6 +224,7 @@ class ExpoArcgisModule : Module() {
|
|
|
224
224
|
Function("applyProps") { ref: KmlLayerRef, changed: Map<String, Any?> ->
|
|
225
225
|
ref.applyProps(changed)
|
|
226
226
|
}
|
|
227
|
+
AsyncFunction("getNodes") Coroutine { ref: KmlLayerRef -> ref.getNodes() }
|
|
227
228
|
}
|
|
228
229
|
|
|
229
230
|
// WFS (Web Feature Service) + OGC API - Features — feature layers over async-populating tables.
|
|
@@ -364,6 +365,10 @@ class ExpoArcgisModule : Module() {
|
|
|
364
365
|
view.setGraphicsOverlays(refs)
|
|
365
366
|
}
|
|
366
367
|
|
|
368
|
+
Prop("imageOverlays") { view: ExpoArcgisMapView, refs: List<ImageOverlayRef> ->
|
|
369
|
+
view.setImageOverlays(refs)
|
|
370
|
+
}
|
|
371
|
+
|
|
367
372
|
Prop("viewpoint") { view: ExpoArcgisMapView, vp: Map<String, Any?>? ->
|
|
368
373
|
view.setViewpoint(vp)
|
|
369
374
|
}
|
|
@@ -450,6 +455,10 @@ class ExpoArcgisModule : Module() {
|
|
|
450
455
|
view.retryLoad(promise)
|
|
451
456
|
}
|
|
452
457
|
|
|
458
|
+
AsyncFunction("getElevation") { view: ExpoArcgisSceneView, point: Map<String, Any?>, promise: Promise ->
|
|
459
|
+
view.getElevation(point, promise)
|
|
460
|
+
}
|
|
461
|
+
|
|
453
462
|
AsyncFunction("identify") { view: ExpoArcgisSceneView, screenPoint: Map<String, Any?>, options: Map<String, Any?>?, promise: Promise ->
|
|
454
463
|
view.identify(screenPoint, options, promise)
|
|
455
464
|
}
|
|
@@ -132,6 +132,17 @@ class ExpoArcgisSceneView(context: Context, appContext: AppContext) : ExpoView(c
|
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
+
/** Returns the terrain elevation (meters) at a point on the scene's base surface, or null. */
|
|
136
|
+
fun getElevation(point: Map<String, Any?>, promise: Promise) {
|
|
137
|
+
val scene = sceneView.scene ?: run { promise.resolve(null); return }
|
|
138
|
+
val p = geometryFromDict(point) as? Point ?: run { promise.resolve(null); return }
|
|
139
|
+
scope.launch {
|
|
140
|
+
scene.baseSurface.getElevation(p)
|
|
141
|
+
.onSuccess { promise.resolve(it) }
|
|
142
|
+
.onFailure { e -> promise.reject("ELEVATION_ERROR", e.message ?: "Elevation query failed", e) }
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
135
146
|
/** Animates the view to a runtime camera sent from JS. */
|
|
136
147
|
fun setCamera(c: Map<String, Any?>?) {
|
|
137
148
|
val position = c?.get("position") as? Map<*, *> ?: return
|
|
@@ -22,6 +22,7 @@ import com.arcgismaps.mapping.symbology.SimpleMarkerSceneSymbol
|
|
|
22
22
|
import com.arcgismaps.mapping.symbology.SimpleMarkerSceneSymbolStyle
|
|
23
23
|
import com.arcgismaps.mapping.symbology.MultilayerPointSymbol
|
|
24
24
|
import com.arcgismaps.mapping.symbology.MultilayerPolygonSymbol
|
|
25
|
+
import com.arcgismaps.mapping.symbology.MultilayerPolylineSymbol
|
|
25
26
|
import com.arcgismaps.mapping.symbology.PictureFillSymbol
|
|
26
27
|
import com.arcgismaps.mapping.symbology.PictureMarkerSymbol
|
|
27
28
|
import com.arcgismaps.mapping.symbology.PictureMarkerSymbolLayer
|
|
@@ -397,20 +398,39 @@ private fun buildSymbol(s: Map<*, *>): Symbol? = when (s["type"]) {
|
|
|
397
398
|
}
|
|
398
399
|
}
|
|
399
400
|
"vector-marker" -> {
|
|
400
|
-
// DEFER: polyline / multipoint element geometries are not yet supported — only polygon.
|
|
401
401
|
val geomMap = ldMap["geometry"] as? Map<*, *> ?: return@mapNotNull null
|
|
402
|
-
if (geomMap["type"] != "polygon") return@mapNotNull null
|
|
403
402
|
val geom = geometryFromDict(geomMap) ?: return@mapNotNull null
|
|
404
|
-
val
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
403
|
+
val elementSymbol = when (geomMap["type"]) {
|
|
404
|
+
"polygon" -> {
|
|
405
|
+
val fillColor = colorOf(ldMap["fillColor"]) ?: Color.fromRgba(255, 0, 0, 255)
|
|
406
|
+
val elementLayers = buildList {
|
|
407
|
+
add(SolidFillSymbolLayer(fillColor))
|
|
408
|
+
colorOf(ldMap["outlineColor"])?.let { outlineColor ->
|
|
409
|
+
val outlineWidth = (ldMap["outlineWidth"] as? Number)?.toDouble() ?: 1.0
|
|
410
|
+
add(SolidStrokeSymbolLayer(outlineWidth, outlineColor))
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
MultilayerPolygonSymbol(elementLayers)
|
|
410
414
|
}
|
|
415
|
+
"polyline" -> {
|
|
416
|
+
val strokeColor = colorOf(ldMap["fillColor"]) ?: colorOf(ldMap["outlineColor"]) ?: Color.fromRgba(255, 0, 0, 255)
|
|
417
|
+
val strokeWidth = (ldMap["outlineWidth"] as? Number)?.toDouble() ?: 1.0
|
|
418
|
+
MultilayerPolylineSymbol(listOf(SolidStrokeSymbolLayer(strokeWidth, strokeColor)))
|
|
419
|
+
}
|
|
420
|
+
"multipoint" -> {
|
|
421
|
+
val fillColor = colorOf(ldMap["fillColor"]) ?: Color.fromRgba(255, 0, 0, 255)
|
|
422
|
+
val elementLayers = buildList {
|
|
423
|
+
add(SolidFillSymbolLayer(fillColor))
|
|
424
|
+
colorOf(ldMap["outlineColor"])?.let { outlineColor ->
|
|
425
|
+
val outlineWidth = (ldMap["outlineWidth"] as? Number)?.toDouble() ?: 1.0
|
|
426
|
+
add(SolidStrokeSymbolLayer(outlineWidth, outlineColor))
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
MultilayerPointSymbol(elementLayers)
|
|
430
|
+
}
|
|
431
|
+
else -> return@mapNotNull null // unsupported geometry type — skip gracefully
|
|
411
432
|
}
|
|
412
|
-
val
|
|
413
|
-
val element = VectorMarkerSymbolElement(geom, fillSymbol)
|
|
433
|
+
val element = VectorMarkerSymbolElement(geom, elementSymbol)
|
|
414
434
|
VectorMarkerSymbolLayer(listOf(element)).apply {
|
|
415
435
|
(ldMap["size"] as? Number)?.toDouble()?.let { size = it }
|
|
416
436
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
package expo.modules.arcgis
|
|
2
|
+
|
|
3
|
+
import com.arcgismaps.geometry.Envelope
|
|
4
|
+
import com.arcgismaps.mapping.view.ImageFrame
|
|
5
|
+
import com.arcgismaps.mapping.view.ImageOverlay
|
|
6
|
+
import expo.modules.kotlin.AppContext
|
|
7
|
+
import expo.modules.kotlin.sharedobjects.SharedObject
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* An [ImageOverlay] that displays a single georeferenced image frame — a local image file shown at a
|
|
11
|
+
* map extent, with adjustable opacity. Added to a `<MapView>` via the `<ImageOverlay>` component.
|
|
12
|
+
*/
|
|
13
|
+
class ImageOverlayRef(appContext: AppContext) : SharedObject(appContext) {
|
|
14
|
+
val overlay = ImageOverlay()
|
|
15
|
+
|
|
16
|
+
/** Sets the displayed frame from a local image file path and its geographic extent (clears on null). */
|
|
17
|
+
fun setFrame(imagePath: String, extent: Map<String, Any?>, opacity: Double?) {
|
|
18
|
+
val envelope = geometryFromDict(extent + ("type" to "envelope")) as? Envelope
|
|
19
|
+
if (envelope == null) {
|
|
20
|
+
overlay.imageFrame = null
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
overlay.imageFrame = ImageFrame(imagePath, envelope)
|
|
24
|
+
opacity?.let { overlay.opacity = it.toFloat() }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
fun setOpacity(opacity: Double) { overlay.opacity = opacity.toFloat() }
|
|
28
|
+
}
|
|
@@ -3,6 +3,9 @@ package expo.modules.arcgis
|
|
|
3
3
|
import android.util.Base64
|
|
4
4
|
import com.arcgismaps.data.ArcGISFeature
|
|
5
5
|
import com.arcgismaps.data.ArcGISFeatureTable
|
|
6
|
+
import com.arcgismaps.data.ContingentCodedValue
|
|
7
|
+
import com.arcgismaps.data.ContingentRangeValue
|
|
8
|
+
import com.arcgismaps.data.ContingentValue
|
|
6
9
|
import com.arcgismaps.data.Feature
|
|
7
10
|
import com.arcgismaps.data.FeatureCollection
|
|
8
11
|
import com.arcgismaps.data.FeatureCollectionTable
|
|
@@ -51,7 +54,9 @@ import com.arcgismaps.mapping.layers.WebTiledLayer
|
|
|
51
54
|
import com.arcgismaps.mapping.layers.KmlLayer
|
|
52
55
|
import com.arcgismaps.mapping.layers.WmsLayer
|
|
53
56
|
import com.arcgismaps.mapping.layers.WmtsLayer
|
|
57
|
+
import com.arcgismaps.mapping.kml.KmlContainer
|
|
54
58
|
import com.arcgismaps.mapping.kml.KmlDataset
|
|
59
|
+
import com.arcgismaps.mapping.kml.KmlNode
|
|
55
60
|
import com.arcgismaps.mapping.view.Graphic
|
|
56
61
|
import com.arcgismaps.raster.ImageServiceRaster
|
|
57
62
|
import com.arcgismaps.raster.Raster
|
|
@@ -136,6 +141,26 @@ class FeatureLayerRef(appContext: AppContext, private val table: FeatureTable) :
|
|
|
136
141
|
return persistEdits()
|
|
137
142
|
}
|
|
138
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Adds a feature created from the named subtype (sets the subtype field and inherits its
|
|
146
|
+
* default attribute values), then optionally applies [attributes] on top and sets [geometry].
|
|
147
|
+
* When [apply] is not `false`, pushes the edit and returns the new object id; pass
|
|
148
|
+
* `apply = false` for a local-only edit.
|
|
149
|
+
*/
|
|
150
|
+
suspend fun addFeatureWithSubtype(subtypeName: String, attributes: Map<String, Any?>?, geometry: Map<String, Any?>?, apply: Boolean?): Long? {
|
|
151
|
+
table.load().getOrThrow()
|
|
152
|
+
val arcGISTable = table as? ArcGISFeatureTable
|
|
153
|
+
?: throw IllegalStateException("addFeatureWithSubtype requires an ArcGIS feature table (not a shapefile or WFS table)")
|
|
154
|
+
val subtype = arcGISTable.featureSubtypes.firstOrNull { it.name == subtypeName }
|
|
155
|
+
?: throw IllegalArgumentException("No feature subtype named '$subtypeName' found in the table")
|
|
156
|
+
val geom = geometry?.let { geometryFromDict(it) }
|
|
157
|
+
val feature = arcGISTable.createFeature(subtype, geom)
|
|
158
|
+
if (attributes != null) applyAttributes(feature, attributes)
|
|
159
|
+
table.addFeature(feature).getOrThrow()
|
|
160
|
+
if (apply == false) return null
|
|
161
|
+
return persistEdits()
|
|
162
|
+
}
|
|
163
|
+
|
|
139
164
|
/**
|
|
140
165
|
* Adds a feature. When `apply` is not `false`, pushes the edit and returns the new object id;
|
|
141
166
|
* pass `apply = false` to make a local-only edit (batch with `applyEdits`).
|
|
@@ -265,6 +290,54 @@ class FeatureLayerRef(appContext: AppContext, private val table: FeatureTable) :
|
|
|
265
290
|
persistEdits()
|
|
266
291
|
}
|
|
267
292
|
|
|
293
|
+
/**
|
|
294
|
+
* Returns the valid contingent values for [fieldName] on the feature with [objectId].
|
|
295
|
+
* Requires the table to be an [ArcGISFeatureTable]; throws otherwise. Returns an empty list when
|
|
296
|
+
* the feature is not found or the table has no contingent-values result for that field.
|
|
297
|
+
* Result shape: `{ fieldName, contingentValues: [{ type, ... }] }` where each entry is either
|
|
298
|
+
* `{ type: "coded", fieldGroupName, codedValue: { name, code } }` or
|
|
299
|
+
* `{ type: "range", fieldGroupName, min, max }`.
|
|
300
|
+
* Exotic subtypes are serialized as `{ type: "any" }` / `{ type: "null" }`.
|
|
301
|
+
*/
|
|
302
|
+
suspend fun getContingentValues(objectId: Long, fieldName: String): Map<String, Any?> {
|
|
303
|
+
table.load().getOrThrow()
|
|
304
|
+
val arcGISTable = table as? ArcGISFeatureTable
|
|
305
|
+
?: throw IllegalStateException("getContingentValues requires an ArcGIS feature table (not a shapefile or WFS table)")
|
|
306
|
+
val feature = featureByObjectId(objectId) as? ArcGISFeature
|
|
307
|
+
?: throw IllegalArgumentException("Feature not found for objectId $objectId")
|
|
308
|
+
val result = arcGISTable.getContingentValuesOrNull(feature, fieldName)
|
|
309
|
+
?: return mapOf("fieldName" to fieldName, "contingentValues" to emptyList<Map<String, Any?>>())
|
|
310
|
+
val serialized = result.byFieldGroup.flatMap { (groupName, values) ->
|
|
311
|
+
values.map { cv -> serializeContingentValue(cv, groupName) }
|
|
312
|
+
}
|
|
313
|
+
return mapOf("fieldName" to fieldName, "contingentValues" to serialized)
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
private fun serializeContingentValue(cv: ContingentValue, groupName: String): Map<String, Any?> {
|
|
317
|
+
val dict = mutableMapOf<String, Any?>("fieldGroupName" to groupName)
|
|
318
|
+
when (cv) {
|
|
319
|
+
is ContingentCodedValue -> {
|
|
320
|
+
dict["type"] = "coded"
|
|
321
|
+
val coded = cv.codedValue
|
|
322
|
+
dict["codedValue"] = mapOf("name" to coded.name, "code" to coded.code)
|
|
323
|
+
}
|
|
324
|
+
is ContingentRangeValue -> {
|
|
325
|
+
dict["type"] = "range"
|
|
326
|
+
dict["min"] = cv.minValue
|
|
327
|
+
dict["max"] = cv.maxValue
|
|
328
|
+
}
|
|
329
|
+
else -> {
|
|
330
|
+
// ContingentNullValue, ContingentAnyValue, or unknown future subtype
|
|
331
|
+
val typeName = cv::class.simpleName ?: ""
|
|
332
|
+
dict["type"] = when {
|
|
333
|
+
typeName.contains("Null", ignoreCase = true) -> "null"
|
|
334
|
+
else -> "any"
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return dict
|
|
339
|
+
}
|
|
340
|
+
|
|
268
341
|
private suspend fun featureByObjectId(objectId: Long): Feature? {
|
|
269
342
|
val params = QueryParameters().apply { objectIds.add(objectId) }
|
|
270
343
|
return table.queryFeatures(params).getOrThrow().firstOrNull()
|
|
@@ -477,9 +550,29 @@ private fun rasterFromSource(s: Map<String, Any?>): Raster =
|
|
|
477
550
|
|
|
478
551
|
/** Operational KML layer from a remote .kml/.kmz URL or local file. */
|
|
479
552
|
class KmlLayerRef(appContext: AppContext, url: String) : LayerRef(appContext) {
|
|
480
|
-
|
|
553
|
+
private val dataset = KmlDataset(url)
|
|
554
|
+
override val layer: KmlLayer = KmlLayer(dataset)
|
|
481
555
|
|
|
482
556
|
override fun applyProps(changed: Map<String, Any?>) = applyCommonProps(changed)
|
|
557
|
+
|
|
558
|
+
/** Loads the KML and returns its node tree (recursing into container nodes like documents / folders). */
|
|
559
|
+
suspend fun getNodes(): List<Map<String, Any?>> {
|
|
560
|
+
dataset.load().getOrThrow()
|
|
561
|
+
return dataset.rootNodes.map { serializeKmlNode(it) }
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/** Serializes a KML node, recursing into container nodes (documents / folders). */
|
|
566
|
+
private fun serializeKmlNode(node: KmlNode): Map<String, Any?> {
|
|
567
|
+
val dict = mutableMapOf<String, Any?>(
|
|
568
|
+
"name" to node.name,
|
|
569
|
+
"visible" to node.isVisible,
|
|
570
|
+
"type" to (node::class.simpleName ?: "KmlNode"),
|
|
571
|
+
)
|
|
572
|
+
if (node is KmlContainer) {
|
|
573
|
+
dict["children"] = node.childNodes.map { serializeKmlNode(it) }
|
|
574
|
+
}
|
|
575
|
+
return dict
|
|
483
576
|
}
|
|
484
577
|
|
|
485
578
|
/** Operational WFS layer — a [FeatureLayer] over a [WfsFeatureTable] (Web Feature Service). */
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
package expo.modules.arcgis
|
|
2
|
+
|
|
3
|
+
import com.arcgismaps.mapping.Basemap
|
|
4
|
+
import com.arcgismaps.mapping.PortalItem
|
|
5
|
+
import com.arcgismaps.portal.Portal
|
|
6
|
+
import com.arcgismaps.portal.PortalQueryParameters
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Free functions backing the JS `portal` namespace — search a Portal and fetch its basemaps.
|
|
10
|
+
* Registered as `AsyncFunction`s in `ExpoArcgisGeometryModule`.
|
|
11
|
+
*
|
|
12
|
+
* Both functions run anonymously (no auth). Authenticated portals would need a credential
|
|
13
|
+
* already present in `ArcGISEnvironment.authenticationManager.arcGISCredentialStore`
|
|
14
|
+
* (e.g. set via `setServiceCredential` / the auth namespace). That is out of scope here.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Serialises a [PortalItem] to the wire map `{ id, title, type, snippet, owner, thumbnailUrl }`.
|
|
19
|
+
*
|
|
20
|
+
* Kotlin SDK notes:
|
|
21
|
+
* - `PortalItem.itemId: String` — the item's portal id
|
|
22
|
+
* - `PortalItem.title: String` — inherited from `Item`
|
|
23
|
+
* - `PortalItem.typeName: String` — human-readable type string (e.g. `"Web Map"`)
|
|
24
|
+
* - `PortalItem.snippet: String` — inherited from `Item`
|
|
25
|
+
* - `PortalItem.owner: String`
|
|
26
|
+
* - `PortalItem.thumbnail: LoadableImage?` — has `getUri(): String?` (relative or absolute URL)
|
|
27
|
+
*
|
|
28
|
+
* Thumbnail handling: `LoadableImage.uri` may be a relative path (e.g.
|
|
29
|
+
* `"thumbnail/thumbnail.png"`) or an absolute URL. We build the canonical ArcGIS REST
|
|
30
|
+
* thumbnail URL from the portal URL + item id so callers always get an absolute URL.
|
|
31
|
+
* We do NOT load the image here — that would require an extra async fetch per item;
|
|
32
|
+
* callers that need the bitmap should load the URL themselves.
|
|
33
|
+
*/
|
|
34
|
+
private fun portalItemToMap(item: PortalItem): Map<String, Any?> {
|
|
35
|
+
val portalUrl = item.portal.url.trimEnd('/')
|
|
36
|
+
val thumbnailUrl = if (item.itemId.isNotEmpty()) {
|
|
37
|
+
"$portalUrl/sharing/rest/content/items/${item.itemId}/info/thumbnail"
|
|
38
|
+
} else {
|
|
39
|
+
null
|
|
40
|
+
}
|
|
41
|
+
return mapOf(
|
|
42
|
+
"id" to item.itemId,
|
|
43
|
+
"title" to item.title,
|
|
44
|
+
"type" to item.typeName,
|
|
45
|
+
"snippet" to item.snippet,
|
|
46
|
+
"owner" to item.owner,
|
|
47
|
+
"thumbnailUrl" to thumbnailUrl,
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Searches the portal at [portalUrl] (default ArcGIS Online) with the given [query] string,
|
|
53
|
+
* returning up to [max] results (default 10).
|
|
54
|
+
*
|
|
55
|
+
* Kotlin SDK signatures used:
|
|
56
|
+
* - `Portal(url: String, connection: Portal.Connection)` — `Portal.Connection.Anonymous`
|
|
57
|
+
* - `portal.load(): Result<Unit>` — must be called before queries
|
|
58
|
+
* - `portal.findItems(PortalQueryParameters): Result<PortalQueryResultSet<PortalItem>>`
|
|
59
|
+
* - `PortalQueryParameters(query: String, boundingBox: Envelope?, limit: Int)`
|
|
60
|
+
* where the primary ctor is `(String, Envelope?, Int)` and `limit` defaults to 10.
|
|
61
|
+
*/
|
|
62
|
+
internal suspend fun portalFindItems(params: Map<String, Any?>): List<Map<String, Any?>> {
|
|
63
|
+
val urlString = params["portalUrl"] as? String ?: "https://www.arcgis.com"
|
|
64
|
+
val query = params["query"] as? String ?: ""
|
|
65
|
+
val max = (params["max"] as? Number)?.toInt() ?: 10
|
|
66
|
+
|
|
67
|
+
val portal = Portal(urlString, Portal.Connection.Anonymous)
|
|
68
|
+
portal.load().getOrThrow()
|
|
69
|
+
|
|
70
|
+
val queryParams = PortalQueryParameters(query, null, max)
|
|
71
|
+
val resultSet = portal.findItems(queryParams).getOrThrow()
|
|
72
|
+
return resultSet.results.map { portalItemToMap(it) }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Fetches the organisation basemaps from the portal at [portalUrl] (default ArcGIS Online).
|
|
77
|
+
* Returns `[{ name, itemId }]`.
|
|
78
|
+
*
|
|
79
|
+
* Kotlin SDK signatures used:
|
|
80
|
+
* - `portal.fetchBasemaps(): Result<List<Basemap>>`
|
|
81
|
+
* - `Basemap.name: String`
|
|
82
|
+
* - `Basemap.item: Item?` — cast to `PortalItem` to get the item id
|
|
83
|
+
*/
|
|
84
|
+
internal suspend fun portalFetchBasemaps(params: Map<String, Any?>): List<Map<String, Any?>> {
|
|
85
|
+
val urlString = params["portalUrl"] as? String ?: "https://www.arcgis.com"
|
|
86
|
+
|
|
87
|
+
val portal = Portal(urlString, Portal.Connection.Anonymous)
|
|
88
|
+
portal.load().getOrThrow()
|
|
89
|
+
|
|
90
|
+
val basemaps: List<Basemap> = portal.fetchBasemaps().getOrThrow()
|
|
91
|
+
return basemaps.map { basemap ->
|
|
92
|
+
val itemId = (basemap.item as? PortalItem)?.itemId
|
|
93
|
+
mapOf("name" to basemap.name, "itemId" to itemId)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -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;AAO5B;;;;;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;AAO5B;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB;;;;;mBAwDw7qC,CAAC;gBAAkB,CAAC;;;;;;;4DAD1+qC,CAAC"}
|
|
@@ -466,6 +466,11 @@ export type SceneViewHandle = {
|
|
|
466
466
|
}): Promise<PopupResult[]>;
|
|
467
467
|
/** Retries loading the scene after a failure (e.g. a network outage). Re-fires `onSceneLoaded`/`onSceneLoadError`. */
|
|
468
468
|
retryLoad(): Promise<void>;
|
|
469
|
+
/**
|
|
470
|
+
* The terrain elevation (in meters) on the scene's base surface at a geographic point, or `null`
|
|
471
|
+
* if no surface/elevation is available there.
|
|
472
|
+
*/
|
|
473
|
+
getElevation(point: Point): Promise<number | null>;
|
|
469
474
|
};
|
|
470
475
|
/** Imperative query handle exposed by `<FeatureLayer>` via `ref`. */
|
|
471
476
|
/** An editing template published with a feature table. Mirrors `FeatureTemplate`. */
|
|
@@ -500,6 +505,46 @@ export type AttachmentInfo = {
|
|
|
500
505
|
/** Size in bytes. */
|
|
501
506
|
size: number;
|
|
502
507
|
};
|
|
508
|
+
/**
|
|
509
|
+
* One valid contingent value entry, discriminated by `type`:
|
|
510
|
+
* - `"coded"` — a specific coded-value domain entry is valid; `codedValue.code` is the domain code.
|
|
511
|
+
* - `"range"` — any numeric value in `[min, max]` is valid.
|
|
512
|
+
* - `"null"` — a null / empty value is explicitly allowed for this field.
|
|
513
|
+
* - `"any"` — any value is allowed (corresponds to `ContingentAnyValue`).
|
|
514
|
+
*
|
|
515
|
+
* `fieldGroupName` identifies which contingent-values field group this constraint belongs to,
|
|
516
|
+
* allowing callers to match constraints to the group they were defined under.
|
|
517
|
+
*/
|
|
518
|
+
export type ContingentValueEntry = {
|
|
519
|
+
type: 'coded';
|
|
520
|
+
fieldGroupName: string;
|
|
521
|
+
codedValue: {
|
|
522
|
+
name: string;
|
|
523
|
+
code: unknown;
|
|
524
|
+
};
|
|
525
|
+
} | {
|
|
526
|
+
type: 'range';
|
|
527
|
+
fieldGroupName: string;
|
|
528
|
+
min: unknown;
|
|
529
|
+
max: unknown;
|
|
530
|
+
} | {
|
|
531
|
+
type: 'null';
|
|
532
|
+
fieldGroupName: string;
|
|
533
|
+
} | {
|
|
534
|
+
type: 'any';
|
|
535
|
+
fieldGroupName: string;
|
|
536
|
+
};
|
|
537
|
+
/**
|
|
538
|
+
* Result of `FeatureLayerHandle.getContingentValues` — the field name that was queried plus
|
|
539
|
+
* all valid contingent values for that field given the feature's current attribute state.
|
|
540
|
+
* An empty `contingentValues` array means no constraints are defined (all values are valid).
|
|
541
|
+
*/
|
|
542
|
+
export type ContingentValuesResult = {
|
|
543
|
+
/** The field name that was queried. */
|
|
544
|
+
fieldName: string;
|
|
545
|
+
/** The valid contingent values, organised across all field groups that reference this field. */
|
|
546
|
+
contingentValues: ContingentValueEntry[];
|
|
547
|
+
};
|
|
503
548
|
export type FeatureLayerHandle = {
|
|
504
549
|
/** Returns the features matching `query` (all features when omitted). */
|
|
505
550
|
queryFeatures(query?: QueryParameters): Promise<Feature[]>;
|
|
@@ -535,6 +580,24 @@ export type FeatureLayerHandle = {
|
|
|
535
580
|
* ```
|
|
536
581
|
*/
|
|
537
582
|
addFeatureWithTemplate(templateName: string, attributes?: Record<string, unknown>, geometry?: Geometry, apply?: boolean): Promise<number | null>;
|
|
583
|
+
/**
|
|
584
|
+
* Creates a feature from the named feature subtype (sets the subtype field and inherits the
|
|
585
|
+
* subtype's default attribute values), then optionally overrides `attributes` on top and sets
|
|
586
|
+
* `geometry`. By default pushes the edit to the service and resolves to the new object id;
|
|
587
|
+
* pass `apply: false` to make a local-only edit. Rejects if no subtype with that name exists.
|
|
588
|
+
* Requires an ArcGIS feature table (service or mobile geodatabase) — rejects for shapefiles
|
|
589
|
+
* and WFS tables, which do not expose feature subtypes.
|
|
590
|
+
*
|
|
591
|
+
* @example
|
|
592
|
+
* ```ts
|
|
593
|
+
* const id = await layer.current.addFeatureWithSubtype(
|
|
594
|
+
* 'Arterial',
|
|
595
|
+
* { ROADNAME: 'Main St' },
|
|
596
|
+
* { type: 'point', x: -117.19, y: 34.05 }
|
|
597
|
+
* );
|
|
598
|
+
* ```
|
|
599
|
+
*/
|
|
600
|
+
addFeatureWithSubtype(subtypeName: string, attributes?: Record<string, unknown>, geometry?: Geometry, apply?: boolean): Promise<number | null>;
|
|
538
601
|
/** Updates the feature with `objectId`. Pass `apply: false` for a local-only edit. */
|
|
539
602
|
updateFeature(objectId: number, changes: {
|
|
540
603
|
attributes?: Record<string, unknown>;
|
|
@@ -577,6 +640,22 @@ export type FeatureLayerHandle = {
|
|
|
577
640
|
* feature layer. The same handle is returned on repeat calls.
|
|
578
641
|
*/
|
|
579
642
|
getServiceGeodatabase(): Promise<ServiceGeodatabaseHandle>;
|
|
643
|
+
/**
|
|
644
|
+
* Returns the valid contingent values for `fieldName` on the feature with `objectId`, given
|
|
645
|
+
* the feature's current attribute state. Contingent values constrain which attribute values
|
|
646
|
+
* are valid based on the values of other fields (e.g. "species" options depend on "habitat").
|
|
647
|
+
*
|
|
648
|
+
* Requires an ArcGIS feature table (service or mobile geodatabase) — rejects for shapefiles
|
|
649
|
+
* and WFS tables. Resolves with an empty `contingentValues` list when no constraints apply.
|
|
650
|
+
*
|
|
651
|
+
* @example
|
|
652
|
+
* ```ts
|
|
653
|
+
* const result = await layer.current.getContingentValues(42, 'species');
|
|
654
|
+
* // result.contingentValues[0] → { type: 'coded', fieldGroupName: 'HabitatGroup',
|
|
655
|
+
* // codedValue: { name: 'Oak', code: 1 } }
|
|
656
|
+
* ```
|
|
657
|
+
*/
|
|
658
|
+
getContingentValues(objectId: number, fieldName: string): Promise<ContingentValuesResult>;
|
|
580
659
|
};
|
|
581
660
|
/** Branch-version access level. */
|
|
582
661
|
export type VersionAccess = 'public' | 'protected' | 'private';
|
|
@@ -955,6 +1034,31 @@ export type Envelope = {
|
|
|
955
1034
|
/** Coordinate system WKID. Defaults to `4326` (WGS84). */
|
|
956
1035
|
spatialReference?: SpatialReference;
|
|
957
1036
|
};
|
|
1037
|
+
/** Props for the `<ImageOverlay>` component — a georeferenced image displayed on a `<MapView>`. */
|
|
1038
|
+
export type ImageOverlayProps = {
|
|
1039
|
+
/** Local image file path to display (e.g. a downloaded or bundled PNG/JPEG). */
|
|
1040
|
+
imagePath: string;
|
|
1041
|
+
/** The geographic extent (envelope) the image is stretched to fill. */
|
|
1042
|
+
extent: Envelope;
|
|
1043
|
+
/** Overlay opacity, 0–1. Defaults to `1`. */
|
|
1044
|
+
opacity?: number;
|
|
1045
|
+
};
|
|
1046
|
+
/** A node in a KML document tree, returned by `KmlLayerHandle.getNodes()`. */
|
|
1047
|
+
export type KmlNodeInfo = {
|
|
1048
|
+
/** Node display name. */
|
|
1049
|
+
name: string;
|
|
1050
|
+
/** Whether the node is currently visible. */
|
|
1051
|
+
visible: boolean;
|
|
1052
|
+
/** Node class name (e.g. `KMLDocument` / `KMLFolder` / `KMLPlacemark` / `KMLNetworkLink` / `KMLTour`). */
|
|
1053
|
+
type: string;
|
|
1054
|
+
/** Child nodes, present for container nodes (documents / folders). */
|
|
1055
|
+
children?: KmlNodeInfo[];
|
|
1056
|
+
};
|
|
1057
|
+
/** Imperative handle exposed by `<KmlLayer>` via `ref`. */
|
|
1058
|
+
export type KmlLayerHandle = {
|
|
1059
|
+
/** Loads the KML and returns its node tree (recursing into container nodes). */
|
|
1060
|
+
getNodes(): Promise<KmlNodeInfo[]>;
|
|
1061
|
+
};
|
|
958
1062
|
/**
|
|
959
1063
|
* A geometry value. The `type` discriminator mirrors the ArcGIS web API
|
|
960
1064
|
* (`"point"` / `"multipoint"` / `"polyline"` / `"polygon"` / `"envelope"`) and
|
|
@@ -1507,6 +1611,55 @@ export type UtilityNetworkHandle = {
|
|
|
1507
1611
|
/** Returns the associations of a feature queried from `tableName`. */
|
|
1508
1612
|
associations(tableName: string, whereClause: string): Promise<UtilityAssociationSummary>;
|
|
1509
1613
|
};
|
|
1614
|
+
/** Parameters for `portal.findItems`. */
|
|
1615
|
+
export type PortalQuery = {
|
|
1616
|
+
/**
|
|
1617
|
+
* ArcGIS portal search query string (e.g. `'type:"Web Map" owner:esri'`).
|
|
1618
|
+
* Forwarded directly to `PortalQueryParameters(query:limit:)` on both platforms.
|
|
1619
|
+
*/
|
|
1620
|
+
query: string;
|
|
1621
|
+
/** Maximum number of items to return (default 10). */
|
|
1622
|
+
max?: number;
|
|
1623
|
+
/** Portal URL (default `https://www.arcgis.com`). */
|
|
1624
|
+
portalUrl?: string;
|
|
1625
|
+
};
|
|
1626
|
+
/** One portal item returned by `portal.findItems`. */
|
|
1627
|
+
export type PortalItemInfo = {
|
|
1628
|
+
/** Portal item id (pass to `<Map portalItem={{ itemId }}>` to display the web map). */
|
|
1629
|
+
id: string;
|
|
1630
|
+
/** Human-readable title. */
|
|
1631
|
+
title: string;
|
|
1632
|
+
/**
|
|
1633
|
+
* Human-readable type string (e.g. `"Web Map"`, `"Feature Service"`).
|
|
1634
|
+
* Maps to `PortalItem.typeName` on both platforms.
|
|
1635
|
+
*/
|
|
1636
|
+
type: string;
|
|
1637
|
+
/** Short description / abstract. */
|
|
1638
|
+
snippet: string;
|
|
1639
|
+
/** Portal username of the item owner. */
|
|
1640
|
+
owner: string;
|
|
1641
|
+
/**
|
|
1642
|
+
* Absolute HTTPS URL of the item's thumbnail, or `null` when none is available.
|
|
1643
|
+
* Constructed as `<portalUrl>/sharing/rest/content/items/<id>/info/thumbnail`.
|
|
1644
|
+
* Load it in an `<Image>` component; no auth is required for public items.
|
|
1645
|
+
*/
|
|
1646
|
+
thumbnailUrl: string | null;
|
|
1647
|
+
};
|
|
1648
|
+
/** Parameters for `portal.fetchBasemaps`. */
|
|
1649
|
+
export type BasemapQuery = {
|
|
1650
|
+
/** Portal URL (default `https://www.arcgis.com`). */
|
|
1651
|
+
portalUrl?: string;
|
|
1652
|
+
};
|
|
1653
|
+
/** One basemap returned by `portal.fetchBasemaps`. */
|
|
1654
|
+
export type BasemapInfo = {
|
|
1655
|
+
/** Human-readable basemap name (e.g. `"World Topographic Map"`). */
|
|
1656
|
+
name: string;
|
|
1657
|
+
/**
|
|
1658
|
+
* Portal item id of the underlying basemap item, or `null` when the basemap has no item.
|
|
1659
|
+
* Pass to `<Map portalItem={{ itemId }}>` to use it as the map's basemap.
|
|
1660
|
+
*/
|
|
1661
|
+
itemId: string | null;
|
|
1662
|
+
};
|
|
1510
1663
|
/** Result of an offline-map download. `path` is the local mobile map package directory. */
|
|
1511
1664
|
export type OfflineMapResult = {
|
|
1512
1665
|
/** Local filesystem path of the downloaded mobile map package (pass to `<Map mobileMapPackagePath>`). */
|
|
@@ -1753,17 +1906,21 @@ export type PictureMarkerSymbolLayerSpec = {
|
|
|
1753
1906
|
/**
|
|
1754
1907
|
* One vector-marker symbol layer within a `MultilayerPointSymbolType`.
|
|
1755
1908
|
* Mirrors the native `VectorMarkerSymbolLayer` (a shape drawn from a geometry with fill/stroke,
|
|
1756
|
-
* requiring no image).
|
|
1757
|
-
* `polyline` (for a stroked shape); polygon is the common case for icons.
|
|
1909
|
+
* requiring no image).
|
|
1758
1910
|
*
|
|
1759
|
-
*
|
|
1760
|
-
*
|
|
1911
|
+
* Supported `geometry` types and how they are symbolised:
|
|
1912
|
+
* - `polygon` — `MultilayerPolygonSymbol([SolidFillSymbolLayer, SolidStrokeSymbolLayer?])`;
|
|
1913
|
+
* `fillColor` is the fill, `outlineColor`/`outlineWidth` add an optional stroke.
|
|
1914
|
+
* - `polyline` — `MultilayerPolylineSymbol([SolidStrokeSymbolLayer])`; `fillColor` is used as the
|
|
1915
|
+
* stroke color (falls back to `outlineColor`, then red), `outlineWidth` sets the stroke width.
|
|
1916
|
+
* - `multipoint` — `MultilayerPointSymbol([SolidFillSymbolLayer, SolidStrokeSymbolLayer?])`;
|
|
1917
|
+
* same color/width props as `polygon`.
|
|
1761
1918
|
*
|
|
1762
|
-
*
|
|
1763
|
-
*
|
|
1764
|
-
*
|
|
1919
|
+
* Any other `geometry` type is silently skipped (the layer is omitted from the symbol).
|
|
1920
|
+
* Geometries use a local coordinate space (not geographic) — use small integer-scale coordinates
|
|
1921
|
+
* (e.g. `x` / `y` in the range `[-1, 1]`).
|
|
1765
1922
|
*
|
|
1766
|
-
* @example
|
|
1923
|
+
* @example — filled triangle (polygon)
|
|
1767
1924
|
* ```ts
|
|
1768
1925
|
* { type: 'multilayer-point', symbolLayers: [
|
|
1769
1926
|
* { type: 'vector-marker', size: 24,
|
|
@@ -1777,9 +1934,10 @@ export type PictureMarkerSymbolLayerSpec = {
|
|
|
1777
1934
|
export type VectorMarkerSymbolLayerSpec = {
|
|
1778
1935
|
type: 'vector-marker';
|
|
1779
1936
|
/**
|
|
1780
|
-
* The geometry that defines the marker shape.
|
|
1781
|
-
* types are
|
|
1782
|
-
*
|
|
1937
|
+
* The geometry that defines the marker shape. Supported types: `polygon`, `polyline`,
|
|
1938
|
+
* `multipoint`. Unsupported types are silently skipped. The geometry is defined in a local
|
|
1939
|
+
* coordinate space (not geographic) — use small integer-scale coordinates
|
|
1940
|
+
* (e.g. `x` / `y` in the range `[-1, 1]`).
|
|
1783
1941
|
*/
|
|
1784
1942
|
geometry: Geometry;
|
|
1785
1943
|
/** Overall size of the marker, in points. Scales the geometry uniformly. Defaults to 12. */
|