Skip to content

Commit fcdd490

Browse files
committed
feat(google-maps): Implemented map feature functions (i.e. GeoJSON support)
1 parent ac36a4f commit fcdd490

File tree

13 files changed

+867
-5
lines changed

13 files changed

+867
-5
lines changed

README.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,9 @@ export default MyMap;
310310
* [`removeCircles(...)`](#removecircles)
311311
* [`addPolylines(...)`](#addpolylines)
312312
* [`removePolylines(...)`](#removepolylines)
313+
* [`addFeatures(...)`](#addfeatures)
314+
* [`getFeatureBounds(...)`](#getfeaturebounds)
315+
* [`removeFeature(...)`](#removefeature)
313316
* [`destroy()`](#destroy)
314317
* [`setCamera(...)`](#setcamera)
315318
* [`getMapType()`](#getmaptype)
@@ -319,6 +322,7 @@ export default MyMap;
319322
* [`enableAccessibilityElements(...)`](#enableaccessibilityelements)
320323
* [`enableCurrentLocation(...)`](#enablecurrentlocation)
321324
* [`setPadding(...)`](#setpadding)
325+
* [`getMapBounds()`](#getmapbounds)
322326
* [`fitBounds(...)`](#fitbounds)
323327
* [`setOnBoundsChangedListener(...)`](#setonboundschangedlistener)
324328
* [`setOnCameraIdleListener(...)`](#setoncameraidlelistener)
@@ -541,6 +545,52 @@ removePolylines(ids: string[]) => Promise<void>
541545
--------------------
542546

543547

548+
### addFeatures(...)
549+
550+
```typescript
551+
addFeatures(type: FeatureType, data: any, idPropertyName?: string | undefined, styles?: FeatureStyles | undefined) => Promise<string[]>
552+
```
553+
554+
| Param | Type |
555+
| -------------------- | ------------------------------------------------------- |
556+
| **`type`** | <code><a href="#featuretype">FeatureType</a></code> |
557+
| **`data`** | <code>any</code> |
558+
| **`idPropertyName`** | <code>string</code> |
559+
| **`styles`** | <code><a href="#featurestyles">FeatureStyles</a></code> |
560+
561+
**Returns:** <code>Promise&lt;string[]&gt;</code>
562+
563+
--------------------
564+
565+
566+
### getFeatureBounds(...)
567+
568+
```typescript
569+
getFeatureBounds(featureId: string) => Promise<LatLngBounds>
570+
```
571+
572+
| Param | Type |
573+
| --------------- | ------------------- |
574+
| **`featureId`** | <code>string</code> |
575+
576+
**Returns:** <code>Promise&lt;LatLngBounds&gt;</code>
577+
578+
--------------------
579+
580+
581+
### removeFeature(...)
582+
583+
```typescript
584+
removeFeature(featureId: string) => Promise<void>
585+
```
586+
587+
| Param | Type |
588+
| --------------- | ------------------- |
589+
| **`featureId`** | <code>string</code> |
590+
591+
--------------------
592+
593+
544594
### destroy()
545595

546596
```typescript
@@ -654,6 +704,19 @@ setPadding(padding: MapPadding) => Promise<void>
654704
--------------------
655705

656706

707+
### getMapBounds()
708+
709+
```typescript
710+
getMapBounds() => Promise<LatLngBounds>
711+
```
712+
713+
Get the map's current viewport latitude and longitude bounds.
714+
715+
**Returns:** <code>Promise&lt;LatLngBounds&gt;</code>
716+
717+
--------------------
718+
719+
657720
### fitBounds(...)
658721

659722
```typescript
@@ -1030,6 +1093,11 @@ Describes the style for some region of a polyline.
10301093
| **`segments`** | <code>number</code> | The length of this span in number of segments. |
10311094

10321095

1096+
#### FeatureStyles
1097+
1098+
Feature styles, identified by the feature id
1099+
1100+
10331101
#### CameraConfig
10341102

10351103
Configuration properties for a Google Map Camera
@@ -1169,9 +1237,24 @@ but the current specification only allows X, Y, and (optionally) Z to be defined
11691237
<code>number[]</code>
11701238

11711239

1240+
#### Marker
1241+
1242+
Supports markers of either either "legacy" or "advanced" types.
1243+
1244+
<code>google.maps.<a href="#marker">Marker</a> | google.maps.marker.AdvancedMarkerElement</code>
1245+
1246+
11721247
### Enums
11731248

11741249

1250+
#### FeatureType
1251+
1252+
| Members | Value | Description |
1253+
| ------------- | ---------------------- | ----------- |
1254+
| **`Default`** | <code>'Default'</code> | Default |
1255+
| **`GeoJSON`** | <code>'GeoJSON'</code> | GeoJSON |
1256+
1257+
11751258
#### MapType
11761259

11771260
| Members | Value | Description |

plugin/README.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,9 @@ export default MyMap;
310310
* [`removeCircles(...)`](#removecircles)
311311
* [`addPolylines(...)`](#addpolylines)
312312
* [`removePolylines(...)`](#removepolylines)
313+
* [`addFeatures(...)`](#addfeatures)
314+
* [`getFeatureBounds(...)`](#getfeaturebounds)
315+
* [`removeFeature(...)`](#removefeature)
313316
* [`destroy()`](#destroy)
314317
* [`setCamera(...)`](#setcamera)
315318
* [`getMapType()`](#getmaptype)
@@ -542,6 +545,52 @@ removePolylines(ids: string[]) => Promise<void>
542545
--------------------
543546

544547

548+
### addFeatures(...)
549+
550+
```typescript
551+
addFeatures(type: FeatureType, data: any, idPropertyName?: string | undefined, styles?: FeatureStyles | undefined) => Promise<string[]>
552+
```
553+
554+
| Param | Type |
555+
| -------------------- | ------------------------------------------------------- |
556+
| **`type`** | <code><a href="#featuretype">FeatureType</a></code> |
557+
| **`data`** | <code>any</code> |
558+
| **`idPropertyName`** | <code>string</code> |
559+
| **`styles`** | <code><a href="#featurestyles">FeatureStyles</a></code> |
560+
561+
**Returns:** <code>Promise&lt;string[]&gt;</code>
562+
563+
--------------------
564+
565+
566+
### getFeatureBounds(...)
567+
568+
```typescript
569+
getFeatureBounds(featureId: string) => Promise<LatLngBounds>
570+
```
571+
572+
| Param | Type |
573+
| --------------- | ------------------- |
574+
| **`featureId`** | <code>string</code> |
575+
576+
**Returns:** <code>Promise&lt;LatLngBounds&gt;</code>
577+
578+
--------------------
579+
580+
581+
### removeFeature(...)
582+
583+
```typescript
584+
removeFeature(featureId: string) => Promise<void>
585+
```
586+
587+
| Param | Type |
588+
| --------------- | ------------------- |
589+
| **`featureId`** | <code>string</code> |
590+
591+
--------------------
592+
593+
545594
### destroy()
546595

547596
```typescript
@@ -1044,6 +1093,11 @@ Describes the style for some region of a polyline.
10441093
| **`segments`** | <code>number</code> | The length of this span in number of segments. |
10451094

10461095

1096+
#### FeatureStyles
1097+
1098+
Feature styles, identified by the feature id
1099+
1100+
10471101
#### CameraConfig
10481102

10491103
Configuration properties for a Google Map Camera
@@ -1193,6 +1247,14 @@ Supports markers of either either "legacy" or "advanced" types.
11931247
### Enums
11941248

11951249

1250+
#### FeatureType
1251+
1252+
| Members | Value | Description |
1253+
| ------------- | ---------------------- | ----------- |
1254+
| **`Default`** | <code>'Default'</code> | Default |
1255+
| **`GeoJSON`** | <code>'GeoJSON'</code> | GeoJSON |
1256+
1257+
11961258
#### MapType
11971259

11981260
| Members | Value | Description |

plugin/android/src/main/java/com/capacitorjs/plugins/googlemaps/CapacitorGoogleMap.kt

Lines changed: 131 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,19 @@ import com.google.android.gms.maps.GoogleMap.*
1616
import com.google.android.gms.maps.model.*
1717
import com.google.maps.android.clustering.Cluster
1818
import com.google.maps.android.clustering.ClusterManager
19+
import com.google.maps.android.data.Feature
20+
import com.google.maps.android.data.geojson.GeoJsonFeature
21+
import com.google.maps.android.data.geojson.GeoJsonGeometryCollection
22+
import com.google.maps.android.data.geojson.GeoJsonLayer
23+
import com.google.maps.android.data.geojson.GeoJsonLineString
24+
import com.google.maps.android.data.geojson.GeoJsonMultiLineString
25+
import com.google.maps.android.data.geojson.GeoJsonMultiPoint
26+
import com.google.maps.android.data.geojson.GeoJsonMultiPolygon
27+
import com.google.maps.android.data.geojson.GeoJsonPoint
28+
import com.google.maps.android.data.geojson.GeoJsonPolygon
1929
import kotlinx.coroutines.*
2030
import kotlinx.coroutines.channels.Channel
31+
import org.json.JSONObject
2132
import java.io.InputStream
2233
import java.net.URL
2334

@@ -45,7 +56,8 @@ class CapacitorGoogleMap(
4556
private val markers = HashMap<String, CapacitorGoogleMapMarker>()
4657
private val polygons = HashMap<String, CapacitorGoogleMapsPolygon>()
4758
private val circles = HashMap<String, CapacitorGoogleMapsCircle>()
48-
private val polylines = HashMap<String, CapacitorGoogleMapPolyline>()
59+
private val polylines = HashMap<String, CapacitorGoogleMapPolyline>()
60+
private val featureLayers = HashMap<String, CapacitorGoogleMapsFeatureLayer>()
4961
private val markerIcons = HashMap<String, Bitmap>()
5062
private var clusterManager: ClusterManager<CapacitorGoogleMapMarker>? = null
5163

@@ -324,6 +336,78 @@ class CapacitorGoogleMap(
324336
}
325337
}
326338

339+
fun addFeatures(type: String, data: JSONObject, idPropertyName: String?, styles: JSONObject?, callback: (ids: Result<List<String>>) -> Unit) {
340+
try {
341+
googleMap ?: throw GoogleMapNotAvailable()
342+
val featureIds: MutableList<String> = mutableListOf()
343+
344+
CoroutineScope(Dispatchers.Main).launch {
345+
if (type == "GeoJSON") {
346+
val tempLayer = GeoJsonLayer(null, data)
347+
tempLayer.features.forEach {
348+
try {
349+
val layer = GeoJsonLayer(googleMap, JSONObject())
350+
val featureLayer = CapacitorGoogleMapsFeatureLayer(layer, it, idPropertyName, styles)
351+
layer.addLayerToMap()
352+
if (id != null) {
353+
featureIds.add(id)
354+
featureLayers[id] = featureLayer
355+
}
356+
callback(Result.success(featureIds))
357+
} catch (e: Exception) {
358+
callback(Result.failure(e))
359+
}
360+
}
361+
} else {
362+
callback(Result.failure(InvalidArgumentsError("addFeatures: not supported for this feature type")))
363+
}
364+
}
365+
} catch (e: GoogleMapsError) {
366+
callback(Result.failure(e))
367+
}
368+
}
369+
370+
fun getFeatureBounds(featureId: String, callback: (bounds: Result<LatLngBounds?>) -> Unit) {
371+
try {
372+
CoroutineScope(Dispatchers.Main).launch {
373+
val featurelayer = featureLayers[featureId]
374+
var feature: Feature? = null;
375+
featurelayer?.layer?.features?.forEach lit@ {
376+
if (it.id == featurelayer.id) {
377+
feature = it
378+
return@lit
379+
}
380+
}
381+
if (feature != null) {
382+
try {
383+
(feature as GeoJsonFeature).let {
384+
callback(Result.success(it.boundingBoxFromGeometry()))
385+
}
386+
} catch (e: Exception) {
387+
callback(Result.failure(InvalidArgumentsError("getFeatureBounds: not supported for this feature type")))
388+
}
389+
} else {
390+
callback(Result.failure(InvalidArgumentsError("Could not find feature for feature id $featureId")))
391+
}
392+
}
393+
} catch(e: Exception) {
394+
callback(Result.failure(InvalidArgumentsError("Could not find feature layer")))
395+
}
396+
}
397+
398+
fun removeFeature(featureId: String, callback: (error: GoogleMapsError?) -> Unit) {
399+
CoroutineScope(Dispatchers.Main).launch {
400+
val featurelayer = featureLayers[featureId]
401+
if (featurelayer != null) {
402+
featurelayer.layer?.removeLayerFromMap()
403+
featureLayers.remove(featureId)
404+
callback(null)
405+
} else {
406+
callback(InvalidArgumentsError("Could not find feature for feature id $featureId"))
407+
}
408+
}
409+
}
410+
327411
private fun setClusterManagerRenderer(minClusterSize: Int?) {
328412
clusterManager?.renderer = CapacitorClusterManagerRenderer(
329413
delegate.bridge.context,
@@ -941,6 +1025,52 @@ class CapacitorGoogleMap(
9411025
return data
9421026
}
9431027

1028+
private fun GeoJsonFeature.boundingBoxFromGeometry(): LatLngBounds? {
1029+
val coordinates: MutableList<LatLng> = ArrayList()
1030+
1031+
if (this.hasGeometry()) {
1032+
when (geometry.geometryType) {
1033+
"Point" -> coordinates.add((geometry as GeoJsonPoint).coordinates)
1034+
"MultiPoint" -> {
1035+
val points = (geometry as GeoJsonMultiPoint).points
1036+
for (point in points) {
1037+
coordinates.add(point.coordinates)
1038+
}
1039+
}
1040+
1041+
"LineString" -> coordinates.addAll((geometry as GeoJsonLineString).coordinates)
1042+
"MultiLineString" -> {
1043+
val lines = (geometry as GeoJsonMultiLineString).lineStrings
1044+
for (line in lines) {
1045+
coordinates.addAll(line.coordinates)
1046+
}
1047+
}
1048+
1049+
"Polygon" -> {
1050+
val lists = (geometry as GeoJsonPolygon).coordinates
1051+
for (list in lists) {
1052+
coordinates.addAll(list)
1053+
}
1054+
}
1055+
1056+
"MultiPolygon" -> {
1057+
val polygons = (geometry as GeoJsonMultiPolygon).polygons
1058+
for (polygon in polygons) {
1059+
for (list in polygon.coordinates) {
1060+
coordinates.addAll(list)
1061+
}
1062+
}
1063+
}
1064+
}
1065+
}
1066+
1067+
val builder = LatLngBounds.builder()
1068+
for (latLng in coordinates) {
1069+
builder.include(latLng)
1070+
}
1071+
return builder.build()
1072+
}
1073+
9441074
override fun onMapClick(point: LatLng) {
9451075
val data = JSObject()
9461076
data.put("mapId", this@CapacitorGoogleMap.id)

0 commit comments

Comments
 (0)