diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..f6b961fd5 Binary files /dev/null and b/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/android/src/main/java/com/mapbox/mapboxgl/Convert.java b/android/src/main/java/com/mapbox/mapboxgl/Convert.java index 96eff5033..a99425cef 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/Convert.java +++ b/android/src/main/java/com/mapbox/mapboxgl/Convert.java @@ -6,8 +6,6 @@ import android.graphics.Point; -import android.util.Log; - import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdate; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; @@ -15,7 +13,6 @@ import com.mapbox.mapboxsdk.geometry.LatLngBounds; import com.mapbox.mapboxsdk.log.Logger; import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.geojson.LineString; import java.util.ArrayList; import java.util.Arrays; diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java index 5d1304ae1..8d236ab31 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java +++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java @@ -10,9 +10,14 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.res.AssetFileDescriptor; +import android.content.res.AssetManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.PointF; import android.graphics.RectF; import android.os.Bundle; +import android.util.DisplayMetrics; import androidx.annotation.NonNull; import android.util.Log; import android.view.View; @@ -47,11 +52,9 @@ import io.flutter.plugin.common.PluginRegistry; import io.flutter.plugin.platform.PlatformView; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.io.IOException; +import java.io.InputStream; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import static com.mapbox.mapboxgl.MapboxMapsPlugin.CREATED; @@ -265,6 +268,15 @@ public void onMapReady(MapboxMap mapboxMap) { mapboxMap.addOnCameraMoveStartedListener(this); mapboxMap.addOnCameraMoveListener(this); mapboxMap.addOnCameraIdleListener(this); + + mapView.addOnStyleImageMissingListener((id) -> { + DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); + final Bitmap bitmap = getScaledImage(id, displayMetrics.density); + if (bitmap != null) { + mapboxMap.getStyle().addImage(id, bitmap); + } + }); + setStyleString(styleStringInitial); // updateMyLocationEnabled(); } @@ -741,4 +753,60 @@ private int checkSelfPermission(String permission) { permission, android.os.Process.myPid(), android.os.Process.myUid()); } + /** + * Tries to find highest scale image for display type + * @param imageId + * @param density + * @return + */ + private Bitmap getScaledImage(String imageId, float density) { + AssetManager assetManager = registrar.context().getAssets(); + AssetFileDescriptor assetFileDescriptor = null; + + // Split image path into parts. + List imagePathList = Arrays.asList(imageId.split("/")); + List assetPathList = new ArrayList<>(); + + // "On devices with a device pixel ratio of 1.8, the asset .../2.0x/my_icon.png would be chosen. + // For a device pixel ratio of 2.7, the asset .../3.0x/my_icon.png would be chosen." + // Source: https://flutter.dev/docs/development/ui/assets-and-images#resolution-aware + for (int i = (int) Math.ceil(density); i > 0; i--) { + String assetPath; + if (i == 1) { + // If density is 1.0x then simply take the default asset path + assetPath = registrar.lookupKeyForAsset(imageId); + } else { + // Build a resolution aware asset path as follows: + // // + // where ratio is 1.0x, 2.0x or 3.0x. + StringBuilder stringBuilder = new StringBuilder(); + for (int j = 0; j < imagePathList.size() - 1; j++) { + stringBuilder.append(imagePathList.get(j)); + stringBuilder.append("/"); + } + stringBuilder.append(((float) i) + "x"); + stringBuilder.append("/"); + stringBuilder.append(imagePathList.get(imagePathList.size()-1)); + assetPath = registrar.lookupKeyForAsset(stringBuilder.toString()); + } + // Build up a list of resolution aware asset paths. + assetPathList.add(assetPath); + } + + // Iterate over asset paths and get the highest scaled asset (as a bitmap). + Bitmap bitmap = null; + for (String assetPath : assetPathList) { + try { + // Read path (throws exception if doesn't exist). + assetFileDescriptor = assetManager.openFd(assetPath); + InputStream assetStream = assetFileDescriptor.createInputStream(); + bitmap = BitmapFactory.decodeStream(assetStream); + assetFileDescriptor.close(); // Close for memory + break; // If exists, break + } catch (IOException e) { + // Skip + } + } + return bitmap; + } } diff --git a/android/src/main/java/com/mapbox/mapboxgl/SymbolBuilder.java b/android/src/main/java/com/mapbox/mapboxgl/SymbolBuilder.java index 24246e178..d0c4cf01b 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/SymbolBuilder.java +++ b/android/src/main/java/com/mapbox/mapboxgl/SymbolBuilder.java @@ -15,6 +15,7 @@ class SymbolBuilder implements SymbolOptionsSink { private final SymbolManager symbolManager; private final SymbolOptions symbolOptions; + private static boolean customImage; SymbolBuilder(SymbolManager symbolManager) { this.symbolManager = symbolManager; @@ -159,4 +160,8 @@ public void setSymbolSortKey(float symbolSortKey) { public void setDraggable(boolean draggable) { symbolOptions.withDraggable(draggable); } + + public boolean getCustomImage() { + return this.customImage; + } } \ No newline at end of file diff --git a/android/src/main/java/com/mapbox/mapboxgl/SymbolOptionsSink.java b/android/src/main/java/com/mapbox/mapboxgl/SymbolOptionsSink.java index cae541bab..b6aa5fc0a 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/SymbolOptionsSink.java +++ b/android/src/main/java/com/mapbox/mapboxgl/SymbolOptionsSink.java @@ -66,4 +66,5 @@ interface SymbolOptionsSink { void setSymbolSortKey(float symbolSortKey); void setDraggable(boolean draggable); + } diff --git a/example/assets/symbols/2.0x/custom-icon.png b/example/assets/symbols/2.0x/custom-icon.png new file mode 100644 index 000000000..eefdfb3a4 Binary files /dev/null and b/example/assets/symbols/2.0x/custom-icon.png differ diff --git a/example/assets/symbols/3.0x/custom-icon.png b/example/assets/symbols/3.0x/custom-icon.png new file mode 100644 index 000000000..f8b5f5e0d Binary files /dev/null and b/example/assets/symbols/3.0x/custom-icon.png differ diff --git a/example/assets/symbols/custom-icon.png b/example/assets/symbols/custom-icon.png new file mode 100644 index 000000000..11f53673a Binary files /dev/null and b/example/assets/symbols/custom-icon.png differ diff --git a/example/lib/place_symbol.dart b/example/lib/place_symbol.dart index 6f2a0bc4c..d1af2c12f 100644 --- a/example/lib/place_symbol.dart +++ b/example/lib/place_symbol.dart @@ -65,14 +65,15 @@ class PlaceSymbolBodyState extends State { controller.updateSymbol(_selectedSymbol, changes); } - void _add() { + void _add(String iconImage) { controller.addSymbol( SymbolOptions( - geometry: LatLng( - center.latitude + sin(_symbolCount * pi / 6.0) / 20.0, - center.longitude + cos(_symbolCount * pi / 6.0) / 20.0, - ), - iconImage: "airport-15"), + geometry: LatLng( + center.latitude + sin(_symbolCount * pi / 6.0) / 20.0, + center.longitude + cos(_symbolCount * pi / 6.0) / 20.0, + ), + iconImage: iconImage, + ), ); setState(() { _symbolCount += 1; @@ -156,8 +157,7 @@ class PlaceSymbolBodyState extends State { } _updateSelectedSymbol( - SymbolOptions( - iconOpacity: current == 0.0 ? 1.0 : 0.0), + SymbolOptions(iconOpacity: current == 0.0 ? 1.0 : 0.0), ); } @@ -202,7 +202,14 @@ class PlaceSymbolBodyState extends State { children: [ FlatButton( child: const Text('add'), - onPressed: (_symbolCount == 12) ? null : _add, + onPressed: () => + (_symbolCount == 12) ? null : _add("airport-15"), + ), + FlatButton( + child: const Text('add (custom icon)'), + onPressed: () => (_symbolCount == 12) + ? null + : _add("assets/symbols/custom-icon.png"), ), FlatButton( child: const Text('remove'), diff --git a/example/pubspec.yaml b/example/pubspec.yaml index a135e9851..95c648eb6 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -40,6 +40,11 @@ flutter: # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.io/assets-and-images/#resolution-aware. + assets: + - assets/symbols/custom-icon.png + - assets/symbols/2.0x/custom-icon.png + - assets/symbols/3.0x/custom-icon.png + # For details regarding adding assets from package dependencies, see # https://flutter.io/assets-and-images/#from-packages diff --git a/ios/Classes/Convert.swift b/ios/Classes/Convert.swift index 5d543b837..999ce594d 100644 --- a/ios/Classes/Convert.swift +++ b/ios/Classes/Convert.swift @@ -123,4 +123,86 @@ class Convert { class func getAltitude(zoom: Double, mapView: MGLMapView) -> Double { return MGLAltitudeForZoomLevel(zoom, mapView.camera.pitch, mapView.camera.centerCoordinate.latitude, mapView.frame.size) } + + class func interpretSymbolOptions(options: Any?, delegate: SymbolOptionsSink) { + guard let options = options as? [String: Any] else { return } + + if let iconSize = options["iconSize"] as? Double { + delegate.setIconSize(iconSize: iconSize) + } + if let iconImage = options["iconImage"] as? String { + delegate.setIconImage(iconImage: iconImage) + } + if let iconRotate = options["iconRotate"] as? Double { + delegate.setIconRotate(iconRotate: iconRotate) + } + //TODO: iconOffset + if let iconAnchor = options["iconAnchor"] as? String { + delegate.setIconAnchor(iconAnchor: iconAnchor) + } + if let textField = options["textField"] as? String { + delegate.setTextField(textField: textField) + } + if let textSize = options["textSize"] as? Double { + delegate.setTextSize(textSize: textSize) + } + if let textMaxWidth = options["textMaxWidth"] as? Double { + delegate.setTextMaxWidth(textMaxWidth: textMaxWidth) + } + if let textLetterSpacing = options["textLetterSpacing"] as? Double { + delegate.setTextLetterSpacing(textLetterSpacing: textLetterSpacing) + } + if let textJustify = options["textJustify"] as? String { + delegate.setTextJustify(textJustify: textJustify) + } + if let textAnchor = options["textAnchor"] as? String { + delegate.setTextAnchor(textAnchor: textAnchor) + } + if let textRotate = options["textRotate"] as? Double { + delegate.setTextRotate(textRotate: textRotate) + } + if let textTransform = options["textTransform"] as? String { + delegate.setTextTransform(textTransform: textTransform) + } + //TODO: textOffset + if let iconOpacity = options["iconOpacity"] as? Double { + delegate.setIconOpacity(iconOpacity: iconOpacity) + } + if let iconColor = options["iconColor"] as? String { + delegate.setIconColor(iconColor: iconColor) + } + if let iconHaloColor = options["iconHaloColor"] as? String { + delegate.setIconHaloColor(iconHaloColor: iconHaloColor) + } + if let iconHaloWidth = options["iconHaloWidth"] as? Double { + delegate.setIconHaloWidth(iconHaloWidth: iconHaloWidth) + } + if let iconHaloBlur = options["iconHaloBlur"] as? Double { + delegate.setIconHaloBlur(iconHaloBlur: iconHaloBlur) + } + if let textOpacity = options["textOpacity"] as? Double { + delegate.setTextOpacity(textOpacity: textOpacity) + } + if let textColor = options["textColor"] as? String { + delegate.setTextColor(textColor: textColor) + } + if let textHaloColor = options["textHaloColor"] as? String { + delegate.setTextHaloColor(textHaloColor: textHaloColor) + } + if let textHaloWidth = options["textHaloWidth"] as? Double { + delegate.setTextHaloWidth(textHaloWidth: textHaloWidth) + } + if let textHaloBlur = options["textHaloBlur"] as? Double { + delegate.setTextHaloBlur(textHaloBlur: textHaloBlur) + } + if let geometry = options["geometry"] as? [Double] { + delegate.setGeometry(geometry: geometry) + } + if let zIndex = options["zIndex"] as? Int { + delegate.setZIndex(zIndex: zIndex) + } + if let draggable = options["draggable"] as? Bool { + delegate.setDraggable(draggable: draggable) + } + } } diff --git a/ios/Classes/Extensions.swift b/ios/Classes/Extensions.swift index d5f6bae2c..4978824a5 100644 --- a/ios/Classes/Extensions.swift +++ b/ios/Classes/Extensions.swift @@ -38,3 +38,26 @@ extension MGLCoordinateBounds { return MGLCoordinateBounds(sw: southwest, ne: northeast) } } + +extension UIImage { + static func loadFromFile(imagePath: String, imageName: String) -> UIImage? { + // Add the trailing slash in path if missing. + let path = imagePath.hasSuffix("/") ? imagePath : "\(imagePath)/" + // Build scale dependant image path. + let scale = UIScreen.main.scale + var absolutePath = "\(path)\(scale)x/\(imageName)" + // Check if the image exists, if not try a an unscaled path. + if Bundle.main.path(forResource: absolutePath, ofType: nil) == nil { + absolutePath = "\(path)\(imageName)" + } + // Load image if it exists. + if let path = Bundle.main.path(forResource: absolutePath, ofType: nil) { + let imageUrl: URL = URL(fileURLWithPath: path) + if let imageData: Data = try? Data(contentsOf: imageUrl), + let image: UIImage = UIImage(data: imageData, scale: UIScreen.main.scale) { + return image + } + } + return nil + } +} diff --git a/ios/Classes/MapboxMapController.swift b/ios/Classes/MapboxMapController.swift index d1b037ddd..1352f9b8e 100644 --- a/ios/Classes/MapboxMapController.swift +++ b/ios/Classes/MapboxMapController.swift @@ -3,12 +3,14 @@ import UIKit import Mapbox class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, MapboxMapOptionsSink { - + + private var registrar: FlutterPluginRegistrar + private var channel: FlutterMethodChannel? + private var mapView: MGLMapView private var isMapReady = false private var mapReadyResult: FlutterResult? - private var channel: FlutterMethodChannel - + private var initialTilt: CGFloat? private var cameraTargetBounds: MGLCoordinateBounds? private var trackCameraPosition = false @@ -17,18 +19,19 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma func view() -> UIView { return mapView } - - init(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?, binaryMessenger messenger: FlutterBinaryMessenger) { + + init(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?, registrar: FlutterPluginRegistrar) { mapView = MGLMapView(frame: frame) mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] - channel = FlutterMethodChannel(name: "plugins.flutter.io/mapbox_maps_\(viewId)", binaryMessenger: messenger) - + self.registrar = registrar + super.init() - - channel.setMethodCallHandler(onMethodCall) - + + channel = FlutterMethodChannel(name: "plugins.flutter.io/mapbox_maps_\(viewId)", binaryMessenger: registrar.messenger()) + channel!.setMethodCallHandler(onMethodCall) + mapView.delegate = self - + if let args = args as? [String: Any] { Convert.interpretMapboxMapOptions(options: args["options"], delegate: self) if let initialCameraPosition = args["initialCameraPosition"] as? [String: Any], @@ -39,7 +42,7 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma } } } - + func onMethodCall(methodCall: FlutterMethodCall, result: @escaping FlutterResult) { switch(methodCall.method) { case "map#waitForMap": @@ -68,61 +71,142 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma if let camera = Convert.parseCameraUpdate(cameraUpdate: cameraUpdate, mapView: mapView) { mapView.setCamera(camera, animated: true) } + case "symbol#add": + guard let arguments = methodCall.arguments as? [String: Any] else { return } + let symbol = Symbol() + Convert.interpretSymbolOptions(options: arguments["options"], delegate: symbol) + if CLLocationCoordinate2DIsValid(symbol.geometry) { + mapView.addAnnotation(symbol) + result(symbol.id) + } else { + result(nil) + } + case "symbol#update": + guard let arguments = methodCall.arguments as? [String: Any] else { return } + guard let symbolIdString = arguments["symbol"] as? String else { return } + + if let symbol = getSymbolInMapView(mapView: mapView, symbolId: symbolIdString) { + Convert.interpretSymbolOptions(options: arguments["options"], delegate: symbol) + } + result(nil) + case "symbol#remove": + guard let arguments = methodCall.arguments as? [String: Any] else { return } + guard let symbolIdString = arguments["symbol"] as? String else { return } + + if let symbol = getSymbolInMapView(mapView: mapView, symbolId: symbolIdString) { + mapView.removeAnnotation(symbol) + } + result(nil) default: result(FlutterMethodNotImplemented) } } + private func getSymbolInMapView(mapView: MGLMapView, symbolId: String) -> Symbol? { + if let annotations = mapView.annotations { + for (_, annotation) in annotations.enumerated() { + if let symbolAnnotation = annotation as? Symbol { + if symbolAnnotation.id == symbolId { + return symbolAnnotation + } + } + } + } + return nil + } + private func updateMyLocationEnabled() { mapView.showsUserLocation = self.myLocationEnabled } - + private func getCamera() -> MGLMapCamera? { return trackCameraPosition ? mapView.camera : nil } - + /* * MGLMapViewDelegate */ func mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle) { isMapReady = true updateMyLocationEnabled() - + if let initialTilt = initialTilt { let camera = mapView.camera camera.pitch = initialTilt mapView.setCamera(camera, animated: false) } - + mapReadyResult?(nil) } - + func mapView(_ mapView: MGLMapView, shouldChangeFrom oldCamera: MGLMapCamera, to newCamera: MGLMapCamera) -> Bool { guard let bbox = cameraTargetBounds else { return true } // Get the current camera to restore it after. let currentCamera = mapView.camera - + // From the new camera obtain the center to test if it’s inside the boundaries. let newCameraCenter = newCamera.centerCoordinate - + // Set the map’s visible bounds to newCamera. mapView.camera = newCamera let newVisibleCoordinates = mapView.visibleCoordinateBounds - + // Revert the camera. mapView.camera = currentCamera - + // Test if the newCameraCenter and newVisibleCoordinates are inside bbox. let inside = MGLCoordinateInCoordinateBounds(newCameraCenter, bbox) let intersects = MGLCoordinateInCoordinateBounds(newVisibleCoordinates.ne, bbox) && MGLCoordinateInCoordinateBounds(newVisibleCoordinates.sw, bbox) - + return inside && intersects } - + + func mapView(_ mapView: MGLMapView, imageFor annotation: MGLAnnotation) -> MGLAnnotationImage? { + // Only for Symbols images should loaded. + guard let symbol = annotation as? Symbol, + let iconImageFullPath = symbol.iconImage else { + return nil + } + // Reuse existing annotations for better performance. + var annotationImage = mapView.dequeueReusableAnnotationImage(withIdentifier: iconImageFullPath) + if annotationImage == nil { + // Initialize the annotation image (from predefined assets symbol folder). + if let range = iconImageFullPath.range(of: "/", options: [.backwards]) { + let directory = String(iconImageFullPath[.. Bool { + return true + } + func mapView(_ mapView: MGLMapView, didChange mode: MGLUserTrackingMode, animated: Bool) { - channel.invokeMethod("map#onCameraTrackingChanged", arguments: ["mode": mode.rawValue]) - if mode == .none { - channel.invokeMethod("map#onCameraTrackingDismissed", arguments: []) + if let channel = channel { + channel.invokeMethod("map#onCameraTrackingChanged", arguments: ["mode": mode.rawValue]) + if mode == .none { + channel.invokeMethod("map#onCameraTrackingDismissed", arguments: []) + } } } diff --git a/ios/Classes/MapboxMapFactory.swift b/ios/Classes/MapboxMapFactory.swift index 59daa40c2..ba3bc4141 100644 --- a/ios/Classes/MapboxMapFactory.swift +++ b/ios/Classes/MapboxMapFactory.swift @@ -2,10 +2,10 @@ import Flutter class MapboxMapFactory: NSObject, FlutterPlatformViewFactory { - var messenger: FlutterBinaryMessenger + var registrar: FlutterPluginRegistrar - init(withMessenger messenger: FlutterBinaryMessenger) { - self.messenger = messenger + init(withRegistrar registrar: FlutterPluginRegistrar) { + self.registrar = registrar super.init() } @@ -14,6 +14,6 @@ class MapboxMapFactory: NSObject, FlutterPlatformViewFactory { } func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView { - return MapboxMapController(withFrame: frame, viewIdentifier: viewId, arguments: args, binaryMessenger: messenger) + return MapboxMapController(withFrame: frame, viewIdentifier: viewId, arguments: args, registrar: registrar) } } diff --git a/ios/Classes/SwiftMapboxGlFlutterPlugin.swift b/ios/Classes/SwiftMapboxGlFlutterPlugin.swift index ac530ebad..75847f066 100644 --- a/ios/Classes/SwiftMapboxGlFlutterPlugin.swift +++ b/ios/Classes/SwiftMapboxGlFlutterPlugin.swift @@ -3,7 +3,7 @@ import UIKit public class SwiftMapboxGlFlutterPlugin: NSObject, FlutterPlugin { public static func register(with registrar: FlutterPluginRegistrar) { - let instance = MapboxMapFactory(withMessenger: registrar.messenger()) + let instance = MapboxMapFactory(withRegistrar: registrar) registrar.register(instance, withId: "plugins.flutter.io/mapbox_gl") let channel = FlutterMethodChannel(name: "plugins.flutter.io/mapbox_gl", binaryMessenger: registrar.messenger()) diff --git a/ios/Classes/Symbol.swift b/ios/Classes/Symbol.swift new file mode 100644 index 000000000..29506c70b --- /dev/null +++ b/ios/Classes/Symbol.swift @@ -0,0 +1,128 @@ +import Mapbox + +class Symbol : MGLPointAnnotation, SymbolOptionsSink { + + private var _id = UUID().uuidString + var id: String { + get { return _id } + } + + private var _iconImage: String? + var iconImage: String? { + get { return _iconImage } + } + + var textField: String? { + get { return title } + } + + var geometry: CLLocationCoordinate2D { + get{ return coordinate } + } + + // MARK: Setters + + func setIconSize(iconSize: Double) { + + } + + func setIconImage(iconImage: String) { + _iconImage = iconImage + } + + func setIconRotate(iconRotate: Double) { + + } + + func setIconAnchor(iconAnchor: String) { + + } + + func setTextField(textField: String) { + title = textField + } + + func setTextSize(textSize: Double) { + + } + + func setTextMaxWidth(textMaxWidth: Double) { + + } + + func setTextLetterSpacing(textLetterSpacing: Double) { + + } + + func setTextJustify(textJustify: String) { + + } + + func setTextAnchor(textAnchor: String) { + + } + + func setTextRotate(textRotate: Double) { + + } + + func setTextTransform(textTransform: String) { + + } + + func setIconOpacity(iconOpacity: Double) { + + } + + func setIconColor(iconColor: String) { + + } + + func setIconHaloColor(iconHaloColor: String) { + + } + + func setIconHaloWidth(iconHaloWidth: Double) { + + } + + func setIconHaloBlur(iconHaloBlur: Double) { + + } + + func setTextOpacity(textOpacity: Double) { + + } + + func setTextColor(textColor: String) { + + } + + func setTextHaloColor(textHaloColor: String) { + + } + + func setTextHaloWidth(textHaloWidth: Double) { + + } + + func setTextHaloBlur(textHaloBlur: Double) { + + } + + func setGeometry(geometry: [Double]) { + if geometry.count == 2, -90...90 ~= geometry[0], -180...180 ~= geometry[1] { + coordinate = CLLocationCoordinate2D(latitude: geometry[0], longitude: geometry[1]) + } else { + NSLog("Invalid geometry") + } + } + + func setZIndex(zIndex: Int) { + + } + + func setDraggable(draggable: Bool) { + + } +} diff --git a/ios/Classes/SymbolOptionsSink.swift b/ios/Classes/SymbolOptionsSink.swift new file mode 100644 index 000000000..2c07414a7 --- /dev/null +++ b/ios/Classes/SymbolOptionsSink.swift @@ -0,0 +1,31 @@ + +protocol SymbolOptionsSink { + func setIconSize(iconSize: Double) + func setIconImage(iconImage: String) + func setIconRotate(iconRotate: Double) +// final Offset iconOffset; + func setIconAnchor(iconAnchor: String) + func setTextField(textField: String) + func setTextSize(textSize: Double) + func setTextMaxWidth(textMaxWidth: Double) + func setTextLetterSpacing(textLetterSpacing: Double) + func setTextJustify(textJustify: String) + func setTextAnchor(textAnchor: String) + func setTextRotate(textRotate: Double) + func setTextTransform(textTransform: String) +// final Offset textOffset; + func setIconOpacity(iconOpacity: Double) + func setIconColor(iconColor: String) + func setIconHaloColor(iconHaloColor: String) + func setIconHaloWidth(iconHaloWidth: Double) + func setIconHaloBlur(iconHaloBlur: Double) + func setTextOpacity(textOpacity: Double) + func setTextColor(textColor: String) + func setTextHaloColor(textHaloColor: String) + func setTextHaloWidth(textHaloWidth: Double) + func setTextHaloBlur(textHaloBlur: Double) + + func setGeometry(geometry: [Double]) + func setZIndex(zIndex: Int) + func setDraggable(draggable: Bool) +}