Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Polyline Feature for android #220

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ android {
lintOptions {
abortOnError false
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

repositories {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -585,4 +585,49 @@ public void run() {
}
});
}

@PluginMethod()
public void addPolyline(final PluginCall call) {
final String mapId = call.getString("mapId");

getBridge().getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
CustomMapView customMapView = customMapViews.get(mapId);

if (customMapView != null) {
CustomPolyline customPolyline = new CustomPolyline();
customPolyline.updateFromJSObject(call.getData());

customMapView.addPolyline(customPolyline, (polyline) -> {
call.resolve(customPolyline.getResultForPolyline(polyline, mapId));
});
} else {
call.reject("map not found");
}
}
});
}

@PluginMethod(returnType = PluginMethod.RETURN_NONE)
public void removePolyline(final PluginCall call) {
final String mapId = call.getString("mapId");

getBridge().getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
CustomMapView customMapView = customMapViews.get(mapId);

if (customMapView != null) {
final String polylineId = call.getString("polylineId");

customMapView.removePolyline(polylineId);

call.resolve();
} else {
call.reject("map not found");
}
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.google.android.libraries.maps.model.Marker;
import com.google.android.libraries.maps.model.PointOfInterest;
import com.google.android.libraries.maps.model.Polygon;
import com.google.android.libraries.maps.model.Polyline;

import java.util.HashMap;
import java.util.Map;
Expand Down Expand Up @@ -56,6 +57,7 @@ public class CustomMapView

private HashMap<String, Marker> markers = new HashMap<>();
private HashMap<String, Polygon> polygons = new HashMap<>();
private HashMap<String, Polyline> polylines = new HashMap<>();

String savedCallbackIdForCreate;

Expand Down Expand Up @@ -495,6 +497,29 @@ public void removePolygon(String polygonId) {
}
}

public void addPolyline(CustomPolyline customPolyline, @Nullable Consumer<Polyline> consumer) {
customPolyline.addToMap(
googleMap,
(polyline) -> {
polylines.put(customPolyline.polylineId, polyline);

if (consumer != null) {
consumer.accept(polyline);
}
}
);
}

public void removePolyline(String polylineId) {
Polyline polyline = polylines.get(polylineId);

if (polyline != null) {
polyline.remove();
polylines.remove(polylineId);
}
}



private JSObject getResultForMap() {
if (this.mapView != null && this.googleMap != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package com.hemangkumar.capacitorgooglemaps;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Consumer;

import com.getcapacitor.JSArray;
import com.getcapacitor.JSObject;
import com.getcapacitor.util.WebColor;
import com.google.android.libraries.maps.GoogleMap;
import com.google.android.libraries.maps.model.LatLng;
import com.google.android.libraries.maps.model.Polyline;
import com.google.android.libraries.maps.model.PolylineOptions;

import org.json.JSONArray;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;

public class CustomPolyline {
// generate id for the just added polyline,
// put this polyline into a hashmap with the corresponding id,
// so we can retrieve the polyline by id later on
public final String polylineId = UUID.randomUUID().toString();

private final PolylineOptions polylineOptions = new PolylineOptions();
protected JSObject tag = new JSObject();

public void updateFromJSObject(JSObject polyline) {
this.setPath(polyline.optJSONArray("path"));

final JSObject preferences = JSObjectDefaults.getJSObjectSafe(polyline, "preferences", new JSObject());

this.setBasicFields(preferences);
this.setMetadata(JSObjectDefaults.getJSObjectSafe(preferences, "metadata", new JSObject()));
}

public void addToMap(GoogleMap googleMap, @Nullable Consumer<Polyline> consumer) {
final Polyline polyline = googleMap.addPolyline(polylineOptions);
polyline.setTag(tag);

if (consumer != null) {
consumer.accept(polyline);
}
}

private void setPath(@Nullable JSONArray path) {
if (path != null) {
List<LatLng> latLngList = getLatLngList(path);
this.polylineOptions.addAll(latLngList);
}
}

private static List<LatLng> getLatLngList(@NonNull JSONArray latLngArray) {
List<LatLng> latLngList = new ArrayList<>();

for (int n = 0; n < latLngArray.length(); n++) {
JSONObject latLngObject = latLngArray.optJSONObject(n);
if (latLngObject != null) {
LatLng latLng = getLatLng(latLngObject);
latLngList.add(latLng);
}
}

return latLngList;
}

private static LatLng getLatLng(@NonNull JSONObject latLngObject) {
double latitude = latLngObject.optDouble("latitude", 0d);
double longitude = latLngObject.optDouble("longitude", 0d);
return new LatLng(latitude, longitude);
}

private void setBasicFields(@NonNull JSObject preferences) {
final float width = (float) preferences.optDouble("width", 10);
final int color = WebColor.parseColor(preferences.optString("color", "#000000"));
final float zIndex = (float) preferences.optDouble("zIndex", 0);
final boolean isVisible = preferences.optBoolean("isVisible", true);
final boolean isGeodesic = preferences.optBoolean("isGeodesic", false);
final boolean isClickable = preferences.optBoolean("isClickable", false);

polylineOptions.color(color);
polylineOptions.width(width);
polylineOptions.zIndex(zIndex);
polylineOptions.visible(isVisible);
polylineOptions.geodesic(isGeodesic);
polylineOptions.clickable(isClickable);
}

private void setMetadata(@NonNull JSObject jsObject) {
JSObject tag = new JSObject();
tag.put("id", this.polylineId);
tag.put("metadata", jsObject);
this.tag = tag;
}

public JSObject getResultForPolyline(Polyline polyline, String mapId) {
JSObject tag = null;

try {
tag = (JSObject) polyline.getTag();
} catch (Exception e) {
e.printStackTrace();
} finally {
tag = tag != null ? tag : new JSObject();
}

// initialize JSObjects to return
JSObject result = new JSObject();
JSObject polylineResult = new JSObject();
JSObject preferencesResult = new JSObject();

result.put("polyline", polylineResult);
polylineResult.put("preferences", preferencesResult);

// get map id
polylineResult.put("mapId", mapId);

// get id
String polylineId = tag.optString("polylineId", polyline.getId());
polylineResult.put("polylineId", polylineId);

// get path values
JSArray path = latLngsToJSArray(polyline.getPoints());
polylineResult.put("path", path);

// get preferences
preferencesResult.put("width", polyline.getWidth());
preferencesResult.put("color", colorToString(polyline.getColor()));
preferencesResult.put("zIndex", polyline.getZIndex());
preferencesResult.put("isVisible", polyline.isVisible());
preferencesResult.put("isGeodesic", polyline.isGeodesic());
preferencesResult.put("isClickable", polyline.isClickable());

JSObject metadata = JSObjectDefaults.getJSObjectSafe(tag, "metadata", new JSObject());
preferencesResult.put("metadata", metadata);

return result;
}

private static JSArray latLngsToJSArray(Collection<LatLng> positions) {
JSArray jsPositions = new JSArray();
for (LatLng pos : positions) {
JSObject jsPos = latLngToJSObject(pos);
jsPositions.put(jsPos);
}
return jsPositions;
}

private static JSObject latLngToJSObject(LatLng latLng) {
JSObject jsPos = new JSObject();
jsPos.put("latitude", latLng.latitude);
jsPos.put("longitude", latLng.longitude);
return jsPos;
}

private static String colorToString(int color) {
int r = ((color >> 16) & 0xff);
int g = ((color >> 8) & 0xff);
int b = ((color) & 0xff);
int a = ((color >> 24) & 0xff);
if (a != 255) {
return String.format("#%02X%02X%02X%02X", a, r, g, b);
} else {
return String.format("#%02X%02X%02X", r, g, b);
}
}

}
83 changes: 83 additions & 0 deletions ios/Plugin/CustomPolyline.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import Foundation
import GoogleMaps
import Capacitor

class CustomPolyline : GMSPolyline {
var id: String! = NSUUID().uuidString.lowercased();

public func updateFromJSObject(_ polylineData: JSObject) {
let pathArray = polylineData["path"] as? [JSObject] ?? [JSObject]()
let path = CustomPolyline.pathFromJson(pathArray)
self.path = path

let preferences = polylineData["preferences"] as? JSObject ?? JSObject()

self.strokeWidth = preferences["width"] as? Double ?? 10.0

if let color = preferences["color"] as? String {
self.strokeColor = UIColor.capacitor.color(fromHex: color) ?? UIColor.black
}

self.title = preferences["title"] as? String ?? ""
self.zIndex = Int32.init(preferences["zIndex"] as? Int ?? 1)
self.geodesic = preferences["isGeodesic"] as? Bool ?? false
self.isTappable = preferences["isClickable"] as? Bool ?? false

let metadata: JSObject = preferences["metadata"] as? JSObject ?? JSObject()
self.userData = [
"polylineId": self.id!,
"metadata": metadata
] as? JSObject ?? JSObject()
}

public static func getResultForPolyline(_ polyline: GMSPolyline, mapId: String) -> PluginCallResultData {
let tag: JSObject = polyline.userData as! JSObject

return [
"polyline": [
"mapId": mapId,
"polylineId": tag["polylineId"] ?? "",
"path": CustomPolyline.jsonFromPath(polyline.path),
"preferences": [
"title": polyline.title ?? "",
"width": polyline.strokeWidth,
"color": polyline.strokeColor ?? "",
"zIndex": polyline.zIndex,
"isGeodesic": polyline.geodesic,
"isClickable": polyline.isTappable,
"metadata": tag["metadata"] ?? JSObject()
]
]
];
}


private static func jsonFromPath(_ path: GMSPath?) -> [JSObject] {
guard let path = path else {
return [JSObject]()
}
let size = path.count()
var result: [JSObject] = []
for i in stride(from: 0, to: size, by: 1) {
let coord = path.coordinate(at: i)
result.append(CustomPolyline.jsonFromCoord(coord))
}
return result
}

private static func jsonFromCoord(_ coord: CLLocationCoordinate2D) -> JSObject {
return ["latitude" : coord.latitude, "longitude": coord.longitude]
}

private static func pathFromJson(_ latLngArray: [JSObject]) -> GMSPath {
let path = GMSMutablePath()
latLngArray.forEach { point in
if let lat = point["latitude"] as? Double, let long = point["longitude"] as? Double {
let coord = CLLocationCoordinate2D(latitude: lat, longitude: long)
path.add(coord)
}
}

return path as GMSPath
}
}
2 changes: 2 additions & 0 deletions ios/Plugin/Plugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
CAP_PLUGIN_METHOD(removeMarker, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(addPolygon, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(removePolygon, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(addPolyline, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(removePolyline, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(didTapInfoWindow, CAPPluginReturnCallback);
CAP_PLUGIN_METHOD(didCloseInfoWindow, CAPPluginReturnCallback);
CAP_PLUGIN_METHOD(didTapMap, CAPPluginReturnCallback);
Expand Down
Loading