Skip to content

Commit 7033f93

Browse files
committed
feat(google-maps): Implemented map feature functions (i.e. GeoJSON support)
1 parent 81caaaf commit 7033f93

File tree

12 files changed

+843
-5
lines changed

12 files changed

+843
-5
lines changed

README.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,9 @@ Vue({
354354
* [`removeCircles(...)`](#removecircles)
355355
* [`addPolylines(...)`](#addpolylines)
356356
* [`removePolylines(...)`](#removepolylines)
357+
* [`addFeatures(...)`](#addfeatures)
358+
* [`getFeatureBounds(...)`](#getfeaturebounds)
359+
* [`removeFeature(...)`](#removefeature)
357360
* [`destroy()`](#destroy)
358361
* [`setCamera(...)`](#setcamera)
359362
* [`getMapType()`](#getmaptype)
@@ -614,6 +617,52 @@ removePolylines(ids: string[]) => Promise<void>
614617
--------------------
615618

616619

620+
### addFeatures(...)
621+
622+
```typescript
623+
addFeatures(type: FeatureType, data: any, idPropertyName?: string | undefined, styles?: FeatureStyles | undefined) => Promise<string[]>
624+
```
625+
626+
| Param | Type |
627+
| -------------------- | ------------------------------------------------------- |
628+
| **`type`** | <code><a href="#featuretype">FeatureType</a></code> |
629+
| **`data`** | <code>any</code> |
630+
| **`idPropertyName`** | <code>string</code> |
631+
| **`styles`** | <code><a href="#featurestyles">FeatureStyles</a></code> |
632+
633+
**Returns:** <code>Promise&lt;string[]&gt;</code>
634+
635+
--------------------
636+
637+
638+
### getFeatureBounds(...)
639+
640+
```typescript
641+
getFeatureBounds(featureId: string) => Promise<LatLngBounds>
642+
```
643+
644+
| Param | Type |
645+
| --------------- | ------------------- |
646+
| **`featureId`** | <code>string</code> |
647+
648+
**Returns:** <code>Promise&lt;LatLngBounds&gt;</code>
649+
650+
--------------------
651+
652+
653+
### removeFeature(...)
654+
655+
```typescript
656+
removeFeature(featureId: string) => Promise<void>
657+
```
658+
659+
| Param | Type |
660+
| --------------- | ------------------- |
661+
| **`featureId`** | <code>string</code> |
662+
663+
--------------------
664+
665+
617666
### destroy()
618667

619668
```typescript
@@ -1139,6 +1188,11 @@ Describes the style for some region of a polyline.
11391188
| **`segments`** | <code>number</code> | The length of this span in number of segments. |
11401189

11411190

1191+
#### FeatureStyles
1192+
1193+
Feature styles, identified by the feature id
1194+
1195+
11421196
#### CameraConfig
11431197

11441198
Configuration properties for a Google Map Camera
@@ -1277,6 +1331,14 @@ Supports markers of either either "legacy" or "advanced" types.
12771331
### Enums
12781332

12791333

1334+
#### FeatureType
1335+
1336+
| Members | Value | Description |
1337+
| ------------- | ---------------------- | ----------- |
1338+
| **`Default`** | <code>'Default'</code> | Default |
1339+
| **`GeoJSON`** | <code>'GeoJSON'</code> | GeoJSON |
1340+
1341+
12801342
#### MapType
12811343

12821344
| Members | Value | Description |

plugin/README.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,9 @@ Vue({
354354
* [`removeCircles(...)`](#removecircles)
355355
* [`addPolylines(...)`](#addpolylines)
356356
* [`removePolylines(...)`](#removepolylines)
357+
* [`addFeatures(...)`](#addfeatures)
358+
* [`getFeatureBounds(...)`](#getfeaturebounds)
359+
* [`removeFeature(...)`](#removefeature)
357360
* [`destroy()`](#destroy)
358361
* [`setCamera(...)`](#setcamera)
359362
* [`getMapType()`](#getmaptype)
@@ -614,6 +617,52 @@ removePolylines(ids: string[]) => Promise<void>
614617
--------------------
615618

616619

620+
### addFeatures(...)
621+
622+
```typescript
623+
addFeatures(type: FeatureType, data: any, idPropertyName?: string | undefined, styles?: FeatureStyles | undefined) => Promise<string[]>
624+
```
625+
626+
| Param | Type |
627+
| -------------------- | ------------------------------------------------------- |
628+
| **`type`** | <code><a href="#featuretype">FeatureType</a></code> |
629+
| **`data`** | <code>any</code> |
630+
| **`idPropertyName`** | <code>string</code> |
631+
| **`styles`** | <code><a href="#featurestyles">FeatureStyles</a></code> |
632+
633+
**Returns:** <code>Promise&lt;string[]&gt;</code>
634+
635+
--------------------
636+
637+
638+
### getFeatureBounds(...)
639+
640+
```typescript
641+
getFeatureBounds(featureId: string) => Promise<LatLngBounds>
642+
```
643+
644+
| Param | Type |
645+
| --------------- | ------------------- |
646+
| **`featureId`** | <code>string</code> |
647+
648+
**Returns:** <code>Promise&lt;LatLngBounds&gt;</code>
649+
650+
--------------------
651+
652+
653+
### removeFeature(...)
654+
655+
```typescript
656+
removeFeature(featureId: string) => Promise<void>
657+
```
658+
659+
| Param | Type |
660+
| --------------- | ------------------- |
661+
| **`featureId`** | <code>string</code> |
662+
663+
--------------------
664+
665+
617666
### destroy()
618667

619668
```typescript
@@ -1139,6 +1188,11 @@ Describes the style for some region of a polyline.
11391188
| **`segments`** | <code>number</code> | The length of this span in number of segments. |
11401189

11411190

1191+
#### FeatureStyles
1192+
1193+
Feature styles, identified by the feature id
1194+
1195+
11421196
#### CameraConfig
11431197

11441198
Configuration properties for a Google Map Camera
@@ -1277,6 +1331,14 @@ Supports markers of either either "legacy" or "advanced" types.
12771331
### Enums
12781332

12791333

1334+
#### FeatureType
1335+
1336+
| Members | Value | Description |
1337+
| ------------- | ---------------------- | ----------- |
1338+
| **`Default`** | <code>'Default'</code> | Default |
1339+
| **`GeoJSON`** | <code>'GeoJSON'</code> | GeoJSON |
1340+
1341+
12801342
#### MapType
12811343

12821344
| 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 tileOverlays = HashMap<String, CapacitorGoogleMapTileOverlay>()
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

@@ -415,6 +427,78 @@ class CapacitorGoogleMap(
415427
}
416428
}
417429

430+
fun addFeatures(type: String, data: JSONObject, idPropertyName: String?, styles: JSONObject?, callback: (ids: Result<List<String>>) -> Unit) {
431+
try {
432+
googleMap ?: throw GoogleMapNotAvailable()
433+
val featureIds: MutableList<String> = mutableListOf()
434+
435+
CoroutineScope(Dispatchers.Main).launch {
436+
if (type == "GeoJSON") {
437+
val tempLayer = GeoJsonLayer(null, data)
438+
tempLayer.features.forEach {
439+
try {
440+
val layer = GeoJsonLayer(googleMap, JSONObject())
441+
val featureLayer = CapacitorGoogleMapsFeatureLayer(layer, it, idPropertyName, styles)
442+
layer.addLayerToMap()
443+
if (id != null) {
444+
featureIds.add(id)
445+
featureLayers[id] = featureLayer
446+
}
447+
callback(Result.success(featureIds))
448+
} catch (e: Exception) {
449+
callback(Result.failure(e))
450+
}
451+
}
452+
} else {
453+
callback(Result.failure(InvalidArgumentsError("addFeatures: not supported for this feature type")))
454+
}
455+
}
456+
} catch (e: GoogleMapsError) {
457+
callback(Result.failure(e))
458+
}
459+
}
460+
461+
fun getFeatureBounds(featureId: String, callback: (bounds: Result<LatLngBounds?>) -> Unit) {
462+
try {
463+
CoroutineScope(Dispatchers.Main).launch {
464+
val featurelayer = featureLayers[featureId]
465+
var feature: Feature? = null;
466+
featurelayer?.layer?.features?.forEach lit@ {
467+
if (it.id == featurelayer.id) {
468+
feature = it
469+
return@lit
470+
}
471+
}
472+
if (feature != null) {
473+
try {
474+
(feature as GeoJsonFeature).let {
475+
callback(Result.success(it.boundingBoxFromGeometry()))
476+
}
477+
} catch (e: Exception) {
478+
callback(Result.failure(InvalidArgumentsError("getFeatureBounds: not supported for this feature type")))
479+
}
480+
} else {
481+
callback(Result.failure(InvalidArgumentsError("Could not find feature for feature id $featureId")))
482+
}
483+
}
484+
} catch(e: Exception) {
485+
callback(Result.failure(InvalidArgumentsError("Could not find feature layer")))
486+
}
487+
}
488+
489+
fun removeFeature(featureId: String, callback: (error: GoogleMapsError?) -> Unit) {
490+
CoroutineScope(Dispatchers.Main).launch {
491+
val featurelayer = featureLayers[featureId]
492+
if (featurelayer != null) {
493+
featurelayer.layer?.removeLayerFromMap()
494+
featureLayers.remove(featureId)
495+
callback(null)
496+
} else {
497+
callback(InvalidArgumentsError("Could not find feature for feature id $featureId"))
498+
}
499+
}
500+
}
501+
418502
private fun setClusterManagerRenderer(minClusterSize: Int?) {
419503
clusterManager?.renderer = CapacitorClusterManagerRenderer(
420504
delegate.bridge.context,
@@ -1032,6 +1116,52 @@ class CapacitorGoogleMap(
10321116
return data
10331117
}
10341118

1119+
private fun GeoJsonFeature.boundingBoxFromGeometry(): LatLngBounds? {
1120+
val coordinates: MutableList<LatLng> = ArrayList()
1121+
1122+
if (this.hasGeometry()) {
1123+
when (geometry.geometryType) {
1124+
"Point" -> coordinates.add((geometry as GeoJsonPoint).coordinates)
1125+
"MultiPoint" -> {
1126+
val points = (geometry as GeoJsonMultiPoint).points
1127+
for (point in points) {
1128+
coordinates.add(point.coordinates)
1129+
}
1130+
}
1131+
1132+
"LineString" -> coordinates.addAll((geometry as GeoJsonLineString).coordinates)
1133+
"MultiLineString" -> {
1134+
val lines = (geometry as GeoJsonMultiLineString).lineStrings
1135+
for (line in lines) {
1136+
coordinates.addAll(line.coordinates)
1137+
}
1138+
}
1139+
1140+
"Polygon" -> {
1141+
val lists = (geometry as GeoJsonPolygon).coordinates
1142+
for (list in lists) {
1143+
coordinates.addAll(list)
1144+
}
1145+
}
1146+
1147+
"MultiPolygon" -> {
1148+
val polygons = (geometry as GeoJsonMultiPolygon).polygons
1149+
for (polygon in polygons) {
1150+
for (list in polygon.coordinates) {
1151+
coordinates.addAll(list)
1152+
}
1153+
}
1154+
}
1155+
}
1156+
}
1157+
1158+
val builder = LatLngBounds.builder()
1159+
for (latLng in coordinates) {
1160+
builder.include(latLng)
1161+
}
1162+
return builder.build()
1163+
}
1164+
10351165
override fun onMapClick(point: LatLng) {
10361166
val data = JSObject()
10371167
data.put("mapId", this@CapacitorGoogleMap.id)

0 commit comments

Comments
 (0)