From 0a0e485dfed0e023a34da1abd07fe052bdbb86d5 Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Fri, 19 Nov 2021 20:57:04 +0100 Subject: [PATCH 01/26] line annotations in dart --- example/lib/line.dart | 32 +++--- lib/mapbox_gl.dart | 3 + lib/src/annotation.dart | 101 ++++++++++++++++++ lib/src/controller.dart | 16 ++- lib/src/util.dart | 14 +++ .../lib/mapbox_gl_platform_interface.dart | 1 + .../lib/src/annotation.dart | 9 ++ .../lib/src/line.dart | 50 ++++++++- .../lib/src/location.dart | 4 + 9 files changed, 213 insertions(+), 17 deletions(-) create mode 100644 lib/src/annotation.dart create mode 100644 lib/src/util.dart create mode 100644 mapbox_gl_platform_interface/lib/src/annotation.dart diff --git a/example/lib/line.dart b/example/lib/line.dart index cc8e541df..b5fbeea5c 100644 --- a/example/lib/line.dart +++ b/example/lib/line.dart @@ -34,18 +34,19 @@ class LineBodyState extends State { static final LatLng center = const LatLng(-33.86711, 151.1947171); MapboxMapController? controller; + LineManager? lineManager; + int lineId = 0; + int _lineCount = 0; Line? _selectedLine; final String _linePatternImage = "assets/fill/cat_silhouette_pattern.png"; void _onMapCreated(MapboxMapController controller) { this.controller = controller; - controller.onLineTapped.add(_onLineTapped); } @override void dispose() { - controller?.onLineTapped.remove(_onLineTapped); super.dispose(); } @@ -63,17 +64,17 @@ class LineBodyState extends State { setState(() { _selectedLine = line; }); - await _updateSelectedLine( - LineOptions(lineColor: "#ffe100"), - ); } - _updateSelectedLine(LineOptions changes) async { - if (_selectedLine != null) controller!.updateLine(_selectedLine!, changes); + Future _updateSelectedLine(LineOptions changes) { + _selectedLine = _selectedLine! + .copyWith(options: _selectedLine!.options.copyWith(changes)); + return lineManager!.set(_selectedLine!); } void _add() { - controller!.addLine( + lineManager!.add(Line( + lineId.toString(), LineOptions( geometry: [ LatLng(-33.86711, 151.1947171), @@ -82,11 +83,13 @@ class LineBodyState extends State { LatLng(-33.86711, 152.1947171), ], lineColor: "#ff0000", - lineWidth: 14.0, + lineWidth: 30.0, lineOpacity: 0.5, draggable: true), - ); + )); + setState(() { + lineId++; _lineCount += 1; }); } @@ -103,7 +106,7 @@ class LineBodyState extends State { } void _remove() { - controller!.removeLine(_selectedLine!); + lineManager!.remove(_selectedLine!); setState(() { _selectedLine = null; _lineCount -= 1; @@ -223,9 +226,10 @@ class LineBodyState extends State { onPressed: (_selectedLine == null) ? null : () async { - var latLngs = await controller! - .getLineLatLngs(_selectedLine!); - for (var latLng in latLngs) { + var current = + lineManager!.byId(_selectedLine!.id)!; + for (var latLng + in current.options.geometry!) { print(latLng.toString()); } }, diff --git a/lib/mapbox_gl.dart b/lib/mapbox_gl.dart index 6d388c930..1af48b0e1 100644 --- a/lib/mapbox_gl.dart +++ b/lib/mapbox_gl.dart @@ -35,6 +35,7 @@ export 'package:mapbox_gl_platform_interface/mapbox_gl_platform_interface.dart' MyLocationRenderMode, CompassViewPosition, AttributionButtonPosition, + Annotation, Circle, CircleOptions, Line, @@ -57,3 +58,5 @@ part 'src/download_region_status.dart'; part 'src/layer_expressions.dart'; part 'src/layer_properties.dart'; part 'src/color_tools.dart'; +part 'src/annotation.dart'; +part 'src/util.dart'; diff --git a/lib/src/annotation.dart b/lib/src/annotation.dart new file mode 100644 index 000000000..b9708457b --- /dev/null +++ b/lib/src/annotation.dart @@ -0,0 +1,101 @@ +part of mapbox_gl; + +abstract class _AnnotationManager { + final MapboxMapController controller; + final void Function(T)? onTap; + final _idToAnnotation = {}; + final id; + LatLng? _dragOrigin; + LayerProperties get properties; + + T? byId(String id) => _idToAnnotation[id]; + + _AnnotationManager(this.controller, {this.onTap}) : id = getRandomString(10) { + controller.addGeoJsonSource(id, buildFeatureCollection([])); + controller.addLayer(id, id, properties); + if (onTap != null) { + controller.onFeatureTapped.add(_onFeatureTapped); + } + } + _onFeatureTapped(dynamic id, Point point, LatLng coordinates) { + final annotation = _idToAnnotation[id]; + if (annotation != null) { + onTap!(annotation); + } + } + + Future _setAll() async { + return controller.setGeoJsonSource( + id, + buildFeatureCollection( + [for (final l in _idToAnnotation.values) l.toGeoJson()])); + } + + Future addAll(Iterable annotations) async { + for (var a in annotations) { + _idToAnnotation[a.id] = a; + } + await _setAll(); + } + + Future add(T annotation) async { + _idToAnnotation[annotation.id] = annotation; + await _setAll(); + } + + Future remove(T annotation) async { + _idToAnnotation.remove(annotation.id); + await _setAll(); + } + + Future clear() async { + _idToAnnotation.clear(); + + await _setAll(); + } + + // TODO this requires a new call back + onPointerDown(String id, LatLng position) { + final annotation = byId(id); + if (annotation != null && annotation.draggable) { + if (_dragOrigin == null) { + // TODO missing from native !! + //controller.lockCamera(); + _dragOrigin = position; + } else { + final moved = annotation.translate(position - _dragOrigin!) as T; + set(moved); + } + } + } + + // TODO this requires a new call back + onPointerUp(String id, LatLng position) { + final annotation = byId(id); + if (annotation != null) { + final moved = annotation.translate(position - _dragOrigin!) as T; + set(moved); + } + _dragOrigin = null; + } + + Future set(T annoation) async { + _idToAnnotation[annoation.id] = annoation; + //Todo: send only the changed line to plugin + await _setAll(); + } +} + +class LineManager extends _AnnotationManager { + LineManager(MapboxMapController controller, {void Function(Line)? onTap}) + : super(controller, onTap: onTap); + @override + LayerProperties get properties => const LineLayerProperties( + lineOpacity: [Expressions.get, 'lineOpacity'], + lineColor: [Expressions.get, 'lineColor'], + lineWidth: [Expressions.get, 'lineWidth'], + lineGapWidth: [Expressions.get, 'lineGapWidth'], + lineOffset: [Expressions.get, 'lineOffset'], + lineBlur: [Expressions.get, 'lineBlur'], + ); +} diff --git a/lib/src/controller.dart b/lib/src/controller.dart index 1909f34a6..b598e5525 100644 --- a/lib/src/controller.dart +++ b/lib/src/controller.dart @@ -406,6 +406,20 @@ class MapboxMapController extends ChangeNotifier { ); } + Future addLayer( + String sourceId, String layerId, LayerProperties properties, + {String? belowLayerId}) async { + if (properties is FillLayerProperties) { + addFillLayer(sourceId, layerId, properties); + } else if (properties is LineLayerProperties) { + addLineLayer(sourceId, layerId, properties); + } else if (properties is SymbolLayerProperties) { + addSymbolLayer(sourceId, layerId, properties); + } else if (properties is CircleLayerProperties) { + addCircleLayer(sourceId, layerId, properties); + } + } + /// Updates user location tracking mode. /// /// The returned [Future] completes after the change has been made on the @@ -615,7 +629,7 @@ class MapboxMapController extends ChangeNotifier { Future updateLine(Line line, LineOptions changes) async { assert(_lines[line.id] == line); await _mapboxGlPlatform.updateLine(line, changes); - line.options = line.options.copyWith(changes); + _lines[line.id] = line.copyWith(options: line.options.copyWith(changes)); notifyListeners(); } diff --git a/lib/src/util.dart b/lib/src/util.dart new file mode 100644 index 000000000..5ba0b789e --- /dev/null +++ b/lib/src/util.dart @@ -0,0 +1,14 @@ +part of mapbox_gl; + +Map buildFeatureCollection( + List> features) { + return {"type": "FeatureCollection", "features": features}; +} + +final _random = Random(); +String getRandomString([int length = 10]) { + const charSet = + 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890'; + return String.fromCharCodes(Iterable.generate( + length, (_) => charSet.codeUnitAt(_random.nextInt(charSet.length)))); +} diff --git a/mapbox_gl_platform_interface/lib/mapbox_gl_platform_interface.dart b/mapbox_gl_platform_interface/lib/mapbox_gl_platform_interface.dart index d9afebae7..3585cd037 100644 --- a/mapbox_gl_platform_interface/lib/mapbox_gl_platform_interface.dart +++ b/mapbox_gl_platform_interface/lib/mapbox_gl_platform_interface.dart @@ -10,6 +10,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:meta/meta.dart' show visibleForTesting; +part 'src/annotation.dart'; part 'src/callbacks.dart'; part 'src/camera.dart'; part 'src/circle.dart'; diff --git a/mapbox_gl_platform_interface/lib/src/annotation.dart b/mapbox_gl_platform_interface/lib/src/annotation.dart new file mode 100644 index 000000000..9f2d4d614 --- /dev/null +++ b/mapbox_gl_platform_interface/lib/src/annotation.dart @@ -0,0 +1,9 @@ +part of mapbox_gl_platform_interface; + +abstract class Annotation { + String get id; + Map toGeoJson(); + + Annotation translate(LatLng delta); + bool get draggable; +} diff --git a/mapbox_gl_platform_interface/lib/src/line.dart b/mapbox_gl_platform_interface/lib/src/line.dart index 0447bd26d..7c02322b7 100644 --- a/mapbox_gl_platform_interface/lib/src/line.dart +++ b/mapbox_gl_platform_interface/lib/src/line.dart @@ -6,7 +6,7 @@ part of mapbox_gl_platform_interface; -class Line { +class Line implements Annotation { Line(this._id, this.options, [this._data]); /// A unique identifier for this line. @@ -25,7 +25,32 @@ class Line { /// /// The returned value does not reflect any changes made to the line through /// touch events. Add listeners to the owning map controller to track those. - LineOptions options; + final LineOptions options; + + Line copyWith({String? id, Map? data, LineOptions? options}) { + return Line( + id ?? this.id, + options ?? this.options, + data ?? this.data, + ); + } + + Map toGeoJson() { + final geojson = options.toGeoJson(); + geojson["id"] = id; + + return geojson; + } + + @override + Line translate(LatLng delta) { + final options = this.options.copyWith(LineOptions( + geometry: this.options.geometry?.map((e) => e + delta).toList())); + return copyWith(options: options); + } + + @override + bool get draggable => options.draggable ?? false; } /// Configuration options for [Line] instances. @@ -100,4 +125,25 @@ class LineOptions { addIfPresent('draggable', draggable); return json; } + + Map toGeoJson() { + return { + "type": "Feature", + "properties": { + if (lineJoin != null) "lineJoin": lineJoin, + if (lineOpacity != null) "lineOpacity": lineOpacity, + if (lineColor != null) "lineColor": lineColor, + if (lineWidth != null) "lineWidth": lineWidth, + if (lineGapWidth != null) "lineGapWidth": lineGapWidth, + if (lineOffset != null) "lineOffset": lineOffset, + if (lineBlur != null) "lineBlur": lineBlur, + if (linePattern != null) "linePattern": linePattern, + }, + "geometry": { + "type": "LineString", + if (geometry != null) + "coordinates": geometry?.map((c) => c.toGeoJsonCoordinates()).toList() + } + }; + } } diff --git a/mapbox_gl_platform_interface/lib/src/location.dart b/mapbox_gl_platform_interface/lib/src/location.dart index c64e05e2c..7c058dda9 100644 --- a/mapbox_gl_platform_interface/lib/src/location.dart +++ b/mapbox_gl_platform_interface/lib/src/location.dart @@ -36,6 +36,10 @@ class LatLng { return [latitude, longitude]; } + dynamic toGeoJsonCoordinates() { + return [longitude, latitude]; + } + static LatLng _fromJson(List json) { return LatLng(json[0], json[1]); } From d2b8bc038f1105adb49eeaba9d6ab7802db93dcd Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Thu, 16 Dec 2021 16:08:04 +0100 Subject: [PATCH 02/26] working drag --- example/lib/line.dart | 8 +-- lib/src/annotation.dart | 30 ++++-------- lib/src/controller.dart | 25 ++++++++-- .../lib/src/line.dart | 2 + .../lib/src/mapbox_gl_platform_interface.dart | 2 + .../lib/src/mapbox_map_controller.dart | 49 ++++++++++++++++++- mapbox_gl_web/pubspec.yaml | 2 +- 7 files changed, 88 insertions(+), 30 deletions(-) diff --git a/example/lib/line.dart b/example/lib/line.dart index b5fbeea5c..88925cf8d 100644 --- a/example/lib/line.dart +++ b/example/lib/line.dart @@ -58,12 +58,12 @@ class LineBodyState extends State { } _onLineTapped(Line line) async { - await _updateSelectedLine( - LineOptions(lineColor: "#ff0000"), - ); setState(() { _selectedLine = line; }); + await _updateSelectedLine( + LineOptions(lineColor: "#ff0000"), + ); } Future _updateSelectedLine(LineOptions changes) { @@ -168,7 +168,7 @@ class LineBodyState extends State { child: MapboxMap( accessToken: MapsDemo.ACCESS_TOKEN, onMapCreated: _onMapCreated, - onStyleLoadedCallback: _onStyleLoadedCallback, + onStyleLoadedCallback: onStyleLoadedCallback, initialCameraPosition: const CameraPosition( target: LatLng(-33.852, 151.211), zoom: 11.0, diff --git a/lib/src/annotation.dart b/lib/src/annotation.dart index b9708457b..33dfd2d40 100644 --- a/lib/src/annotation.dart +++ b/lib/src/annotation.dart @@ -5,17 +5,18 @@ abstract class _AnnotationManager { final void Function(T)? onTap; final _idToAnnotation = {}; final id; - LatLng? _dragOrigin; LayerProperties get properties; T? byId(String id) => _idToAnnotation[id]; _AnnotationManager(this.controller, {this.onTap}) : id = getRandomString(10) { - controller.addGeoJsonSource(id, buildFeatureCollection([])); + controller.addGeoJsonSource(id, buildFeatureCollection([]), + promoteId: "id"); controller.addLayer(id, id, properties); if (onTap != null) { controller.onFeatureTapped.add(_onFeatureTapped); } + controller.onFeatureDrag.add(_onDrag); } _onFeatureTapped(dynamic id, Point point, LatLng coordinates) { final annotation = _idToAnnotation[id]; @@ -54,29 +55,16 @@ abstract class _AnnotationManager { await _setAll(); } - // TODO this requires a new call back - onPointerDown(String id, LatLng position) { - final annotation = byId(id); - if (annotation != null && annotation.draggable) { - if (_dragOrigin == null) { - // TODO missing from native !! - //controller.lockCamera(); - _dragOrigin = position; - } else { - final moved = annotation.translate(position - _dragOrigin!) as T; - set(moved); - } - } - } - - // TODO this requires a new call back - onPointerUp(String id, LatLng position) { + _onDrag(dynamic id, + {required Point point, + required LatLng origin, + required LatLng current, + required LatLng delta}) { final annotation = byId(id); if (annotation != null) { - final moved = annotation.translate(position - _dragOrigin!) as T; + final moved = annotation.translate(delta) as T; set(moved); } - _dragOrigin = null; } Future set(T annoation) async { diff --git a/lib/src/controller.dart b/lib/src/controller.dart index b598e5525..be8ffdff3 100644 --- a/lib/src/controller.dart +++ b/lib/src/controller.dart @@ -6,9 +6,15 @@ part of mapbox_gl; typedef void OnMapClickCallback(Point point, LatLng coordinates); -typedef void OnFeatureTappedCallback( +typedef void OnFeatureInteractionCallback( dynamic id, Point point, LatLng coordinates); +typedef void OnFeatureDragnCallback(dynamic id, + {required Point point, + required LatLng origin, + required LatLng current, + required LatLng delta}); + typedef void OnMapLongClickCallback(Point point, LatLng coordinates); typedef void OnAttributionClickCallback(); @@ -91,11 +97,22 @@ class MapboxMapController extends ChangeNotifier { }); _mapboxGlPlatform.onFeatureTappedPlatform.add((payload) { - for (final fun in List.from(onFeatureTapped)) { + for (final fun + in List.from(onFeatureTapped)) { fun(payload["id"], payload["point"], payload["latLng"]); } }); + _mapboxGlPlatform.onFeatureDraggedPlatform.add((payload) { + for (final fun in List.from(onFeatureDrag)) { + fun(payload["id"], + point: payload["point"], + origin: payload["origin"], + current: payload["current"], + delta: payload["delta"]); + } + }); + _mapboxGlPlatform.onCameraMoveStartedPlatform.add((_) { _isCameraMoving = true; notifyListeners(); @@ -187,7 +204,9 @@ class MapboxMapController extends ChangeNotifier { final ArgumentCallbacks onFillTapped = ArgumentCallbacks(); /// Callbacks to receive tap events for features (geojson layer) placed on this map. - final onFeatureTapped = []; + final onFeatureTapped = []; + + final onFeatureDrag = []; /// Callbacks to receive tap events for info windows on symbols final ArgumentCallbacks onInfoWindowTapped = diff --git a/mapbox_gl_platform_interface/lib/src/line.dart b/mapbox_gl_platform_interface/lib/src/line.dart index 7c02322b7..583ed79f3 100644 --- a/mapbox_gl_platform_interface/lib/src/line.dart +++ b/mapbox_gl_platform_interface/lib/src/line.dart @@ -38,6 +38,7 @@ class Line implements Annotation { Map toGeoJson() { final geojson = options.toGeoJson(); geojson["id"] = id; + geojson["properties"]["id"] = id; return geojson; } @@ -138,6 +139,7 @@ class LineOptions { if (lineOffset != null) "lineOffset": lineOffset, if (lineBlur != null) "lineBlur": lineBlur, if (linePattern != null) "linePattern": linePattern, + "draggable": draggable ?? false, }, "geometry": { "type": "LineString", diff --git a/mapbox_gl_platform_interface/lib/src/mapbox_gl_platform_interface.dart b/mapbox_gl_platform_interface/lib/src/mapbox_gl_platform_interface.dart index ec618d067..957022dde 100644 --- a/mapbox_gl_platform_interface/lib/src/mapbox_gl_platform_interface.dart +++ b/mapbox_gl_platform_interface/lib/src/mapbox_gl_platform_interface.dart @@ -26,6 +26,8 @@ abstract class MapboxGlPlatform { final onFeatureTappedPlatform = ArgumentCallbacks>(); + final onFeatureDraggedPlatform = ArgumentCallbacks>(); + final onCameraMoveStartedPlatform = ArgumentCallbacks(); final onCameraMovePlatform = ArgumentCallbacks(); diff --git a/mapbox_gl_web/lib/src/mapbox_map_controller.dart b/mapbox_gl_web/lib/src/mapbox_map_controller.dart index 48eed54dd..1d5995e77 100644 --- a/mapbox_gl_web/lib/src/mapbox_map_controller.dart +++ b/mapbox_gl_web/lib/src/mapbox_map_controller.dart @@ -10,6 +10,9 @@ class MapboxMapController extends MapboxGlPlatform late Map _creationParams; late MapboxMap _map; bool _mapReady = false; + dynamic _draggedFeatureId; + LatLng? _dragOrigin; + LatLng? _dragPrevious; List annotationOrder = []; final _featureLayerIdentifiers = Set(); @@ -74,6 +77,8 @@ class MapboxMapController extends MapboxGlPlatform _map.on('move', _onCameraMove); _map.on('moveend', _onCameraIdle); _map.on('resize', _onMapResize); + _map.on('mouseup', _onMouseUp); + _map.on('mousemove', _onMouseMove); } Convert.interpretMapboxMapOptions(_creationParams['options'], this); @@ -82,6 +87,44 @@ class MapboxMapController extends MapboxGlPlatform } } + onDrag(dynamic id, LatLng coords) { + print("FOOOBAR"); + } + + _onMouseDown(Event e) { + var isDraggable = e.features[0].properties['draggable']; + if (isDraggable != null && isDraggable) { + // Prevent the default map drag behavior. + e.preventDefault(); + _draggedFeatureId = e.features[0].id; + _map.getCanvas().style.cursor = 'grabbing'; + var coords = e.lngLat; + _dragOrigin = LatLng(coords.lat as double, coords.lng as double); + } + } + + _onMouseUp(Event e) { + _draggedFeatureId = null; + _dragPrevious = null; + _dragOrigin = null; + _map.getCanvas().style.cursor = ''; + } + + _onMouseMove(Event e) { + if (_draggedFeatureId != null) { + final current = LatLng(e.lngLat.lat.toDouble(), e.lngLat.lng.toDouble()); + final payload = { + 'id': _draggedFeatureId, + 'point': Point(e.point.x.toDouble(), e.point.y.toDouble()), + 'origin': _dragOrigin, + 'current': current, + 'delta': current - (_dragPrevious ?? _dragOrigin!), + }; + _dragPrevious = current; + onFeatureDraggedPlatform(payload); + } + } + Future _addStylesheetToShadowRoot(HtmlElement e) async { LinkElement link = LinkElement() ..href = _mapboxGlCssUrl @@ -706,6 +749,7 @@ class MapboxMapController extends MapboxGlPlatform _map.off('mouseenter', layerId, _onMouseEnterFeature); _map.off('mousemouve', layerId, _onMouseEnterFeature); _map.off('mouseleave', layerId, _onMouseLeaveFeature); + _map.off('mousedown', layerId, _onMouseDown); } _featureLayerIdentifiers.clear(); @@ -848,10 +892,13 @@ class MapboxMapController extends MapboxGlPlatform _map.on('mouseenter', layerId, _onMouseEnterFeature); } _map.on('mouseleave', layerId, _onMouseLeaveFeature); + _map.on('mousedown', layerId, _onMouseDown); } void _onMouseEnterFeature(_) { - _map.getCanvas().style.cursor = 'pointer'; + if (_draggedFeatureId == null) { + _map.getCanvas().style.cursor = 'pointer'; + } } void _onMouseLeaveFeature(_) { diff --git a/mapbox_gl_web/pubspec.yaml b/mapbox_gl_web/pubspec.yaml index 38fde8a62..e6e736718 100644 --- a/mapbox_gl_web/pubspec.yaml +++ b/mapbox_gl_web/pubspec.yaml @@ -20,7 +20,7 @@ dependencies: git: url: https://github.com/tobrun/flutter-mapbox-gl.git path: mapbox_gl_platform_interface - mapbox_gl_dart: ^0.2.0-nullsafety + mapbox_gl_dart: ^0.2.1 image: ^3.0.0 dependency_overrides: From d0a4e0b2122715a6eb351880954b0b089e240293 Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Thu, 16 Dec 2021 19:02:39 +0100 Subject: [PATCH 03/26] add ios drag support --- ios/Classes/MapboxMapController.swift | 76 ++++++++++++++++++- .../lib/src/method_channel_mapbox_gl.dart | 22 ++++++ 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/ios/Classes/MapboxMapController.swift b/ios/Classes/MapboxMapController.swift index 4e750900e..14be84126 100644 --- a/ios/Classes/MapboxMapController.swift +++ b/ios/Classes/MapboxMapController.swift @@ -4,7 +4,7 @@ import MapboxAnnotationExtension import UIKit class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, MapboxMapOptionsSink, - MGLAnnotationControllerDelegate + UIGestureRecognizerDelegate, MGLAnnotationControllerDelegate { private var registrar: FlutterPluginRegistrar private var channel: FlutterMethodChannel? @@ -14,11 +14,15 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma private var isFirstStyleLoad = true private var onStyleLoadedCalled = false private var mapReadyResult: FlutterResult? + private var previousDragCoordinate: CLLocationCoordinate2D? + private var originDragCoordinate: CLLocationCoordinate2D? + private var dragFeature: MGLFeature? private var initialTilt: CGFloat? private var cameraTargetBounds: MGLCoordinateBounds? private var trackCameraPosition = false private var myLocationEnabled = false + private var scrollingEnabled = true private var symbolAnnotationController: MGLSymbolAnnotationController? private var circleAnnotationController: MGLCircleAnnotationController? @@ -80,6 +84,14 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma } mapView.addGestureRecognizer(longPress) + let pan = UIPanGestureRecognizer( + target: self, + action: #selector(handleMapPan(sender:)) + ) + + pan.delegate = self + mapView.addGestureRecognizer(pan) + if let args = args as? [String: Any] { Convert.interpretMapboxMapOptions(options: args["options"], delegate: self) if let initialCameraPosition = args["initialCameraPosition"] as? [String: Any], @@ -114,6 +126,13 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma controller.removeStyleAnnotations(annotations.filter { idSet.contains($0.identifier) }) } + func gestureRecognizer( + _: UIGestureRecognizer, + shouldRecognizeSimultaneouslyWith _: UIGestureRecognizer + ) -> Bool { + return true + } + func onMethodCall(methodCall: FlutterMethodCall, result: @escaping FlutterResult) { switch methodCall.method { case "map#waitForMap": @@ -1047,6 +1066,60 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma } } + /* + * UITapGestureRecognizer + * On pan might invoke the feature#onDrag callback. + */ + @IBAction func handleMapPan(sender: UIPanGestureRecognizer) { + // Get the CGPoint where the user tapped. + print(sender.state) + + let point = sender.location(in: mapView) + let coordinate = mapView.convert(point, toCoordinateFrom: mapView) + + if sender.state == UIGestureRecognizer.State.began, + sender.numberOfTouches == 1, + let feature = firstFeatureOnLayers(at: point), + let draggable = feature.attribute(forKey: "draggable") as? Bool, + draggable + { + dragFeature = feature + originDragCoordinate = coordinate + previousDragCoordinate = coordinate + mapView.allowsScrolling = false + for gestureRecognizer in mapView.gestureRecognizers! { + if let _ = gestureRecognizer as? UIPanGestureRecognizer { + gestureRecognizer.addTarget(self, action: #selector(handleMapPan)) + break + } + } + } else if sender.state == UIGestureRecognizer.State.ended || sender.numberOfTouches != 1 { + sender.state = UIGestureRecognizer.State.ended + mapView.allowsScrolling = scrollingEnabled + dragFeature = nil + originDragCoordinate = nil + previousDragCoordinate = nil + } else if let feature = dragFeature, + let id = feature.identifier, + let previous = previousDragCoordinate, + let origin = originDragCoordinate + { + print("in drag") + channel?.invokeMethod("feature#onDrag", arguments: [ + "id": id, + "x": point.x, + "y": point.y, + "originLng": origin.longitude, + "originLat": origin.latitude, + "currentLng": coordinate.longitude, + "currentLat": coordinate.latitude, + "deltaLng": coordinate.longitude - previous.longitude, + "deltaLat": coordinate.latitude - previous.latitude, + ]) + previousDragCoordinate = coordinate + } + } + /* * UILongPressGestureRecognizer * After a long press invoke the map#onMapLongClick callback. @@ -1559,6 +1632,7 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma func setScrollGesturesEnabled(scrollGesturesEnabled: Bool) { mapView.allowsScrolling = scrollGesturesEnabled + scrollingEnabled = scrollGesturesEnabled } func setTiltGesturesEnabled(tiltGesturesEnabled: Bool) { diff --git a/mapbox_gl_platform_interface/lib/src/method_channel_mapbox_gl.dart b/mapbox_gl_platform_interface/lib/src/method_channel_mapbox_gl.dart index 7bd89eaff..686da1a97 100644 --- a/mapbox_gl_platform_interface/lib/src/method_channel_mapbox_gl.dart +++ b/mapbox_gl_platform_interface/lib/src/method_channel_mapbox_gl.dart @@ -47,6 +47,28 @@ class MethodChannelMapboxGl extends MapboxGlPlatform { 'latLng': LatLng(lat, lng) }); break; + case 'feature#onDrag': + final id = call.arguments['id']; + final double x = call.arguments['x']; + final double y = call.arguments['y']; + final double originLat = call.arguments['originLat']; + final double originLng = call.arguments['originLng']; + + final double currentLat = call.arguments['currentLat']; + final double currentLng = call.arguments['currentLng']; + + final double deltaLat = call.arguments['deltaLat']; + final double deltaLng = call.arguments['deltaLng']; + + onFeatureDraggedPlatform({ + 'id': id, + 'point': Point(x, y), + 'origin': LatLng(originLat, originLng), + 'current': LatLng(currentLat, currentLng), + 'delta': LatLng(deltaLat, deltaLng), + }); + break; + case 'camera#onMoveStarted': onCameraMoveStartedPlatform(null); break; From abb5d7b391af1b790f5fb3f23df0384fd7520610 Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Thu, 16 Dec 2021 19:26:48 +0100 Subject: [PATCH 04/26] added other annotation managers --- lib/src/annotation.dart | 61 +++++++++++++++++++ .../lib/src/annotation.dart | 1 - .../lib/src/circle.dart | 44 ++++++++++++- .../lib/src/fill.dart | 59 +++++++++++++++--- .../lib/src/line.dart | 23 ++----- .../lib/src/symbol.dart | 44 ++++++++++++- 6 files changed, 200 insertions(+), 32 deletions(-) diff --git a/lib/src/annotation.dart b/lib/src/annotation.dart index 33dfd2d40..7abc5d276 100644 --- a/lib/src/annotation.dart +++ b/lib/src/annotation.dart @@ -87,3 +87,64 @@ class LineManager extends _AnnotationManager { lineBlur: [Expressions.get, 'lineBlur'], ); } + +class FillManager extends _AnnotationManager { + FillManager(MapboxMapController controller, {void Function(Fill)? onTap}) + : super(controller, onTap: onTap); + @override + LayerProperties get properties => const FillLayerProperties( + fillOpacity: [Expressions.get, 'fillOpacity'], + fillColor: [Expressions.get, 'fillColor'], + fillOutlineColor: [Expressions.get, 'fillOutlineColor'], + fillPattern: [Expressions.get, 'fillPattern'], + ); +} + +class CircleManager extends _AnnotationManager { + CircleManager(MapboxMapController controller, {void Function(Circle)? onTap}) + : super(controller, onTap: onTap); + @override + LayerProperties get properties => const CircleLayerProperties( + circleRadius: [Expressions.get, 'circleRadius'], + circleColor: [Expressions.get, 'circleColor'], + circleBlur: [Expressions.get, 'circleBlur'], + circleOpacity: [Expressions.get, 'circleOpacity'], + circleStrokeWidth: [Expressions.get, 'circleStrokeWidth'], + circleStrokeColor: [Expressions.get, 'circleStrokeColor'], + circleStrokeOpacity: [Expressions.get, 'circleStrokeOpacity'], + ); +} + +class SymbolManager extends _AnnotationManager { + SymbolManager(MapboxMapController controller, {void Function(Symbol)? onTap}) + : super(controller, onTap: onTap); + @override + LayerProperties get properties => const SymbolLayerProperties( + iconSize: [Expressions.get, 'iconSize'], + iconImage: [Expressions.get, 'iconImage'], + iconRotate: [Expressions.get, 'iconRotate'], + iconOffset: [Expressions.get, 'iconOffset'], + iconAnchor: [Expressions.get, 'iconAnchor'], + textFont: [Expressions.get, 'fontNames'], + textField: [Expressions.get, 'textField'], + textSize: [Expressions.get, 'textSize'], + textMaxWidth: [Expressions.get, 'textMaxWidth'], + textLetterSpacing: [Expressions.get, 'textLetterSpacing'], + textJustify: [Expressions.get, 'textJustify'], + textAnchor: [Expressions.get, 'textAnchor'], + textRotate: [Expressions.get, 'textRotate'], + textTransform: [Expressions.get, 'textTransform'], + textOffset: [Expressions.get, 'textOffset'], + iconOpacity: [Expressions.get, 'iconOpacity'], + iconColor: [Expressions.get, 'iconColor'], + iconHaloColor: [Expressions.get, 'iconHaloColor'], + iconHaloWidth: [Expressions.get, 'iconHaloWidth'], + iconHaloBlur: [Expressions.get, 'iconHaloBlur'], + textOpacity: [Expressions.get, 'textOpacity'], + textColor: [Expressions.get, 'textColor'], + textHaloColor: [Expressions.get, 'textHaloColor'], + textHaloWidth: [Expressions.get, 'textHaloWidth'], + textHaloBlur: [Expressions.get, 'textHaloBlur'], + symbolZOrder: [Expressions.get, 'zIndex'], + ); +} diff --git a/mapbox_gl_platform_interface/lib/src/annotation.dart b/mapbox_gl_platform_interface/lib/src/annotation.dart index 9f2d4d614..99c2c5c76 100644 --- a/mapbox_gl_platform_interface/lib/src/annotation.dart +++ b/mapbox_gl_platform_interface/lib/src/annotation.dart @@ -5,5 +5,4 @@ abstract class Annotation { Map toGeoJson(); Annotation translate(LatLng delta); - bool get draggable; } diff --git a/mapbox_gl_platform_interface/lib/src/circle.dart b/mapbox_gl_platform_interface/lib/src/circle.dart index a75a0217e..47fc71755 100644 --- a/mapbox_gl_platform_interface/lib/src/circle.dart +++ b/mapbox_gl_platform_interface/lib/src/circle.dart @@ -6,7 +6,7 @@ part of mapbox_gl_platform_interface; -class Circle { +class Circle implements Annotation { Circle(this._id, this.options, [this._data]); /// A unique identifier for this circle. @@ -24,6 +24,31 @@ class Circle { /// The returned value does not reflect any changes made to the circle through /// touch events. Add listeners to the owning map controller to track those. CircleOptions options; + + Circle copyWith({String? id, Map? data, CircleOptions? options}) { + return Circle( + id ?? this.id, + options ?? this.options, + data ?? this.data, + ); + } + + @override + Map toGeoJson() { + final geojson = options.toGeoJson(); + geojson["id"] = id; + geojson["properties"]["id"] = id; + + return geojson; + } + + @override + Annotation translate(LatLng delta) { + final options = this + .options + .copyWith(CircleOptions(geometry: this.options.geometry! + delta)); + return copyWith(options: options); + } } /// Configuration options for [Circle] instances. @@ -73,7 +98,7 @@ class CircleOptions { ); } - dynamic toJson() { + dynamic toJson([bool addGeometry = true]) { final Map json = {}; void addIfPresent(String fieldName, dynamic value) { @@ -89,8 +114,21 @@ class CircleOptions { addIfPresent('circleStrokeWidth', circleStrokeWidth); addIfPresent('circleStrokeColor', circleStrokeColor); addIfPresent('circleStrokeOpacity', circleStrokeOpacity); - addIfPresent('geometry', geometry?.toJson()); + if (addGeometry) { + addIfPresent('geometry', geometry?.toJson()); + } addIfPresent('draggable', draggable); return json; } + + Map toGeoJson() { + return { + "type": "Feature", + "properties": toJson(false), + "geometry": { + "type": "LineString", + if (geometry != null) "coordinates": geometry!.toJson() + } + }; + } } diff --git a/mapbox_gl_platform_interface/lib/src/fill.dart b/mapbox_gl_platform_interface/lib/src/fill.dart index 15c966551..15570e790 100644 --- a/mapbox_gl_platform_interface/lib/src/fill.dart +++ b/mapbox_gl_platform_interface/lib/src/fill.dart @@ -21,7 +21,7 @@ FillOptions translateFillOptions(FillOptions options, LatLng delta) { return options; } -class Fill { +class Fill implements Annotation { Fill(this._id, this.options, [this._data]); /// A unique identifier for this fill. @@ -39,6 +39,32 @@ class Fill { /// The returned value does not reflect any changes made to the fill through /// touch events. Add listeners to the owning map controller to track those. FillOptions options; + + Fill copyWith({String? id, Map? data, FillOptions? options}) { + return Fill( + id ?? this.id, + options ?? this.options, + data ?? this.data, + ); + } + + @override + // TODO: implement draggable + bool get draggable => throw UnimplementedError(); + + @override + Map toGeoJson() { + final geojson = options.toGeoJson(); + geojson["id"] = id; + geojson["properties"]["id"] = id; + + return geojson; + } + + @override + Annotation translate(LatLng delta) { + return copyWith(options: translateFillOptions(options, delta)); + } } /// Configuration options for [Fill] instances. @@ -78,7 +104,7 @@ class FillOptions { ); } - dynamic toJson() { + dynamic toJson([bool addGeometry = true]) { final Map json = {}; void addIfPresent(String fieldName, dynamic value) { @@ -91,13 +117,30 @@ class FillOptions { addIfPresent('fillColor', fillColor); addIfPresent('fillOutlineColor', fillOutlineColor); addIfPresent('fillPattern', fillPattern); - addIfPresent( - 'geometry', - geometry - ?.map((List latLngList) => - latLngList.map((LatLng latLng) => latLng.toJson()).toList()) - .toList()); + if (addGeometry) { + addIfPresent( + 'geometry', + geometry + ?.map((List latLngList) => + latLngList.map((LatLng latLng) => latLng.toJson()).toList()) + .toList()); + } addIfPresent('draggable', draggable); return json; } + + Map toGeoJson() { + return { + "type": "Feature", + "properties": toJson(false), + "geometry": { + "type": "LineString", + if (geometry != null) + "coordinates": geometry + ?.map((List latLngList) => + latLngList.map((LatLng latLng) => latLng.toJson()).toList()) + .toList() + } + }; + } } diff --git a/mapbox_gl_platform_interface/lib/src/line.dart b/mapbox_gl_platform_interface/lib/src/line.dart index 583ed79f3..958e286cc 100644 --- a/mapbox_gl_platform_interface/lib/src/line.dart +++ b/mapbox_gl_platform_interface/lib/src/line.dart @@ -49,9 +49,6 @@ class Line implements Annotation { geometry: this.options.geometry?.map((e) => e + delta).toList())); return copyWith(options: options); } - - @override - bool get draggable => options.draggable ?? false; } /// Configuration options for [Line] instances. @@ -104,7 +101,7 @@ class LineOptions { ); } - dynamic toJson() { + dynamic toJson([bool addGeometry = true]) { final Map json = {}; void addIfPresent(String fieldName, dynamic value) { @@ -121,8 +118,10 @@ class LineOptions { addIfPresent('lineOffset', lineOffset); addIfPresent('lineBlur', lineBlur); addIfPresent('linePattern', linePattern); - addIfPresent( - 'geometry', geometry?.map((LatLng latLng) => latLng.toJson()).toList()); + if (addGeometry) { + addIfPresent('geometry', + geometry?.map((LatLng latLng) => latLng.toJson()).toList()); + } addIfPresent('draggable', draggable); return json; } @@ -130,17 +129,7 @@ class LineOptions { Map toGeoJson() { return { "type": "Feature", - "properties": { - if (lineJoin != null) "lineJoin": lineJoin, - if (lineOpacity != null) "lineOpacity": lineOpacity, - if (lineColor != null) "lineColor": lineColor, - if (lineWidth != null) "lineWidth": lineWidth, - if (lineGapWidth != null) "lineGapWidth": lineGapWidth, - if (lineOffset != null) "lineOffset": lineOffset, - if (lineBlur != null) "lineBlur": lineBlur, - if (linePattern != null) "linePattern": linePattern, - "draggable": draggable ?? false, - }, + "properties": toJson(false), "geometry": { "type": "LineString", if (geometry != null) diff --git a/mapbox_gl_platform_interface/lib/src/symbol.dart b/mapbox_gl_platform_interface/lib/src/symbol.dart index 87eaa79b5..023cb2842 100644 --- a/mapbox_gl_platform_interface/lib/src/symbol.dart +++ b/mapbox_gl_platform_interface/lib/src/symbol.dart @@ -6,7 +6,7 @@ part of mapbox_gl_platform_interface; -class Symbol { +class Symbol implements Annotation { Symbol(this._id, this.options, [this._data]); /// A unique identifier for this symbol. @@ -25,6 +25,31 @@ class Symbol { /// The returned value does not reflect any changes made to the symbol through /// touch events. Add listeners to the owning map controller to track those. SymbolOptions options; + + Symbol copyWith({String? id, Map? data, SymbolOptions? options}) { + return Symbol( + id ?? this.id, + options ?? this.options, + data ?? this.data, + ); + } + + @override + Map toGeoJson() { + final geojson = options.toGeoJson(); + geojson["id"] = id; + geojson["properties"]["id"] = id; + + return geojson; + } + + @override + Annotation translate(LatLng delta) { + final options = this + .options + .copyWith(SymbolOptions(geometry: this.options.geometry! + delta)); + return copyWith(options: options); + } } dynamic _offsetToJson(Offset? offset) { @@ -138,7 +163,7 @@ class SymbolOptions { ); } - dynamic toJson() { + dynamic toJson([bool addGeometry = true]) { final Map json = {}; void addIfPresent(String fieldName, dynamic value) { @@ -172,9 +197,22 @@ class SymbolOptions { addIfPresent('textHaloColor', textHaloColor); addIfPresent('textHaloWidth', textHaloWidth); addIfPresent('textHaloBlur', textHaloBlur); - addIfPresent('geometry', geometry?.toJson()); + if (addGeometry) { + addIfPresent('geometry', geometry?.toJson()); + } addIfPresent('zIndex', zIndex); addIfPresent('draggable', draggable); return json; } + + Map toGeoJson() { + return { + "type": "Feature", + "properties": toJson(false), + "geometry": { + "type": "LineString", + if (geometry != null) "coordinates": geometry!.toJson() + } + }; + } } From b362dd51a65936f0a3925b130fb3b09a91c7eae0 Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Thu, 16 Dec 2021 20:39:00 +0100 Subject: [PATCH 05/26] support old api with new managers --- lib/src/annotation.dart | 13 +- lib/src/controller.dart | 220 +++++++-------- lib/src/mapbox_map.dart | 1 + .../lib/src/mapbox_gl_platform_interface.dart | 96 ------- .../lib/src/method_channel_mapbox_gl.dart | 254 +----------------- .../lib/src/mapbox_map_controller.dart | 158 +---------- 6 files changed, 104 insertions(+), 638 deletions(-) diff --git a/lib/src/annotation.dart b/lib/src/annotation.dart index 7abc5d276..ffcf61929 100644 --- a/lib/src/annotation.dart +++ b/lib/src/annotation.dart @@ -1,6 +1,6 @@ part of mapbox_gl; -abstract class _AnnotationManager { +abstract class AnnotationManager { final MapboxMapController controller; final void Function(T)? onTap; final _idToAnnotation = {}; @@ -9,7 +9,7 @@ abstract class _AnnotationManager { T? byId(String id) => _idToAnnotation[id]; - _AnnotationManager(this.controller, {this.onTap}) : id = getRandomString(10) { + AnnotationManager(this.controller, {this.onTap}) : id = getRandomString(10) { controller.addGeoJsonSource(id, buildFeatureCollection([]), promoteId: "id"); controller.addLayer(id, id, properties); @@ -32,6 +32,7 @@ abstract class _AnnotationManager { [for (final l in _idToAnnotation.values) l.toGeoJson()])); } + @override Future addAll(Iterable annotations) async { for (var a in annotations) { _idToAnnotation[a.id] = a; @@ -74,7 +75,7 @@ abstract class _AnnotationManager { } } -class LineManager extends _AnnotationManager { +class LineManager extends AnnotationManager { LineManager(MapboxMapController controller, {void Function(Line)? onTap}) : super(controller, onTap: onTap); @override @@ -88,7 +89,7 @@ class LineManager extends _AnnotationManager { ); } -class FillManager extends _AnnotationManager { +class FillManager extends AnnotationManager { FillManager(MapboxMapController controller, {void Function(Fill)? onTap}) : super(controller, onTap: onTap); @override @@ -100,7 +101,7 @@ class FillManager extends _AnnotationManager { ); } -class CircleManager extends _AnnotationManager { +class CircleManager extends AnnotationManager { CircleManager(MapboxMapController controller, {void Function(Circle)? onTap}) : super(controller, onTap: onTap); @override @@ -115,7 +116,7 @@ class CircleManager extends _AnnotationManager { ); } -class SymbolManager extends _AnnotationManager { +class SymbolManager extends AnnotationManager { SymbolManager(MapboxMapController controller, {void Function(Symbol)? onTap}) : super(controller, onTap: onTap); @override diff --git a/lib/src/controller.dart b/lib/src/controller.dart index be8ffdff3..c9f93da54 100644 --- a/lib/src/controller.dart +++ b/lib/src/controller.dart @@ -49,6 +49,7 @@ class MapboxMapController extends ChangeNotifier { MapboxMapController({ required MapboxGlPlatform mapboxGlPlatform, required CameraPosition initialCameraPosition, + required Iterable annotationOrder, this.onStyleLoadedCallback, this.onMapClick, this.onMapLongClick, @@ -60,6 +61,23 @@ class MapboxMapController extends ChangeNotifier { this.onCameraIdle, }) : _mapboxGlPlatform = mapboxGlPlatform { _cameraPosition = initialCameraPosition; + for (var type in annotationOrder.toSet()) { + switch (type) { + case AnnotationType.fill: + fillManager = FillManager(this, onTap: onFillTapped); + break; + case AnnotationType.line: + lineManager = LineManager(this, onTap: onLineTapped); + break; + case AnnotationType.circle: + circleManager = CircleManager(this, onTap: onCircleTapped); + break; + case AnnotationType.symbol: + symbolManager = SymbolManager(this, onTap: onSymbolTapped); + break; + default: + } + } _mapboxGlPlatform.onInfoWindowTappedPlatform.add((symbolId) { final symbol = _symbols[symbolId]; @@ -68,34 +86,6 @@ class MapboxMapController extends ChangeNotifier { } }); - _mapboxGlPlatform.onSymbolTappedPlatform.add((symbolId) { - final symbol = _symbols[symbolId]; - if (symbol != null) { - onSymbolTapped(symbol); - } - }); - - _mapboxGlPlatform.onLineTappedPlatform.add((lineId) { - final line = _lines[lineId]; - if (line != null) { - onLineTapped(line); - } - }); - - _mapboxGlPlatform.onCircleTappedPlatform.add((circleId) { - final circle = _circles[circleId]; - if (circle != null) { - onCircleTapped(circle); - } - }); - - _mapboxGlPlatform.onFillTappedPlatform.add((fillId) { - final fill = _fills[fillId]; - if (fill != null) { - onFillTapped(fill); - } - }); - _mapboxGlPlatform.onFeatureTappedPlatform.add((payload) { for (final fun in List.from(onFeatureTapped)) { @@ -180,6 +170,11 @@ class MapboxMapController extends ChangeNotifier { }); } + FillManager? fillManager; + LineManager? lineManager; + CircleManager? circleManager; + SymbolManager? symbolManager; + final OnStyleLoadedCallback? onStyleLoadedCallback; final OnMapClickCallback? onMapClick; final OnMapLongClickCallback? onMapLongClick; @@ -507,10 +502,11 @@ class MapboxMapController extends ChangeNotifier { /// The returned [Future] completes with the added symbol once listeners have /// been notified. Future addSymbol(SymbolOptions options, [Map? data]) async { - List result = - await addSymbols([options], data != null ? [data] : []); - - return result.first; + final effectiveOptions = SymbolOptions.defaultOptions.copyWith(options); + final symbol = Symbol(getRandomString(), effectiveOptions, data); + await symbolManager!.add(symbol); + notifyListeners(); + return symbol; } /// Adds multiple symbols to the map, configured using the specified custom @@ -523,11 +519,13 @@ class MapboxMapController extends ChangeNotifier { /// been notified. Future> addSymbols(List options, [List? data]) async { - final List effectiveOptions = - options.map((o) => SymbolOptions.defaultOptions.copyWith(o)).toList(); + final symbols = [ + for (var i = 0; i < options.length; i++) + Symbol(getRandomString(), + SymbolOptions.defaultOptions.copyWith(options[i]), data?[i]) + ]; + await symbolManager!.addAll(symbols); - final symbols = await _mapboxGlPlatform.addSymbols(effectiveOptions, data); - symbols.forEach((s) => _symbols[s.id] = s); notifyListeners(); return symbols; } @@ -540,10 +538,8 @@ class MapboxMapController extends ChangeNotifier { /// /// The returned [Future] completes once listeners have been notified. Future updateSymbol(Symbol symbol, SymbolOptions changes) async { - assert(_symbols[symbol.id] == symbol); + await symbolManager!.set(symbol.copyWith(options: changes)); - await _mapboxGlPlatform.updateSymbol(symbol, changes); - symbol.options = symbol.options.copyWith(changes); notifyListeners(); } @@ -551,10 +547,7 @@ class MapboxMapController extends ChangeNotifier { /// This may be different from the value of `symbol.options.geometry` if the symbol is draggable. /// In that case this method provides the symbol's actual position, and `symbol.options.geometry` the last programmatically set position. Future getSymbolLatLng(Symbol symbol) async { - assert(_symbols[symbol.id] == symbol); - final symbolLatLng = await _mapboxGlPlatform.getSymbolLatLng(symbol); - notifyListeners(); - return symbolLatLng; + return symbol.options.geometry!; } /// Removes the specified [symbol] from the map. The symbol must be a current @@ -565,8 +558,7 @@ class MapboxMapController extends ChangeNotifier { /// /// The returned [Future] completes once listeners have been notified. Future removeSymbol(Symbol symbol) async { - assert(_symbols[symbol.id] == symbol); - await _removeSymbols([symbol.id]); + await symbolManager!.remove(symbol); notifyListeners(); } @@ -578,10 +570,9 @@ class MapboxMapController extends ChangeNotifier { /// /// The returned [Future] completes once listeners have been notified. Future removeSymbols(Iterable symbols) async { - final ids = symbols.where((s) => _symbols[s.id] == s).map((s) => s.id); - assert(symbols.length == ids.length); - - await _removeSymbols(ids); + for (var symbol in symbols) { + await symbolManager!.remove(symbol); + } notifyListeners(); } @@ -592,21 +583,10 @@ class MapboxMapController extends ChangeNotifier { /// /// The returned [Future] completes once listeners have been notified. Future clearSymbols() async { - await _mapboxGlPlatform.removeSymbols(_symbols.keys); - _symbols.clear(); + symbolManager!.clear(); notifyListeners(); } - /// Helper method to remove a single symbol from the map. Consumed by - /// [removeSymbol] and [clearSymbols]. - /// - /// The returned [Future] completes once the symbol has been removed from - /// [_symbols]. - Future _removeSymbols(Iterable ids) async { - await _mapboxGlPlatform.removeSymbols(ids); - _symbols.removeWhere((k, s) => ids.contains(k)); - } - /// Adds a line to the map, configured using the specified custom [options]. /// /// Change listeners are notified once the line has been added on the @@ -615,10 +595,9 @@ class MapboxMapController extends ChangeNotifier { /// The returned [Future] completes with the added line once listeners have /// been notified. Future addLine(LineOptions options, [Map? data]) async { - final LineOptions effectiveOptions = - LineOptions.defaultOptions.copyWith(options); - final line = await _mapboxGlPlatform.addLine(effectiveOptions, data); - _lines[line.id] = line; + final effectiveOptions = LineOptions.defaultOptions.copyWith(options); + final line = Line(getRandomString(), effectiveOptions, data); + await lineManager!.add(line); notifyListeners(); return line; } @@ -632,8 +611,13 @@ class MapboxMapController extends ChangeNotifier { /// been notified. Future> addLines(List options, [List? data]) async { - final lines = await _mapboxGlPlatform.addLines(options, data); - lines.forEach((l) => _lines[l.id] = l); + final lines = [ + for (var i = 0; i < options.length; i++) + Line(getRandomString(), LineOptions.defaultOptions.copyWith(options[i]), + data?[i]) + ]; + await lineManager!.addAll(lines); + notifyListeners(); return lines; } @@ -646,9 +630,8 @@ class MapboxMapController extends ChangeNotifier { /// /// The returned [Future] completes once listeners have been notified. Future updateLine(Line line, LineOptions changes) async { - assert(_lines[line.id] == line); - await _mapboxGlPlatform.updateLine(line, changes); - _lines[line.id] = line.copyWith(options: line.options.copyWith(changes)); + await lineManager!.set(line.copyWith(options: changes)); + notifyListeners(); } @@ -656,10 +639,7 @@ class MapboxMapController extends ChangeNotifier { /// This may be different from the value of `line.options.geometry` if the line is draggable. /// In that case this method provides the line's actual position, and `line.options.geometry` the last programmatically set position. Future> getLineLatLngs(Line line) async { - assert(_lines[line.id] == line); - final lineLatLngs = await _mapboxGlPlatform.getLineLatLngs(line); - notifyListeners(); - return lineLatLngs; + return line.options.geometry!; } /// Removes the specified [line] from the map. The line must be a current @@ -670,10 +650,7 @@ class MapboxMapController extends ChangeNotifier { /// /// The returned [Future] completes once listeners have been notified. Future removeLine(Line line) async { - assert(_lines[line.id] == line); - - await _mapboxGlPlatform.removeLine(line.id); - _lines.remove(line.id); + await lineManager!.remove(line); notifyListeners(); } @@ -685,11 +662,10 @@ class MapboxMapController extends ChangeNotifier { /// /// The returned [Future] completes once listeners have been notified. Future removeLines(Iterable lines) async { - final ids = lines.where((l) => _lines[l.id] == l).map((l) => l.id); - assert(lines.length == ids.length); + for (var line in lines) { + await lineManager!.remove(line); + } - await _mapboxGlPlatform.removeLines(ids); - ids.forEach((id) => _lines.remove(id)); notifyListeners(); } @@ -700,9 +676,7 @@ class MapboxMapController extends ChangeNotifier { /// /// The returned [Future] completes once listeners have been notified. Future clearLines() async { - final List lineIds = List.from(_lines.keys); - await _mapboxGlPlatform.removeLines(lineIds); - _lines.clear(); + await lineManager!.clear(); notifyListeners(); } @@ -716,8 +690,8 @@ class MapboxMapController extends ChangeNotifier { Future addCircle(CircleOptions options, [Map? data]) async { final CircleOptions effectiveOptions = CircleOptions.defaultOptions.copyWith(options); - final circle = await _mapboxGlPlatform.addCircle(effectiveOptions, data); - _circles[circle.id] = circle; + final circle = Circle(getRandomString(), effectiveOptions, data); + await circleManager!.add(circle); notifyListeners(); return circle; } @@ -732,10 +706,15 @@ class MapboxMapController extends ChangeNotifier { /// been notified. Future> addCircles(List options, [List? data]) async { - final circles = await _mapboxGlPlatform.addCircles(options, data); - circles.forEach((c) => _circles[c.id] = c); + final cricles = [ + for (var i = 0; i < options.length; i++) + Circle(getRandomString(), + CircleOptions.defaultOptions.copyWith(options[i]), data?[i]) + ]; + await circleManager!.addAll(cricles); + notifyListeners(); - return circles; + return cricles; } /// Updates the specified [circle] with the given [changes]. The circle must @@ -746,9 +725,8 @@ class MapboxMapController extends ChangeNotifier { /// /// The returned [Future] completes once listeners have been notified. Future updateCircle(Circle circle, CircleOptions changes) async { - assert(_circles[circle.id] == circle); - await _mapboxGlPlatform.updateCircle(circle, changes); - circle.options = circle.options.copyWith(changes); + await circleManager!.set(circle.copyWith(options: changes)); + notifyListeners(); } @@ -756,10 +734,7 @@ class MapboxMapController extends ChangeNotifier { /// This may be different from the value of `circle.options.geometry` if the circle is draggable. /// In that case this method provides the circle's actual position, and `circle.options.geometry` the last programmatically set position. Future getCircleLatLng(Circle circle) async { - assert(_circles[circle.id] == circle); - final circleLatLng = await _mapboxGlPlatform.getCircleLatLng(circle); - notifyListeners(); - return circleLatLng; + return circle.options.geometry!; } /// Removes the specified [circle] from the map. The circle must be a current @@ -770,10 +745,7 @@ class MapboxMapController extends ChangeNotifier { /// /// The returned [Future] completes once listeners have been notified. Future removeCircle(Circle circle) async { - assert(_circles[circle.id] == circle); - - await _mapboxGlPlatform.removeCircle(circle.id); - _circles.remove(circle.id); + circleManager!.remove(circle); notifyListeners(); } @@ -786,11 +758,9 @@ class MapboxMapController extends ChangeNotifier { /// /// The returned [Future] completes once listeners have been notified. Future removeCircles(Iterable circles) async { - final ids = circles.where((c) => _circles[c.id] == c).map((c) => c.id); - assert(circles.length == ids.length); - - await _mapboxGlPlatform.removeCircles(ids); - ids.forEach((id) => _circles.remove(id)); + for (var circle in circles) { + await circleManager!.remove(circle); + } notifyListeners(); } @@ -801,8 +771,7 @@ class MapboxMapController extends ChangeNotifier { /// /// The returned [Future] completes once listeners have been notified. Future clearCircles() async { - await _mapboxGlPlatform.removeCircles(_circles.keys); - _circles.clear(); + circleManager!.clear(); notifyListeners(); } @@ -817,8 +786,8 @@ class MapboxMapController extends ChangeNotifier { Future addFill(FillOptions options, [Map? data]) async { final FillOptions effectiveOptions = FillOptions.defaultOptions.copyWith(options); - final fill = await _mapboxGlPlatform.addFill(effectiveOptions, data); - _fills[fill.id] = fill; + final fill = Fill(getRandomString(), effectiveOptions, data); + await fillManager!.add(fill); notifyListeners(); return fill; } @@ -833,10 +802,15 @@ class MapboxMapController extends ChangeNotifier { /// been notified. Future> addFills(List options, [List? data]) async { - final circles = await _mapboxGlPlatform.addFills(options, data); - circles.forEach((f) => _fills[f.id] = f); + final fills = [ + for (var i = 0; i < options.length; i++) + Fill(getRandomString(), FillOptions.defaultOptions.copyWith(options[i]), + data?[i]) + ]; + await fillManager!.addAll(fills); + notifyListeners(); - return circles; + return fills; } /// Updates the specified [fill] with the given [changes]. The fill must @@ -847,9 +821,8 @@ class MapboxMapController extends ChangeNotifier { /// /// The returned [Future] completes once listeners have been notified. Future updateFill(Fill fill, FillOptions changes) async { - assert(_fills[fill.id] == fill); - await _mapboxGlPlatform.updateFill(fill, changes); - fill.options = fill.options.copyWith(changes); + await fillManager!.set(fill.copyWith(options: changes)); + notifyListeners(); } @@ -860,8 +833,7 @@ class MapboxMapController extends ChangeNotifier { /// /// The returned [Future] completes once listeners have been notified. Future clearFills() async { - await _mapboxGlPlatform.removeFills(_fills.keys); - _fills.clear(); + await fillManager!.clear(); notifyListeners(); } @@ -874,10 +846,7 @@ class MapboxMapController extends ChangeNotifier { /// /// The returned [Future] completes once listeners have been notified. Future removeFill(Fill fill) async { - assert(_fills[fill.id] == fill); - await _mapboxGlPlatform.removeFill(fill.id); - _fills.remove(fill.id); - + await fillManager!.remove(fill); notifyListeners(); } @@ -889,11 +858,10 @@ class MapboxMapController extends ChangeNotifier { /// /// The returned [Future] completes once listeners have been notified. Future removeFills(Iterable fills) async { - final ids = fills.where((f) => _fills[f.id] == f).map((f) => f.id); - assert(fills.length == ids.length); + for (var fill in fills) { + await fillManager!.remove(fill); + } - await _mapboxGlPlatform.removeFills(ids); - ids.forEach((id) => _fills.remove(id)); notifyListeners(); } diff --git a/lib/src/mapbox_map.dart b/lib/src/mapbox_map.dart index ce11c2a1e..6b0819dce 100644 --- a/lib/src/mapbox_map.dart +++ b/lib/src/mapbox_map.dart @@ -299,6 +299,7 @@ class _MapboxMapState extends State { onCameraTrackingChanged: widget.onCameraTrackingChanged, onCameraIdle: widget.onCameraIdle, onMapIdle: widget.onMapIdle, + annotationOrder: widget.annotationOrder, ); await _mapboxGlPlatform.initPlatform(id); _controller.complete(controller); diff --git a/mapbox_gl_platform_interface/lib/src/mapbox_gl_platform_interface.dart b/mapbox_gl_platform_interface/lib/src/mapbox_gl_platform_interface.dart index 957022dde..1c5c9c799 100644 --- a/mapbox_gl_platform_interface/lib/src/mapbox_gl_platform_interface.dart +++ b/mapbox_gl_platform_interface/lib/src/mapbox_gl_platform_interface.dart @@ -16,14 +16,6 @@ abstract class MapboxGlPlatform { final onInfoWindowTappedPlatform = ArgumentCallbacks(); - final onSymbolTappedPlatform = ArgumentCallbacks(); - - final onLineTappedPlatform = ArgumentCallbacks(); - - final onCircleTappedPlatform = ArgumentCallbacks(); - - final onFillTappedPlatform = ArgumentCallbacks(); - final onFeatureTappedPlatform = ArgumentCallbacks>(); final onFeatureDraggedPlatform = ArgumentCallbacks>(); @@ -104,94 +96,6 @@ abstract class MapboxGlPlatform { throw UnimplementedError('getTelemetryEnabled() has not been implemented.'); } - Future> addSymbols(List options, - [List? data]) async { - throw UnimplementedError('addSymbols() has not been implemented.'); - } - - Future updateSymbol(Symbol symbol, SymbolOptions changes) async { - throw UnimplementedError('updateSymbol() has not been implemented.'); - } - - Future removeSymbols(Iterable symbolsIds) async { - throw UnimplementedError('removeSymbol() has not been implemented.'); - } - - Future addLine(LineOptions options, [Map? data]) async { - throw UnimplementedError('addLine() has not been implemented.'); - } - - Future> addLines(List options, - [List? data]) async { - throw UnimplementedError('addLines() has not been implemented.'); - } - - Future updateLine(Line line, LineOptions changes) async { - throw UnimplementedError('updateLine() has not been implemented.'); - } - - Future removeLine(String lineId) async { - throw UnimplementedError('removeLine() has not been implemented.'); - } - - Future removeLines(Iterable ids) async { - throw UnimplementedError('removeLines() has not been implemented.'); - } - - Future addCircle(CircleOptions options, [Map? data]) async { - throw UnimplementedError('addCircle() has not been implemented.'); - } - - Future> addCircles(List options, - [List? data]) async { - throw UnimplementedError('addCircles() has not been implemented.'); - } - - Future updateCircle(Circle circle, CircleOptions changes) async { - throw UnimplementedError('updateCircle() has not been implemented.'); - } - - Future getCircleLatLng(Circle circle) async { - throw UnimplementedError('getCircleLatLng() has not been implemented.'); - } - - Future getSymbolLatLng(Symbol symbol) async { - throw UnimplementedError('getSymbolLatLng() has not been implemented.'); - } - - Future> getLineLatLngs(Line line) async { - throw UnimplementedError('getLineLatLngs() has not been implemented.'); - } - - Future removeCircle(String circleId) async { - throw UnimplementedError('removeCircle() has not been implemented.'); - } - - Future removeCircles(Iterable ids) async { - throw UnimplementedError('removeCircles() has not been implemented.'); - } - - Future addFill(FillOptions options, [Map? data]) async { - throw UnimplementedError('addFill() has not been implemented.'); - } - - Future> addFills(List options, - [List? data]) async { - throw UnimplementedError('addFills() has not been implemented.'); - } - - Future updateFill(Fill fill, FillOptions changes) async { - throw UnimplementedError('updateFill() has not been implemented.'); - } - - Future removeFill(String fillId) async { - throw UnimplementedError('removeFill() has not been implemented.'); - } - - Future removeFills(Iterable fillIds) async { - throw UnimplementedError('removeFills() has not been implemented.'); - } - Future queryRenderedFeatures( Point point, List layerIds, List? filter) async { throw UnimplementedError( diff --git a/mapbox_gl_platform_interface/lib/src/method_channel_mapbox_gl.dart b/mapbox_gl_platform_interface/lib/src/method_channel_mapbox_gl.dart index 686da1a97..e24cd1734 100644 --- a/mapbox_gl_platform_interface/lib/src/method_channel_mapbox_gl.dart +++ b/mapbox_gl_platform_interface/lib/src/method_channel_mapbox_gl.dart @@ -11,30 +11,7 @@ class MethodChannelMapboxGl extends MapboxGlPlatform { onInfoWindowTappedPlatform(symbolId); } break; - case 'symbol#onTap': - final String? symbolId = call.arguments['symbol']; - if (symbolId != null) { - onSymbolTappedPlatform(symbolId); - } - break; - case 'line#onTap': - final String? lineId = call.arguments['line']; - if (lineId != null) { - onLineTappedPlatform(lineId); - } - break; - case 'circle#onTap': - final String? circleId = call.arguments['circle']; - if (circleId != null) { - onCircleTappedPlatform(circleId); - } - break; - case 'fill#onTap': - final String? fillId = call.arguments['fill']; - if (fillId != null) { - onFillTappedPlatform(fillId); - } - break; + case 'feature#onTap': final id = call.arguments['id']; final double x = call.arguments['x']; @@ -253,235 +230,6 @@ class MethodChannelMapboxGl extends MapboxGlPlatform { return await _channel.invokeMethod('map#getTelemetryEnabled'); } - @override - Future> addSymbols(List options, - [List? data]) async { - final List symbolIds = await _channel.invokeMethod( - 'symbols#addAll', - { - 'options': options.map((o) => o.toJson()).toList(), - }, - ); - final List symbols = symbolIds - .asMap() - .map((i, id) => MapEntry( - i, - Symbol(id, options.elementAt(i), - data != null && data.length > i ? data.elementAt(i) : null))) - .values - .toList(); - - return symbols; - } - - @override - Future updateSymbol(Symbol symbol, SymbolOptions changes) async { - await _channel.invokeMethod('symbol#update', { - 'symbol': symbol.id, - 'options': changes.toJson(), - }); - } - - @override - Future getSymbolLatLng(Symbol symbol) async { - Map mapLatLng = - await _channel.invokeMethod('symbol#getGeometry', { - 'symbol': symbol._id, - }); - LatLng symbolLatLng = - new LatLng(mapLatLng['latitude'], mapLatLng['longitude']); - return symbolLatLng; - } - - @override - Future removeSymbols(Iterable ids) async { - await _channel.invokeMethod('symbols#removeAll', { - 'ids': ids.toList(), - }); - } - - @override - Future addLine(LineOptions options, [Map? data]) async { - final String lineId = await _channel.invokeMethod( - 'line#add', - { - 'options': options.toJson(), - }, - ); - return Line(lineId, options, data); - } - - @override - Future> addLines(List options, - [List? data]) async { - final List ids = await _channel.invokeMethod( - 'line#addAll', - { - 'options': options.map((o) => o.toJson()).toList(), - }, - ); - final List lines = ids - .asMap() - .map((i, id) => MapEntry( - i, - Line(id, options.elementAt(i), - data != null && data.length > i ? data.elementAt(i) : null))) - .values - .toList(); - - return lines; - } - - @override - Future updateLine(Line line, LineOptions changes) async { - await _channel.invokeMethod('line#update', { - 'line': line.id, - 'options': changes.toJson(), - }); - } - - @override - Future> getLineLatLngs(Line line) async { - List latLngList = - await _channel.invokeMethod('line#getGeometry', { - 'line': line._id, - }); - List resultList = []; - for (var latLng in latLngList) { - resultList.add(LatLng(latLng['latitude'], latLng['longitude'])); - } - return resultList; - } - - @override - Future removeLine(String lineId) async { - await _channel.invokeMethod('line#remove', { - 'line': lineId, - }); - } - - @override - Future removeLines(Iterable ids) async { - await _channel.invokeMethod('line#removeAll', { - 'ids': ids.toList(), - }); - } - - @override - Future addCircle(CircleOptions options, [Map? data]) async { - final String circleId = await _channel.invokeMethod( - 'circle#add', - { - 'options': options.toJson(), - }, - ); - return Circle(circleId, options, data); - } - - @override - Future> addCircles(List options, - [List? data]) async { - final List ids = await _channel.invokeMethod( - 'circle#addAll', - { - 'options': options.map((o) => o.toJson()).toList(), - }, - ); - return ids - .asMap() - .map((i, id) => MapEntry( - i, - Circle(id, options.elementAt(i), - data != null && data.length > i ? data.elementAt(i) : null))) - .values - .toList(); - } - - @override - Future updateCircle(Circle circle, CircleOptions changes) async { - await _channel.invokeMethod('circle#update', { - 'circle': circle.id, - 'options': changes.toJson(), - }); - } - - @override - Future getCircleLatLng(Circle circle) async { - Map mapLatLng = - await _channel.invokeMethod('circle#getGeometry', { - 'circle': circle.id, - }); - return LatLng(mapLatLng['latitude'], mapLatLng['longitude']); - } - - @override - Future removeCircle(String circleId) async { - await _channel.invokeMethod('circle#remove', { - 'circle': circleId, - }); - } - - @override - Future removeCircles(Iterable ids) async { - await _channel.invokeMethod('circle#removeAll', { - 'ids': ids.toList(), - }); - } - - @override - Future addFill(FillOptions options, [Map? data]) async { - final String fillId = await _channel.invokeMethod( - 'fill#add', - { - 'options': options.toJson(), - }, - ); - return Fill(fillId, options, data); - } - - @override - Future> addFills(List options, - [List? data]) async { - final List ids = await _channel.invokeMethod( - 'fill#addAll', - { - 'options': options.map((o) => o.toJson()).toList(), - }, - ); - final List fills = ids - .asMap() - .map((i, id) => MapEntry( - i, - Fill(id, options.elementAt(i), - data != null && data.length > i ? data.elementAt(i) : null))) - .values - .toList(); - - return fills; - } - - @override - Future updateFill(Fill fill, FillOptions changes) async { - await _channel.invokeMethod('fill#update', { - 'fill': fill.id, - 'options': changes.toJson(), - }); - } - - @override - Future removeFill(String fillId) async { - await _channel.invokeMethod('fill#remove', { - 'fill': fillId, - }); - } - - @override - Future removeFills(Iterable ids) async { - await _channel.invokeMethod('fill#removeAll', { - 'ids': ids.toList(), - }); - } - @override Future queryRenderedFeatures( Point point, List layerIds, List? filter) async { diff --git a/mapbox_gl_web/lib/src/mapbox_map_controller.dart b/mapbox_gl_web/lib/src/mapbox_map_controller.dart index 1d5995e77..83656ab34 100644 --- a/mapbox_gl_web/lib/src/mapbox_map_controller.dart +++ b/mapbox_gl_web/lib/src/mapbox_map_controller.dart @@ -188,142 +188,6 @@ class MapboxMapController extends MapboxGlPlatform return false; } - @override - Future> addSymbols(List options, - [List? data]) async { - Map optionsById = { - for (final o in options) - symbolManager.add(Feature( - geometry: Geometry( - type: 'Point', - coordinates: [o.geometry!.longitude, o.geometry!.latitude], - ), - )): o, - }; - symbolManager.updateAll(optionsById); - - return optionsById - .map((id, singleOptions) { - int dataIndex = options.indexOf(singleOptions); - Map? singleData = data != null && data.length >= dataIndex + 1 - ? data[dataIndex] - : null; - return MapEntry(id, Symbol(id, singleOptions, singleData)); - }) - .values - .toList(); - } - - @override - Future updateSymbol(Symbol symbol, SymbolOptions changes) async { - symbolManager.update(symbol.id, changes); - } - - @override - Future getSymbolLatLng(Symbol symbol) async { - var coordinates = symbolManager.getFeature(symbol.id)!.geometry.coordinates; - return LatLng(coordinates[1], coordinates[0]); - } - - @override - Future removeSymbols(Iterable symbolsIds) async { - symbolManager.removeAll(symbolsIds); - } - - @override - Future addLine(LineOptions options, [Map? data]) async { - String lineId = lineManager.add(Feature( - geometry: Geometry( - type: 'LineString', - coordinates: options.geometry! - .map((latLng) => [latLng.longitude, latLng.latitude]) - .toList(), - ), - )); - lineManager.update(lineId, options); - return Line(lineId, options, data); - } - - @override - Future updateLine(Line line, LineOptions changes) async { - lineManager.update(line.id, changes); - } - - @override - Future> getLineLatLngs(Line line) async { - List coordinates = - lineManager.getFeature(line.id)!.geometry.coordinates; - return coordinates.map((c) => LatLng(c[1], c[0])).toList(); - } - - @override - Future removeLine(String lineId) async { - lineManager.remove(lineId); - } - - @override - Future removeLines(Iterable ids) async { - lineManager.removeAll(ids); - } - - @override - Future addCircle(CircleOptions options, [Map? data]) async { - String circleId = circleManager.add(Feature( - geometry: Geometry( - type: 'Point', - coordinates: [options.geometry!.longitude, options.geometry!.latitude], - ), - )); - circleManager.update(circleId, options); - return Circle(circleId, options, data); - } - - @override - Future updateCircle(Circle circle, CircleOptions changes) async { - circleManager.update(circle.id, changes); - } - - @override - Future getCircleLatLng(Circle circle) async { - var coordinates = circleManager.getFeature(circle.id)!.geometry.coordinates; - return LatLng(coordinates[1], coordinates[0]); - } - - @override - Future removeCircle(String circleId) async { - circleManager.remove(circleId); - } - - @override - Future removeCircles(Iterable ids) async { - circleManager.removeAll(ids); - } - - Future addFill(FillOptions options, [Map? data]) async { - String fillId = fillManager.add(Feature( - geometry: Geometry( - type: 'Polygon', - coordinates: Convert.fillGeometryToFeatureGeometry(options.geometry!), - ), - )); - - fillManager.update(fillId, options); - return Fill(fillId, options, data); - } - - Future updateFill(Fill fill, FillOptions changes) async { - fillManager.update(fill.id, changes); - } - - Future removeFill(String fillId) async { - fillManager.remove(fillId); - } - - @override - Future removeFills(Iterable ids) async { - fillManager.removeAll(ids); - } - @override Future queryRenderedFeatures( Point point, List layerIds, List? filter) async { @@ -466,27 +330,7 @@ class MapboxMapController extends MapboxGlPlatform void _onStyleLoaded(_) { _mapReady = true; - for (final annotationType in annotationOrder) { - switch (annotationType) { - case 'AnnotationType.symbol': - symbolManager = - SymbolManager(map: _map, onTap: onSymbolTappedPlatform); - break; - case 'AnnotationType.line': - lineManager = LineManager(map: _map, onTap: onLineTappedPlatform); - break; - case 'AnnotationType.circle': - circleManager = - CircleManager(map: _map, onTap: onCircleTappedPlatform); - break; - case 'AnnotationType.fill': - fillManager = FillManager(map: _map, onTap: onFillTappedPlatform); - break; - default: - print( - "Unknown annotation type: \(annotationType), must be either 'fill', 'line', 'circle' or 'symbol'"); - } - } + onMapStyleLoadedPlatform(null); } From c8f02b51f4ff9e7356bfa4b4318c6856fc437600 Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Thu, 16 Dec 2021 20:39:15 +0100 Subject: [PATCH 06/26] ios remove annotations --- ios/Classes/Convert.swift | 227 ------------ ios/Classes/MapboxMapController.swift | 477 +------------------------- ios/Classes/Symbol.swift | 75 ---- ios/Classes/SymbolOptionsSink.swift | 31 -- 4 files changed, 2 insertions(+), 808 deletions(-) delete mode 100644 ios/Classes/Symbol.swift delete mode 100644 ios/Classes/SymbolOptionsSink.swift diff --git a/ios/Classes/Convert.swift b/ios/Classes/Convert.swift index b6113fa48..fb1a521c5 100644 --- a/ios/Classes/Convert.swift +++ b/ios/Classes/Convert.swift @@ -185,190 +185,6 @@ class Convert { ) } - class func interpretSymbolOptions(options: Any?, delegate: MGLSymbolStyleAnnotation) { - guard let options = options as? [String: Any] else { return } - if let iconSize = options["iconSize"] as? CGFloat { - delegate.iconScale = iconSize - } - if let iconImage = options["iconImage"] as? String { - delegate.iconImageName = iconImage - } - if let iconRotate = options["iconRotate"] as? CGFloat { - delegate.iconRotation = iconRotate - } - if let iconOffset = options["iconOffset"] as? [Double] { - delegate.iconOffset = CGVector(dx: iconOffset[0], dy: iconOffset[1]) - } - if let iconAnchorStr = options["iconAnchor"] as? String { - if let iconAnchor = Constants.symbolIconAnchorMapping[iconAnchorStr] { - delegate.iconAnchor = iconAnchor - } else { - delegate.iconAnchor = MGLIconAnchor.center - } - } - if let iconOpacity = options["iconOpacity"] as? CGFloat { - delegate.iconOpacity = iconOpacity - } - if let iconColor = options["iconColor"] as? String { - delegate.iconColor = UIColor(hexString: iconColor) ?? UIColor.black - } - if let iconHaloColor = options["iconHaloColor"] as? String { - delegate.iconHaloColor = UIColor(hexString: iconHaloColor) ?? UIColor.white - } - if let iconHaloWidth = options["iconHaloWidth"] as? CGFloat { - delegate.iconHaloWidth = iconHaloWidth - } - if let iconHaloBlur = options["iconHaloBlur"] as? CGFloat { - delegate.iconHaloBlur = iconHaloBlur - } - if let fontNames = options["fontNames"] as? [String] { - delegate.fontNames = fontNames - } - if let textField = options["textField"] as? String { - delegate.text = textField - } - if let textSize = options["textSize"] as? CGFloat { - delegate.textFontSize = textSize - } - if let textMaxWidth = options["textMaxWidth"] as? CGFloat { - delegate.maximumTextWidth = textMaxWidth - } - if let textLetterSpacing = options["textLetterSpacing"] as? CGFloat { - delegate.textLetterSpacing = textLetterSpacing - } - if let textJustify = options["textJustify"] as? String { - if let textJustifaction = Constants.symbolTextJustificationMapping[textJustify] { - delegate.textJustification = textJustifaction - } else { - delegate.textJustification = MGLTextJustification.center - } - } - if let textRadialOffset = options["textRadialOffset"] as? CGFloat { - delegate.textRadialOffset = textRadialOffset - } - if let textAnchorStr = options["textAnchor"] as? String { - if let textAnchor = Constants.symbolTextAnchorMapping[textAnchorStr] { - delegate.textAnchor = textAnchor - } else { - delegate.textAnchor = MGLTextAnchor.center - } - } - if let textRotate = options["textRotate"] as? CGFloat { - delegate.textRotation = textRotate - } - if let textTransform = options["textTransform"] as? String { - if let textTransformation = Constants.symbolTextTransformationMapping[textTransform] { - delegate.textTransform = textTransformation - } else { - delegate.textTransform = MGLTextTransform.none - } - } - if let textTranslate = options["textTranslate"] as? [Double] { - delegate.textTranslation = CGVector(dx: textTranslate[0], dy: textTranslate[1]) - } - if let textOffset = options["textOffset"] as? [Double] { - delegate.textOffset = CGVector(dx: textOffset[0], dy: textOffset[1]) - } - if let textOpacity = options["textOpacity"] as? CGFloat { - delegate.textOpacity = textOpacity - } - if let textColor = options["textColor"] as? String { - delegate.textColor = UIColor(hexString: textColor) ?? UIColor.black - } - if let textHaloColor = options["textHaloColor"] as? String { - delegate.textHaloColor = UIColor(hexString: textHaloColor) ?? UIColor.white - } - if let textHaloWidth = options["textHaloWidth"] as? CGFloat { - delegate.textHaloWidth = textHaloWidth - } - if let textHaloBlur = options["textHaloBlur"] as? CGFloat { - delegate.textHaloBlur = textHaloBlur - } - if let geometry = options["geometry"] as? [Double] { - // We cannot set the geometry directy on the annotation so calculate - // the difference and update the coordinate using the delta. - let currCoord = delegate.feature.coordinate - let newCoord = CLLocationCoordinate2DMake(geometry[0], geometry[1]) - let delta = CGVector( - dx: newCoord.longitude - currCoord.longitude, - dy: newCoord.latitude - currCoord.latitude - ) - delegate.updateGeometryCoordinates(withDelta: delta) - } - if let zIndex = options["zIndex"] as? Int { - delegate.symbolSortKey = zIndex - } - if let draggable = options["draggable"] as? Bool { - delegate.isDraggable = draggable - } - } - - class func interpretCircleOptions(options: Any?, delegate: MGLCircleStyleAnnotation) { - guard let options = options as? [String: Any] else { return } - if let circleRadius = options["circleRadius"] as? CGFloat { - delegate.circleRadius = circleRadius - } - if let circleColor = options["circleColor"] as? String { - delegate.circleColor = UIColor(hexString: circleColor) ?? UIColor.black - } - if let circleBlur = options["circleBlur"] as? CGFloat { - delegate.circleBlur = circleBlur - } - if let circleOpacity = options["circleOpacity"] as? CGFloat { - delegate.circleOpacity = circleOpacity - } - if let circleStrokeWidth = options["circleStrokeWidth"] as? CGFloat { - delegate.circleStrokeWidth = circleStrokeWidth - } - if let circleStrokeColor = options["circleStrokeColor"] as? String { - delegate.circleStrokeColor = UIColor(hexString: circleStrokeColor) ?? UIColor.black - } - if let circleStrokeOpacity = options["circleStrokeOpacity"] as? CGFloat { - delegate.circleStrokeOpacity = circleStrokeOpacity - } - if let geometry = options["geometry"] as? [Double] { - delegate.center = CLLocationCoordinate2DMake(geometry[0], geometry[1]) - } - if let draggable = options["draggable"] as? Bool { - delegate.isDraggable = draggable - } - } - - class func interpretLineOptions(options: Any?, delegate: MGLLineStyleAnnotation) { - guard let options = options as? [String: Any] else { return } - if let lineJoinStr = options["lineJoin"] as? String { - if let lineJoin = Constants.lineJoinMapping[lineJoinStr] { - delegate.lineJoin = lineJoin - } else { - delegate.lineJoin = MGLLineJoin.miter - } - } - if let lineOpacity = options["lineOpacity"] as? CGFloat { - delegate.lineOpacity = lineOpacity - } - if let lineColor = options["lineColor"] as? String { - delegate.lineColor = UIColor(hexString: lineColor) ?? UIColor.black - } - if let lineWidth = options["lineWidth"] as? CGFloat { - delegate.lineWidth = lineWidth - } - if let lineGapWidth = options["lineGapWidth"] as? CGFloat { - delegate.lineGapWidth = lineGapWidth - } - if let lineOffset = options["lineOffset"] as? CGFloat { - delegate.lineOffset = lineOffset - } - if let lineBlur = options["lineBlur"] as? CGFloat { - delegate.lineBlur = lineBlur - } - if let linePattern = options["linePattern"] as? String { - delegate.linePattern = linePattern - } - if let draggable = options["draggable"] as? Bool { - delegate.isDraggable = draggable - } - } - class func getCoordinates(options: Any?) -> [CLLocationCoordinate2D] { var coordinates: [CLLocationCoordinate2D] = [] @@ -381,47 +197,4 @@ class Convert { } return coordinates } - - class func interpretGeometryUpdate(options: Any?, delegate: MGLLineStyleAnnotation) { - if let options = options as? [String: Any], - let geometry = options["geometry"] as? [[Double]], geometry.count > 0 - { - if let feature = delegate.feature as? MGLPolylineFeature { - var coordinates = Convert.getCoordinates(options: options) - feature.setCoordinates(&coordinates, count: UInt(coordinates.count)) - } - } - } - - class func interpretFillOptions(options: Any?, delegate: MGLPolygonStyleAnnotation) { - guard let options = options as? [String: Any] else { return } - if let fillOpacity = options["fillOpacity"] as? CGFloat { - delegate.fillOpacity = fillOpacity - } - if let fillColor = options["fillColor"] as? String { - delegate.fillColor = UIColor(hexString: fillColor) ?? UIColor.black - } - if let fillOutlineColor = options["fillOutlineColor"] as? String { - delegate.fillOutlineColor = UIColor(hexString: fillOutlineColor) ?? UIColor.black - } - if let fillPattern = options["fillPattern"] as? String { - delegate.fillPattern = fillPattern - } - if let draggable = options["draggable"] as? Bool { - delegate.isDraggable = draggable - } - } - - class func toPolygons(geometry: [[[Double]]]) -> [MGLPolygonFeature] { - var polygons: [MGLPolygonFeature] = [] - for lineString in geometry { - var linearRing: [CLLocationCoordinate2D] = [] - for coordinate in lineString { - linearRing.append(CLLocationCoordinate2DMake(coordinate[0], coordinate[1])) - } - let polygon = MGLPolygonFeature(coordinates: linearRing, count: UInt(linearRing.count)) - polygons.append(polygon) - } - return polygons - } } diff --git a/ios/Classes/MapboxMapController.swift b/ios/Classes/MapboxMapController.swift index 14be84126..30ef72af2 100644 --- a/ios/Classes/MapboxMapController.swift +++ b/ios/Classes/MapboxMapController.swift @@ -4,7 +4,7 @@ import MapboxAnnotationExtension import UIKit class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, MapboxMapOptionsSink, - UIGestureRecognizerDelegate, MGLAnnotationControllerDelegate + UIGestureRecognizerDelegate { private var registrar: FlutterPluginRegistrar private var channel: FlutterMethodChannel? @@ -24,14 +24,6 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma private var myLocationEnabled = false private var scrollingEnabled = true - private var symbolAnnotationController: MGLSymbolAnnotationController? - private var circleAnnotationController: MGLCircleAnnotationController? - private var lineAnnotationController: MGLLineAnnotationController? - private var fillAnnotationController: MGLPolygonAnnotationController? - - private var annotationOrder = [String]() - private var annotationConsumeTapEvents = [String]() - private var featureLayerIdentifiers = Set() func view() -> UIView { @@ -106,12 +98,6 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma ) initialTilt = camera.pitch } - if let annotationOrderArg = args["annotationOrder"] as? [String] { - annotationOrder = annotationOrderArg - } - if let annotationConsumeTapEventsArg = args["annotationConsumeTapEvents"] as? [String] { - annotationConsumeTapEvents = annotationConsumeTapEventsArg - } if let onAttributionClickOverride = args["onAttributionClickOverride"] as? Bool { if onAttributionClickOverride { setupAttribution(mapView) @@ -336,267 +322,7 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma mapView.setCamera(camera, animated: true) } result(nil) - case "symbols#addAll": - guard let symbolAnnotationController = symbolAnnotationController else { return } - guard let arguments = methodCall.arguments as? [String: Any] else { return } - - if let options = arguments["options"] as? [[String: Any]] { - var symbols: [MGLSymbolStyleAnnotation] = [] - for o in options { - if let symbol = getSymbolForOptions(options: o) { - symbols.append(symbol) - } - } - if !symbols.isEmpty { - symbolAnnotationController.addStyleAnnotations(symbols) - symbolAnnotationController - .annotationsInteractionEnabled = annotationConsumeTapEvents - .contains("AnnotationType.symbol") - } - - result(symbols.map { $0.identifier }) - } else { - result(nil) - } - case "symbol#update": - guard let symbolAnnotationController = symbolAnnotationController else { return } - guard let arguments = methodCall.arguments as? [String: Any] else { return } - guard let symbolId = arguments["symbol"] as? String else { return } - - for symbol in symbolAnnotationController.styleAnnotations() { - if symbol.identifier == symbolId { - Convert.interpretSymbolOptions( - options: arguments["options"], - delegate: symbol as! MGLSymbolStyleAnnotation - ) - // Load (updated) icon image from asset if an icon name is supplied. - if let options = arguments["options"] as? [String: Any], - let iconImage = options["iconImage"] as? String - { - addIconImageToMap(iconImageName: iconImage) - } - symbolAnnotationController.updateStyleAnnotation(symbol) - break - } - } - result(nil) - case "symbols#removeAll": - guard let symbolAnnotationController = symbolAnnotationController else { return } - guard let arguments = methodCall.arguments as? [String: Any] else { return } - guard let symbolIds = arguments["ids"] as? [String] else { return } - - removeAllForController(controller: symbolAnnotationController, ids: symbolIds) - result(nil) - - case "symbol#getGeometry": - guard let symbolAnnotationController = symbolAnnotationController else { return } - guard let arguments = methodCall.arguments as? [String: Any] else { return } - guard let symbolId = arguments["symbol"] as? String else { return } - - var reply: [String: Double]? - for symbol in symbolAnnotationController.styleAnnotations() { - if symbol.identifier == symbolId { - if let geometry = symbol.geoJSONDictionary["geometry"] as? [String: Any], - let coordinates = geometry["coordinates"] as? [Double] - { - reply = ["latitude": coordinates[1], "longitude": coordinates[0]] - } - break - } - } - result(reply) - case "symbolManager#iconAllowOverlap": - guard let symbolAnnotationController = symbolAnnotationController else { return } - guard let arguments = methodCall.arguments as? [String: Any] else { return } - guard let iconAllowOverlap = arguments["iconAllowOverlap"] as? Bool else { return } - - symbolAnnotationController.iconAllowsOverlap = iconAllowOverlap - result(nil) - case "symbolManager#iconIgnorePlacement": - guard let symbolAnnotationController = symbolAnnotationController else { return } - guard let arguments = methodCall.arguments as? [String: Any] else { return } - guard let iconIgnorePlacement = arguments["iconIgnorePlacement"] as? Bool - else { return } - - symbolAnnotationController.iconIgnoresPlacement = iconIgnorePlacement - result(nil) - case "symbolManager#textAllowOverlap": - guard let symbolAnnotationController = symbolAnnotationController else { return } - guard let arguments = methodCall.arguments as? [String: Any] else { return } - guard let textAllowOverlap = arguments["textAllowOverlap"] as? Bool else { return } - - symbolAnnotationController.textAllowsOverlap = textAllowOverlap - result(nil) - case "symbolManager#textIgnorePlacement": - result(FlutterMethodNotImplemented) - case "circle#add": - guard let circleAnnotationController = circleAnnotationController else { return } - guard let arguments = methodCall.arguments as? [String: Any] else { return } - // Parse geometry - if let options = arguments["options"] as? [String: Any], - let geometry = options["geometry"] as? [Double] - { - // Convert geometry to coordinate and create circle. - let coordinate = CLLocationCoordinate2DMake(geometry[0], geometry[1]) - let circle = MGLCircleStyleAnnotation(center: coordinate) - Convert.interpretCircleOptions(options: arguments["options"], delegate: circle) - circleAnnotationController.addStyleAnnotation(circle) - circleAnnotationController - .annotationsInteractionEnabled = annotationConsumeTapEvents - .contains("AnnotationType.circle") - result(circle.identifier) - } else { - result(nil) - } - - case "circle#addAll": - guard let circleAnnotationController = circleAnnotationController else { return } - guard let arguments = methodCall.arguments as? [String: Any] else { return } - // Parse geometry - var identifier: String? - if let allOptions = arguments["options"] as? [[String: Any]] { - var circles: [MGLCircleStyleAnnotation] = [] - - for options in allOptions { - if let geometry = options["geometry"] as? [Double] { - guard geometry.count > 0 else { break } - - let coordinate = CLLocationCoordinate2DMake(geometry[0], geometry[1]) - let circle = MGLCircleStyleAnnotation(center: coordinate) - Convert.interpretCircleOptions(options: options, delegate: circle) - circles.append(circle) - } - } - if !circles.isEmpty { - circleAnnotationController.addStyleAnnotations(circles) - } - result(circles.map { $0.identifier }) - } else { - result(nil) - } - - case "circle#update": - guard let circleAnnotationController = circleAnnotationController else { return } - guard let arguments = methodCall.arguments as? [String: Any] else { return } - guard let circleId = arguments["circle"] as? String else { return } - - for circle in circleAnnotationController.styleAnnotations() { - if circle.identifier == circleId { - Convert.interpretCircleOptions( - options: arguments["options"], - delegate: circle as! MGLCircleStyleAnnotation - ) - circleAnnotationController.updateStyleAnnotation(circle) - break - } - } - result(nil) - case "circle#remove": - guard let circleAnnotationController = circleAnnotationController else { return } - guard let arguments = methodCall.arguments as? [String: Any] else { return } - guard let circleId = arguments["circle"] as? String else { return } - - for circle in circleAnnotationController.styleAnnotations() { - if circle.identifier == circleId { - circleAnnotationController.removeStyleAnnotation(circle) - break - } - } - result(nil) - - case "circle#removeAll": - guard let circleAnnotationController = circleAnnotationController else { return } - guard let arguments = methodCall.arguments as? [String: Any] else { return } - guard let ids = arguments["ids"] as? [String] else { return } - - removeAllForController(controller: circleAnnotationController, ids: ids) - result(nil) - - case "line#add": - guard let lineAnnotationController = lineAnnotationController else { return } - guard let arguments = methodCall.arguments as? [String: Any] else { return } - - if let options = arguments["options"] as? [String: Any] { - var coordinates = Convert.getCoordinates(options: options) - let line = MGLLineStyleAnnotation( - coordinates: &coordinates, - count: UInt(coordinates.count) - ) - Convert.interpretLineOptions(options: options, delegate: line) - lineAnnotationController.addStyleAnnotation(line) - lineAnnotationController.annotationsInteractionEnabled = annotationConsumeTapEvents - .contains("AnnotationType.line") - result(line.identifier) - } else { - result(nil) - } - - case "line#addAll": - guard let lineAnnotationController = lineAnnotationController else { return } - guard let arguments = methodCall.arguments as? [String: Any] else { return } - - var identifier: String? - if let allOptions = arguments["options"] as? [[String: Any]] { - var lines: [MGLLineStyleAnnotation] = [] - - for options in allOptions { - var coordinates = Convert.getCoordinates(options: options) - let line = MGLLineStyleAnnotation( - coordinates: &coordinates, - count: UInt(coordinates.count) - ) - Convert.interpretLineOptions(options: options, delegate: line) - lines.append(line) - } - if !lines.isEmpty { - lineAnnotationController.addStyleAnnotations(lines) - } - result(lines.map { $0.identifier }) - } else { - result(nil) - } - - case "line#update": - guard let lineAnnotationController = lineAnnotationController else { return } - guard let arguments = methodCall.arguments as? [String: Any] else { return } - guard let lineId = arguments["line"] as? String else { return } - - for line in lineAnnotationController.styleAnnotations() { - if line.identifier == lineId { - Convert.interpretGeometryUpdate( - options: arguments["options"], - delegate: line as! MGLLineStyleAnnotation - ) - Convert.interpretLineOptions( - options: arguments["options"], - delegate: line as! MGLLineStyleAnnotation - ) - lineAnnotationController.updateStyleAnnotation(line) - break - } - } - result(nil) - case "line#remove": - guard let lineAnnotationController = lineAnnotationController else { return } - guard let arguments = methodCall.arguments as? [String: Any] else { return } - guard let lineId = arguments["line"] as? String else { return } - - for line in lineAnnotationController.styleAnnotations() { - if line.identifier == lineId { - lineAnnotationController.removeStyleAnnotation(line) - break - } - } - result(nil) - - case "line#removeAll": - guard let lineAnnotationController = lineAnnotationController else { return } - guard let arguments = methodCall.arguments as? [String: Any] else { return } - guard let ids = arguments["ids"] as? [String] else { return } - - removeAllForController(controller: lineAnnotationController, ids: ids) - result(nil) - + case "symbolLayer#add": guard let arguments = methodCall.arguments as? [String: Any] else { return } guard let sourceId = arguments["sourceId"] as? String else { return } @@ -689,124 +415,6 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma ) result(nil) - case "line#getGeometry": - guard let lineAnnotationController = lineAnnotationController else { return } - guard let arguments = methodCall.arguments as? [String: Any] else { return } - guard let lineId = arguments["line"] as? String else { return } - - var reply: [Any]? - for line in lineAnnotationController.styleAnnotations() { - if line.identifier == lineId { - if let geometry = line.geoJSONDictionary["geometry"] as? [String: Any], - let coordinates = geometry["coordinates"] as? [[Double]] - { - reply = coordinates.map { ["latitude": $0[1], "longitude": $0[0]] } - } - break - } - } - result(reply) - case "fill#add": - guard let fillAnnotationController = fillAnnotationController else { return } - guard let arguments = methodCall.arguments as? [String: Any] else { return } - // Parse geometry - var identifier: String? - if let options = arguments["options"] as? [String: Any], - let geometry = options["geometry"] as? [[[Double]]] - { - guard geometry.count > 0 else { break } - // Convert geometry to coordinate and interior polygonc. - var fillCoordinates: [CLLocationCoordinate2D] = [] - for coordinate in geometry[0] { - fillCoordinates.append(CLLocationCoordinate2DMake(coordinate[0], coordinate[1])) - } - let polygons = Convert.toPolygons(geometry: geometry.tail) - let fill = MGLPolygonStyleAnnotation( - coordinates: fillCoordinates, - count: UInt(fillCoordinates.count), - interiorPolygons: polygons - ) - Convert.interpretFillOptions(options: arguments["options"], delegate: fill) - fillAnnotationController.addStyleAnnotation(fill) - fillAnnotationController.annotationsInteractionEnabled = annotationConsumeTapEvents - .contains("AnnotationType.fill") - identifier = fill.identifier - } - - result(identifier) - - case "fill#addAll": - guard let fillAnnotationController = fillAnnotationController else { return } - guard let arguments = methodCall.arguments as? [String: Any] else { return } - // Parse geometry - var identifier: String? - if let allOptions = arguments["options"] as? [[String: Any]] { - var fills: [MGLPolygonStyleAnnotation] = [] - - for options in allOptions { - if let geometry = options["geometry"] as? [[[Double]]] { - guard geometry.count > 0 else { break } - // Convert geometry to coordinate and interior polygonc. - var fillCoordinates: [CLLocationCoordinate2D] = [] - for coordinate in geometry[0] { - fillCoordinates - .append(CLLocationCoordinate2DMake(coordinate[0], coordinate[1])) - } - let polygons = Convert.toPolygons(geometry: geometry.tail) - let fill = MGLPolygonStyleAnnotation( - coordinates: fillCoordinates, - count: UInt(fillCoordinates.count), - interiorPolygons: polygons - ) - Convert.interpretFillOptions(options: options, delegate: fill) - fills.append(fill) - } - } - if !fills.isEmpty { - fillAnnotationController.addStyleAnnotations(fills) - } - result(fills.map { $0.identifier }) - } else { - result(nil) - } - - case "fill#update": - guard let fillAnnotationController = fillAnnotationController else { return } - guard let arguments = methodCall.arguments as? [String: Any] else { return } - guard let fillId = arguments["fill"] as? String else { return } - - for fill in fillAnnotationController.styleAnnotations() { - if fill.identifier == fillId { - Convert.interpretFillOptions( - options: arguments["options"], - delegate: fill as! MGLPolygonStyleAnnotation - ) - fillAnnotationController.updateStyleAnnotation(fill) - break - } - } - - result(nil) - case "fill#remove": - guard let fillAnnotationController = fillAnnotationController else { return } - guard let arguments = methodCall.arguments as? [String: Any] else { return } - guard let fillId = arguments["fill"] as? String else { return } - - for fill in fillAnnotationController.styleAnnotations() { - if fill.identifier == fillId { - fillAnnotationController.removeStyleAnnotation(fill) - break - } - } - result(nil) - - case "fill#removeAll": - guard let fillAnnotationController = fillAnnotationController else { return } - guard let arguments = methodCall.arguments as? [String: Any] else { return } - guard let ids = arguments["ids"] as? [String] else { return } - - removeAllForController(controller: fillAnnotationController, ids: ids) - result(nil) case "style#addImage": guard let arguments = methodCall.arguments as? [String: Any] else { return } @@ -1139,43 +747,6 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma } } - /* - * MGLAnnotationControllerDelegate - */ - func annotationController( - _ annotationController: MGLAnnotationController, - didSelect styleAnnotation: MGLStyleAnnotation - ) { - DispatchQueue.main.async { - // Remove tint color overlay from selected annotation by - // deselecting. This is not handled correctly if requested - // synchronously from the callback. - annotationController.deselectStyleAnnotation(styleAnnotation) - } - - guard let channel = channel else { - return - } - - if let symbol = styleAnnotation as? MGLSymbolStyleAnnotation { - channel.invokeMethod("symbol#onTap", arguments: ["symbol": "\(symbol.identifier)"]) - } else if let circle = styleAnnotation as? MGLCircleStyleAnnotation { - channel.invokeMethod("circle#onTap", arguments: ["circle": "\(circle.identifier)"]) - } else if let line = styleAnnotation as? MGLLineStyleAnnotation { - channel.invokeMethod("line#onTap", arguments: ["line": "\(line.identifier)"]) - } else if let fill = styleAnnotation as? MGLPolygonStyleAnnotation { - channel.invokeMethod("fill#onTap", arguments: ["fill": "\(fill.identifier)"]) - } - } - - // This is required in order to hide the default Maps SDK pin - func mapView(_: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView? { - if annotation is MGLUserLocation { - return nil - } - return MGLAnnotationView(frame: CGRect(x: 0, y: 0, width: 10, height: 10)) - } - /* * Override the attribution button's click target to handle the event locally. * Called if the application supplies an onAttributionClick handler. @@ -1214,38 +785,6 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma mapView.setCamera(camera, animated: false) } - for annotationType in annotationOrder { - switch annotationType { - case "AnnotationType.fill": - fillAnnotationController = MGLPolygonAnnotationController(mapView: self.mapView) - fillAnnotationController!.annotationsInteractionEnabled = annotationConsumeTapEvents - .contains("AnnotationType.fill") - fillAnnotationController?.delegate = self - case "AnnotationType.line": - lineAnnotationController = MGLLineAnnotationController(mapView: self.mapView) - lineAnnotationController!.annotationsInteractionEnabled = annotationConsumeTapEvents - .contains("AnnotationType.line") - - lineAnnotationController?.delegate = self - case "AnnotationType.circle": - circleAnnotationController = MGLCircleAnnotationController(mapView: self.mapView) - circleAnnotationController! - .annotationsInteractionEnabled = annotationConsumeTapEvents - .contains("AnnotationType.circle") - circleAnnotationController?.delegate = self - case "AnnotationType.symbol": - symbolAnnotationController = MGLSymbolAnnotationController(mapView: self.mapView) - symbolAnnotationController! - .annotationsInteractionEnabled = annotationConsumeTapEvents - .contains("AnnotationType.symbol") - symbolAnnotationController?.delegate = self - default: - print( - "Unknown annotation type: \(annotationType), must be either 'fill', 'line', 'circle' or 'symbol'" - ) - } - } - mapReadyResult?(nil) // On first launch we only call map#onStyleLoaded if map#waitForMap has already been called @@ -1312,18 +851,6 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma return annotationImage } - // On tap invoke the symbol#onTap callback. - func mapView(_: MGLMapView, didSelect annotation: MGLAnnotation) { - if let symbol = annotation as? Symbol { - channel?.invokeMethod("symbol#onTap", arguments: ["symbol": "\(symbol.id)"]) - } - } - - // Allow callout view to appear when an annotation is tapped. - func mapView(_: MGLMapView, annotationCanShowCallout _: MGLAnnotation) -> Bool { - return true - } - func mapView(_: MGLMapView, didUpdate userLocation: MGLUserLocation?) { if let channel = channel, let userLocation = userLocation, let location = userLocation.location diff --git a/ios/Classes/Symbol.swift b/ios/Classes/Symbol.swift deleted file mode 100644 index dae118ba1..000000000 --- a/ios/Classes/Symbol.swift +++ /dev/null @@ -1,75 +0,0 @@ -import Mapbox - -class Symbol: MGLPointAnnotation, SymbolOptionsSink { - private var _id = UUID().uuidString - var id: String { return _id } - - private var _iconImage: String? - var iconImage: String? { return _iconImage } - - var textField: String? { return title } - - var geometry: CLLocationCoordinate2D { 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 deleted file mode 100644 index db658fce5..000000000 --- a/ios/Classes/SymbolOptionsSink.swift +++ /dev/null @@ -1,31 +0,0 @@ - -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) -} From 32b7d4cc2facaad633638d4ac491e5aee94de7ac Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Thu, 16 Dec 2021 20:40:33 +0100 Subject: [PATCH 07/26] web cleanup --- mapbox_gl_web/lib/mapbox_gl_web.dart | 5 - .../src/feature_manager/circle_manager.dart | 43 ------- .../src/feature_manager/feature_manager.dart | 115 ------------------ .../lib/src/feature_manager/fill_manager.dart | 46 ------- .../lib/src/feature_manager/line_manager.dart | 47 ------- .../src/feature_manager/symbol_manager.dart | 93 -------------- .../lib/src/mapbox_map_controller.dart | 4 - 7 files changed, 353 deletions(-) delete mode 100644 mapbox_gl_web/lib/src/feature_manager/circle_manager.dart delete mode 100644 mapbox_gl_web/lib/src/feature_manager/feature_manager.dart delete mode 100644 mapbox_gl_web/lib/src/feature_manager/fill_manager.dart delete mode 100644 mapbox_gl_web/lib/src/feature_manager/line_manager.dart delete mode 100644 mapbox_gl_web/lib/src/feature_manager/symbol_manager.dart diff --git a/mapbox_gl_web/lib/mapbox_gl_web.dart b/mapbox_gl_web/lib/mapbox_gl_web.dart index 92a219118..cf5af7666 100644 --- a/mapbox_gl_web/lib/mapbox_gl_web.dart +++ b/mapbox_gl_web/lib/mapbox_gl_web.dart @@ -23,9 +23,4 @@ import 'package:mapbox_gl_web/src/layer_tools.dart'; part 'src/convert.dart'; part 'src/mapbox_map_plugin.dart'; part 'src/options_sink.dart'; -part 'src/feature_manager/feature_manager.dart'; -part 'src/feature_manager/symbol_manager.dart'; -part 'src/feature_manager/line_manager.dart'; -part 'src/feature_manager/circle_manager.dart'; -part 'src/feature_manager/fill_manager.dart'; part 'src/mapbox_map_controller.dart'; diff --git a/mapbox_gl_web/lib/src/feature_manager/circle_manager.dart b/mapbox_gl_web/lib/src/feature_manager/circle_manager.dart deleted file mode 100644 index 94269242f..000000000 --- a/mapbox_gl_web/lib/src/feature_manager/circle_manager.dart +++ /dev/null @@ -1,43 +0,0 @@ -part of mapbox_gl_web; - -class CircleManager extends FeatureManager { - CircleManager({ - required MapboxMap map, - ArgumentCallbacks? onTap, - }) : super( - sourceId: 'circle_source', - layerId: 'circle_layer', - map: map, - onTap: onTap, - ); - - @override - void initLayer() { - map.addLayer({ - 'id': layerId, - 'type': 'circle', - 'source': sourceId, - 'paint': { - 'circle-radius': ['get', 'circleRadius'], - 'circle-color': ['get', 'circleColor'], - 'circle-blur': ['get', 'circleBlur'], - 'circle-opacity': ['get', 'circleOpacity'], - 'circle-stroke-width': ['get', 'circleStrokeWidth'], - 'circle-stroke-color': ['get', 'circleStrokeColor'], - 'circle-stroke-opacity': ['get', 'circleStrokeOpacity'], - } - }); - } - - @override - void onDrag(String featureId, LatLng latLng) { - update(featureId, CircleOptions(geometry: latLng)); - } - - @override - void update(String lineId, CircleOptions changes) { - Feature olfFeature = getFeature(lineId)!; - Feature newFeature = Convert.interpretCircleOptions(changes, olfFeature); - updateFeature(newFeature); - } -} diff --git a/mapbox_gl_web/lib/src/feature_manager/feature_manager.dart b/mapbox_gl_web/lib/src/feature_manager/feature_manager.dart deleted file mode 100644 index a4bcfbfb0..000000000 --- a/mapbox_gl_web/lib/src/feature_manager/feature_manager.dart +++ /dev/null @@ -1,115 +0,0 @@ -part of mapbox_gl_web; - -abstract class FeatureManager { - final String sourceId; - final String layerId; - final MapboxMap map; - final ArgumentCallbacks? onTap; - @protected - late LatLng dragOrigin; - - final Map _features = {}; - num featureCounter = 1; - String? _draggableFeatureId; - - FeatureManager({ - required this.sourceId, - required this.layerId, - required this.map, - this.onTap, - }) { - var featureSource = GeoJsonSource(data: FeatureCollection(features: [])); - map.addSource(sourceId, featureSource); - initLayer(); - _initClickHandler(); - _initDragHandler(); - } - - void initLayer(); - - void update(String featureId, T changes); - - void onDrag(String featureId, LatLng latLng); - - String add(Feature feature) { - feature.id = featureCounter++; - _features['${feature.id}'] = feature; - _updateSource(); - return '${feature.id}'; - } - - void updateFeature(Feature feature) { - updateFeatures([feature]); - } - - void updateFeatures(Iterable features) { - features.forEach((feature) => _features['${feature.id}'] = feature); - _updateSource(); - } - - void remove(String featureId) { - removeAll([featureId]); - } - - void removeAll(Iterable featuresIds) { - featuresIds.forEach((featureId) => _features.remove(featureId)); - _updateSource(); - } - - Feature? getFeature(String featureId) { - return _features[featureId]; - } - - void _initClickHandler() { - map.on('click', (e) { - if (e is Event) { - final features = map.queryRenderedFeatures([e.point.x, e.point.y]); - if (features.isNotEmpty && features[0].source == sourceId) { - if (onTap != null) { - onTap!('${features[0].id}'); - } - } - } - }); - - map.on('mouseenter', layerId, (_) { - map.getCanvas().style.cursor = 'pointer'; - }); - - map.on('mouseleave', layerId, (_) { - map.getCanvas().style.cursor = ''; - }); - } - - void _initDragHandler() { - map.on('mousedown', layerId, (e) { - var isDraggable = e.features[0].properties['draggable']; - if (isDraggable != null && isDraggable) { - // Prevent the default map drag behavior. - e.preventDefault(); - _draggableFeatureId = '${e.features[0].id}'; - map.getCanvas().style.cursor = 'grabbing'; - var coords = e.lngLat; - dragOrigin = LatLng(coords.lat as double, coords.lng as double); - } - }); - - map.on('mousemove', (e) { - if (_draggableFeatureId != null) { - var coords = e.lngLat; - onDrag(_draggableFeatureId!, LatLng(coords.lat, coords.lng)); - } - }); - - map.on('mouseup', (_) { - _draggableFeatureId = null; - map.getCanvas().style.cursor = ''; - }); - } - - void _updateSource() { - GeoJsonSource featureSource = map.getSource(sourceId); - featureSource - .setData(FeatureCollection(features: _features.values.toList())); - } -} diff --git a/mapbox_gl_web/lib/src/feature_manager/fill_manager.dart b/mapbox_gl_web/lib/src/feature_manager/fill_manager.dart deleted file mode 100644 index 14def9505..000000000 --- a/mapbox_gl_web/lib/src/feature_manager/fill_manager.dart +++ /dev/null @@ -1,46 +0,0 @@ -part of mapbox_gl_web; - -class FillManager extends FeatureManager { - FillManager({ - required MapboxMap map, - ArgumentCallbacks? onTap, - }) : super( - sourceId: 'fill_source', - layerId: 'fill_layer', - map: map, - onTap: onTap, - ); - - @override - void initLayer() { - map.addLayer({ - 'id': layerId, - 'type': 'fill', - 'source': sourceId, - 'paint': { - 'fill-color': ['get', 'fillColor'], - 'fill-opacity': ['get', 'fillOpacity'], - 'fill-outline-color': ['get', 'fillOutlineColor'], - } - }); - } - - @override - void onDrag(String featureId, LatLng latLng) { - Feature oldFeature = getFeature(featureId)!; - final geometry = - Convert.featureGeometryToFillGeometry(oldFeature.geometry.coordinates); - update( - featureId, - translateFillOptions( - FillOptions(geometry: geometry), latLng - dragOrigin)); - dragOrigin = latLng; - } - - @override - void update(String featureId, FillOptions changes) { - Feature oldFeature = getFeature(featureId)!; - Feature newFeature = Convert.intepretFillOptions(changes, oldFeature); - updateFeature(newFeature); - } -} diff --git a/mapbox_gl_web/lib/src/feature_manager/line_manager.dart b/mapbox_gl_web/lib/src/feature_manager/line_manager.dart deleted file mode 100644 index 59c3a71ed..000000000 --- a/mapbox_gl_web/lib/src/feature_manager/line_manager.dart +++ /dev/null @@ -1,47 +0,0 @@ -part of mapbox_gl_web; - -class LineManager extends FeatureManager { - LineManager({ - required MapboxMap map, - ArgumentCallbacks? onTap, - }) : super( - sourceId: 'line_source', - layerId: 'line_layer', - map: map, - onTap: onTap, - ); - - @override - void initLayer() { - // NOTE: line-pattern disable line-color - map.addLayer({ - 'id': layerId, - 'type': 'line', - 'source': sourceId, - 'layout': { - 'line-join': ['get', 'lineJoin'], - }, - 'paint': { - 'line-opacity': ['get', 'lineOpacity'], - 'line-color': ['get', 'lineColor'], - 'line-width': ['get', 'lineWidth'], - 'line-gap-width': ['get', 'lineGapWidth'], - 'line-offset': ['get', 'lineOffset'], - 'line-blur': ['get', 'lineBlur'], - //'line-pattern': ['get', 'linePattern'], - } - }); - } - - void update(String lineId, LineOptions changes) { - Feature olfFeature = getFeature(lineId)!; - Feature newFeature = Convert.interpretLineOptions(changes, olfFeature); - updateFeature(newFeature); - } - - @override - void onDrag(String featureId, LatLng latLng) { - // TODO: implement onDrag - print('onDrag is not already implemented'); - } -} diff --git a/mapbox_gl_web/lib/src/feature_manager/symbol_manager.dart b/mapbox_gl_web/lib/src/feature_manager/symbol_manager.dart deleted file mode 100644 index a3d2e7567..000000000 --- a/mapbox_gl_web/lib/src/feature_manager/symbol_manager.dart +++ /dev/null @@ -1,93 +0,0 @@ -part of mapbox_gl_web; - -class SymbolManager extends FeatureManager { - SymbolManager({ - required MapboxMap map, - ArgumentCallbacks? onTap, - }) : super( - sourceId: 'symbol_source', - layerId: 'symbol_layer', - map: map, - onTap: onTap, - ); - - @override - void initLayer() { - map.addLayer({ - 'id': layerId, - 'type': 'symbol', - 'source': sourceId, - 'layout': { - 'icon-image': '{iconImage}', - 'icon-size': ['get', 'iconSize'], - 'icon-rotate': ['get', 'iconRotate'], - 'icon-offset': ['get', 'iconOffset'], - 'icon-anchor': ['get', 'iconAnchor'], - 'text-field': ['get', 'textField'], - 'text-size': ['get', 'textSize'], - 'text-max-width': ['get', 'textMaxWidth'], - 'text-letter-spacing': ['get', 'textLetterSpacing'], - 'text-justify': ['get', 'textJustify'], - 'text-anchor': ['get', 'textAnchor'], - 'text-rotate': ['get', 'textRotate'], - 'text-transform': ['get', 'textTransform'], - 'text-offset': ['get', 'textOffset'], - 'symbol-sort-key': ['get', 'symbolSortKey'], - 'icon-allow-overlap': true, - 'icon-ignore-placement': true, - 'text-allow-overlap': true, - 'text-ignore-placement': true, - }, - 'paint': { - 'icon-opacity': ['get', 'iconOpacity'], - 'icon-color': ['get', 'iconColor'], - 'icon-halo-color': ['get', 'iconHaloColor'], - 'icon-halo-width': ['get', 'iconHaloWidth'], - 'icon-halo-blur': ['get', 'iconHaloBlur'], - 'text-opacity': ['get', 'textOpacity'], - 'text-color': ['get', 'textColor'], - 'text-halo-color': ['get', 'textHaloColor'], - 'text-halo-width': ['get', 'textHaloWidth'], - 'text-halo-blur': ['get', 'textHaloBlur'], - } - }); - - map.on('styleimagemissing', (event) { - if (event.id == '') { - return; - } - var density = context['window'].devicePixelRatio ?? 1; - var imagePath = density == 1 - ? '/assets/assets/symbols/custom-icon.png' - : '/assets/assets/symbols/$density.0x/custom-icon.png'; - map.loadImage(imagePath, (error, image) { - if (error != null) throw error; - if (!map.hasImage(event.id)) - map.addImage(event.id, image, {'pixelRatio': density}); - }); - }); - } - - @override - void update(String lineId, SymbolOptions changes) { - updateAll({lineId: changes}); - } - - void updateAll(Map changesById) { - List featuresWithUpdatedOptions = []; - changesById.forEach( - (id, options) => featuresWithUpdatedOptions.add( - Convert.interpretSymbolOptions( - options, - getFeature(id)!, - ), - ), - ); - updateFeatures(featuresWithUpdatedOptions); - } - - @override - void onDrag(String featureId, LatLng latLng) { - update(featureId, SymbolOptions(geometry: latLng)); - } -} diff --git a/mapbox_gl_web/lib/src/mapbox_map_controller.dart b/mapbox_gl_web/lib/src/mapbox_map_controller.dart index 83656ab34..bdc602aba 100644 --- a/mapbox_gl_web/lib/src/mapbox_map_controller.dart +++ b/mapbox_gl_web/lib/src/mapbox_map_controller.dart @@ -16,10 +16,6 @@ class MapboxMapController extends MapboxGlPlatform List annotationOrder = []; final _featureLayerIdentifiers = Set(); - late SymbolManager symbolManager; - late LineManager lineManager; - late CircleManager circleManager; - late FillManager fillManager; bool _trackCameraPosition = false; GeolocateControl? _geolocateControl; From 04e224327d6640cb472af4f6df0a75fa489abfc2 Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Sun, 19 Dec 2021 18:07:43 +0100 Subject: [PATCH 08/26] working android version --- .../com/mapbox/mapboxgl/CircleBuilder.java | 76 -- .../com/mapbox/mapboxgl/CircleController.java | 96 --- .../mapbox/mapboxgl/CircleOptionsSink.java | 31 - .../java/com/mapbox/mapboxgl/Convert.java | 261 +------ .../java/com/mapbox/mapboxgl/FillBuilder.java | 62 -- .../com/mapbox/mapboxgl/FillController.java | 78 -- .../com/mapbox/mapboxgl/FillOptionsSink.java | 27 - .../java/com/mapbox/mapboxgl/LineBuilder.java | 82 -- .../com/mapbox/mapboxgl/LineController.java | 112 --- .../com/mapbox/mapboxgl/LineOptionsSink.java | 36 - .../mapbox/mapboxgl/MapboxMapController.java | 739 +++--------------- .../mapboxgl/OnCircleTappedListener.java | 11 - .../mapbox/mapboxgl/OnFillTappedListener.java | 7 - .../mapbox/mapboxgl/OnLineTappedListener.java | 11 - .../mapboxgl/OnSymbolTappedListener.java | 11 - .../com/mapbox/mapboxgl/SymbolBuilder.java | 168 ---- .../com/mapbox/mapboxgl/SymbolController.java | 191 ----- .../mapbox/mapboxgl/SymbolOptionsSink.java | 72 -- example/lib/line.dart | 14 +- example/lib/place_symbol.dart | 4 +- lib/mapbox_gl.dart | 2 +- ...nnotation.dart => annotation_manager.dart} | 16 +- lib/src/controller.dart | 67 +- .../lib/src/annotation.dart | 2 +- .../lib/src/circle.dart | 18 +- .../lib/src/fill.dart | 28 +- .../lib/src/line.dart | 18 +- .../lib/src/symbol.dart | 18 +- 28 files changed, 185 insertions(+), 2073 deletions(-) delete mode 100644 android/src/main/java/com/mapbox/mapboxgl/CircleBuilder.java delete mode 100644 android/src/main/java/com/mapbox/mapboxgl/CircleController.java delete mode 100644 android/src/main/java/com/mapbox/mapboxgl/CircleOptionsSink.java delete mode 100644 android/src/main/java/com/mapbox/mapboxgl/FillBuilder.java delete mode 100644 android/src/main/java/com/mapbox/mapboxgl/FillController.java delete mode 100644 android/src/main/java/com/mapbox/mapboxgl/FillOptionsSink.java delete mode 100644 android/src/main/java/com/mapbox/mapboxgl/LineBuilder.java delete mode 100644 android/src/main/java/com/mapbox/mapboxgl/LineController.java delete mode 100644 android/src/main/java/com/mapbox/mapboxgl/LineOptionsSink.java delete mode 100644 android/src/main/java/com/mapbox/mapboxgl/OnCircleTappedListener.java delete mode 100644 android/src/main/java/com/mapbox/mapboxgl/OnFillTappedListener.java delete mode 100644 android/src/main/java/com/mapbox/mapboxgl/OnLineTappedListener.java delete mode 100644 android/src/main/java/com/mapbox/mapboxgl/OnSymbolTappedListener.java delete mode 100644 android/src/main/java/com/mapbox/mapboxgl/SymbolBuilder.java delete mode 100644 android/src/main/java/com/mapbox/mapboxgl/SymbolController.java delete mode 100644 android/src/main/java/com/mapbox/mapboxgl/SymbolOptionsSink.java rename lib/src/{annotation.dart => annotation_manager.dart} (93%) diff --git a/android/src/main/java/com/mapbox/mapboxgl/CircleBuilder.java b/android/src/main/java/com/mapbox/mapboxgl/CircleBuilder.java deleted file mode 100644 index db7accf56..000000000 --- a/android/src/main/java/com/mapbox/mapboxgl/CircleBuilder.java +++ /dev/null @@ -1,76 +0,0 @@ -// This file is generated. - -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package com.mapbox.mapboxgl; - -import com.mapbox.geojson.Point; -import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.plugins.annotation.Circle; -import com.mapbox.mapboxsdk.plugins.annotation.CircleManager; -import com.mapbox.mapboxsdk.plugins.annotation.CircleOptions; - -class CircleBuilder implements CircleOptionsSink { - private final CircleManager circleManager; - private final CircleOptions circleOptions; - - CircleBuilder(CircleManager circleManager) { - this.circleManager = circleManager; - this.circleOptions = new CircleOptions(); - } - - public CircleOptions getCircleOptions(){ - return this.circleOptions; - } - - Circle build() { - return circleManager.create(circleOptions); - } - - @Override - public void setCircleRadius(float circleRadius) { - circleOptions.withCircleRadius(circleRadius); - } - - @Override - public void setCircleColor(String circleColor) { - circleOptions.withCircleColor(circleColor); - } - - @Override - public void setCircleBlur(float circleBlur) { - circleOptions.withCircleBlur(circleBlur); - } - - @Override - public void setCircleOpacity(float circleOpacity) { - circleOptions.withCircleOpacity(circleOpacity); - } - - @Override - public void setCircleStrokeWidth(float circleStrokeWidth) { - circleOptions.withCircleStrokeWidth(circleStrokeWidth); - } - - @Override - public void setCircleStrokeColor(String circleStrokeColor) { - circleOptions.withCircleStrokeColor(circleStrokeColor); - } - - @Override - public void setCircleStrokeOpacity(float circleStrokeOpacity) { - circleOptions.withCircleStrokeOpacity(circleStrokeOpacity); - } - - @Override - public void setGeometry(LatLng geometry) { - circleOptions.withGeometry(Point.fromLngLat(geometry.getLongitude(), geometry.getLatitude())); - } - - @Override - public void setDraggable(boolean draggable) { - circleOptions.withDraggable(draggable); - } -} \ No newline at end of file diff --git a/android/src/main/java/com/mapbox/mapboxgl/CircleController.java b/android/src/main/java/com/mapbox/mapboxgl/CircleController.java deleted file mode 100644 index 76860ea6f..000000000 --- a/android/src/main/java/com/mapbox/mapboxgl/CircleController.java +++ /dev/null @@ -1,96 +0,0 @@ -// This file is generated. - -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package com.mapbox.mapboxgl; - -import android.graphics.Color; -import com.mapbox.geojson.Point; -import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.plugins.annotation.Circle; -import com.mapbox.mapboxsdk.plugins.annotation.CircleManager; - -/** Controller of a single Circle on the map. */ -class CircleController implements CircleOptionsSink { - private final Circle circle; - private final OnCircleTappedListener onTappedListener; - private boolean consumeTapEvents; - - CircleController(Circle circle, boolean consumeTapEvents, OnCircleTappedListener onTappedListener) { - this.circle = circle; - this.consumeTapEvents = consumeTapEvents; - this.onTappedListener = onTappedListener; - } - - public Circle getCircle(){ - return this.circle; - } - - boolean onTap() { - if (onTappedListener != null) { - onTappedListener.onCircleTapped(circle); - } - return consumeTapEvents; - } - - void remove(CircleManager circleManager) { - circleManager.delete(circle); - } - - @Override - public void setCircleRadius(float circleRadius) { - circle.setCircleRadius(circleRadius); - } - - @Override - public void setCircleColor(String circleColor) { - circle.setCircleColor(Color.parseColor(circleColor)); - } - - @Override - public void setCircleBlur(float circleBlur) { - circle.setCircleBlur(circleBlur); - } - - @Override - public void setCircleOpacity(float circleOpacity) { - circle.setCircleOpacity(circleOpacity); - } - - @Override - public void setCircleStrokeWidth(float circleStrokeWidth) { - circle.setCircleStrokeWidth(circleStrokeWidth); - } - - @Override - public void setCircleStrokeColor(String circleStrokeColor) { - circle.setCircleStrokeColor(Color.parseColor(circleStrokeColor)); - } - - @Override - public void setCircleStrokeOpacity(float circleStrokeOpacity) { - circle.setCircleStrokeOpacity(circleStrokeOpacity); - } - - @Override - public void setGeometry(LatLng geometry) { - circle.setGeometry(Point.fromLngLat(geometry.getLongitude(), geometry.getLatitude())); - } - - public LatLng getGeometry() { - Point point = circle.getGeometry(); - return new LatLng(point.latitude(), point.longitude()); - } - - @Override - public void setDraggable(boolean draggable) { - circle.setDraggable(draggable); - } - - public void update(CircleManager circleManager) { - circleManager.update(circle); - } - -} diff --git a/android/src/main/java/com/mapbox/mapboxgl/CircleOptionsSink.java b/android/src/main/java/com/mapbox/mapboxgl/CircleOptionsSink.java deleted file mode 100644 index 80bd8ea04..000000000 --- a/android/src/main/java/com/mapbox/mapboxgl/CircleOptionsSink.java +++ /dev/null @@ -1,31 +0,0 @@ -// This file is generated. - -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package com.mapbox.mapboxgl; - -import com.mapbox.mapboxsdk.geometry.LatLng; - -/** Receiver of Circle configuration options. */ -interface CircleOptionsSink { - - void setCircleRadius(float circleRadius); - - void setCircleColor(String circleColor); - - void setCircleBlur(float circleBlur); - - void setCircleOpacity(float circleOpacity); - - void setCircleStrokeWidth(float circleStrokeWidth); - - void setCircleStrokeColor(String circleStrokeColor); - - void setCircleStrokeOpacity(float circleStrokeOpacity); - - void setGeometry(LatLng geometry); - - void setDraggable(boolean draggable); -} diff --git a/android/src/main/java/com/mapbox/mapboxgl/Convert.java b/android/src/main/java/com/mapbox/mapboxgl/Convert.java index f4ba4a389..068f29490 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/Convert.java +++ b/android/src/main/java/com/mapbox/mapboxgl/Convert.java @@ -31,29 +31,7 @@ class Convert { private final static String TAG = "Convert"; -// private static BitmapDescriptor toBitmapDescriptor(Object o) { -// final List data = toList(o); -// switch (toString(data.get(0))) { -// case "defaultMarker": -// if (data.size() == 1) { -// return BitmapDescriptorFactory.defaultMarker(); -// } else { -// return BitmapDescriptorFactory.defaultMarker(toFloat(data.get(1))); -// } -// case "fromAsset": -// if (data.size() == 2) { -// return BitmapDescriptorFactory.fromAsset( -// FlutterMain.getLookupKeyForAsset(toString(data.get(1)))); -// } else { -// return BitmapDescriptorFactory.fromAsset( -// FlutterMain.getLookupKeyForAsset(toString(data.get(1)), toString(data.get(2)))); -// } -// default: -// throw new IllegalArgumentException("Cannot interpret " + o + " as BitmapDescriptor"); -// } -// } - - static boolean toBoolean(Object o) { + private static boolean toBoolean(Object o) { return (Boolean) o; } @@ -326,241 +304,4 @@ static void interpretMapboxMapOptions(Object o, MapboxMapOptionsSink sink, Conte sink.setAttributionButtonMargins(point.x, point.y); } } - - static void interpretSymbolOptions(Object o, SymbolOptionsSink sink) { - final Map data = toMap(o); - final Object iconSize = data.get("iconSize"); - if (iconSize != null) { - sink.setIconSize(toFloat(iconSize)); - } - final Object iconImage = data.get("iconImage"); - if (iconImage != null) { - sink.setIconImage(toString(iconImage)); - } - final Object iconRotate = data.get("iconRotate"); - if (iconRotate != null) { - sink.setIconRotate(toFloat(iconRotate)); - } - final Object iconOffset = data.get("iconOffset"); - if (iconOffset != null) { - sink.setIconOffset(new float[] {toFloat(toList(iconOffset).get(0)), toFloat(toList(iconOffset).get(1))}); - } - final Object iconAnchor = data.get("iconAnchor"); - if (iconAnchor != null) { - sink.setIconAnchor(toString(iconAnchor)); - } - final ArrayList fontNames = (ArrayList) data.get("fontNames"); - if (fontNames != null) { - sink.setFontNames((String[]) fontNames.toArray(new String[0])); - } - final Object textField = data.get("textField"); - if (textField != null) { - sink.setTextField(toString(textField)); - } - final Object textSize = data.get("textSize"); - if (textSize != null) { - sink.setTextSize(toFloat(textSize)); - } - final Object textMaxWidth = data.get("textMaxWidth"); - if (textMaxWidth != null) { - sink.setTextMaxWidth(toFloat(textMaxWidth)); - } - final Object textLetterSpacing = data.get("textLetterSpacing"); - if (textLetterSpacing != null) { - sink.setTextLetterSpacing(toFloat(textLetterSpacing)); - } - final Object textJustify = data.get("textJustify"); - if (textJustify != null) { - sink.setTextJustify(toString(textJustify)); - } - final Object textAnchor = data.get("textAnchor"); - if (textAnchor != null) { - sink.setTextAnchor(toString(textAnchor)); - } - final Object textRotate = data.get("textRotate"); - if (textRotate != null) { - sink.setTextRotate(toFloat(textRotate)); - } - final Object textTransform = data.get("textTransform"); - if (textTransform != null) { - sink.setTextTransform(toString(textTransform)); - } - final Object textOffset = data.get("textOffset"); - if (textOffset != null) { - sink.setTextOffset(new float[] {toFloat(toList(textOffset).get(0)), toFloat(toList(textOffset).get(1))}); - } - final Object iconOpacity = data.get("iconOpacity"); - if (iconOpacity != null) { - sink.setIconOpacity(toFloat(iconOpacity)); - } - final Object iconColor = data.get("iconColor"); - if (iconColor != null) { - sink.setIconColor(toString(iconColor)); - } - final Object iconHaloColor = data.get("iconHaloColor"); - if (iconHaloColor != null) { - sink.setIconHaloColor(toString(iconHaloColor)); - } - final Object iconHaloWidth = data.get("iconHaloWidth"); - if (iconHaloWidth != null) { - sink.setIconHaloWidth(toFloat(iconHaloWidth)); - } - final Object iconHaloBlur = data.get("iconHaloBlur"); - if (iconHaloBlur != null) { - sink.setIconHaloBlur(toFloat(iconHaloBlur)); - } - final Object textOpacity = data.get("textOpacity"); - if (textOpacity != null) { - sink.setTextOpacity(toFloat(textOpacity)); - } - final Object textColor = data.get("textColor"); - if (textColor != null) { - sink.setTextColor(toString(textColor)); - } - final Object textHaloColor = data.get("textHaloColor"); - if (textHaloColor != null) { - sink.setTextHaloColor(toString(textHaloColor)); - } - final Object textHaloWidth = data.get("textHaloWidth"); - if (textHaloWidth != null) { - sink.setTextHaloWidth(toFloat(textHaloWidth)); - } - final Object textHaloBlur = data.get("textHaloBlur"); - if (textHaloBlur != null) { - sink.setTextHaloBlur(toFloat(textHaloBlur)); - } - final Object geometry = data.get("geometry"); - if (geometry != null) { - sink.setGeometry(toLatLng(geometry)); - } - final Object symbolSortKey = data.get("zIndex"); - if (symbolSortKey != null) { - sink.setSymbolSortKey(toFloat(symbolSortKey)); - } - final Object draggable = data.get("draggable"); - if (draggable != null) { - sink.setDraggable(toBoolean(draggable)); - } - } - - static void interpretCircleOptions(Object o, CircleOptionsSink sink) { - final Map data = toMap(o); - final Object circleRadius = data.get("circleRadius"); - if (circleRadius != null) { - sink.setCircleRadius(toFloat(circleRadius)); - } - final Object circleColor = data.get("circleColor"); - if (circleColor != null) { - sink.setCircleColor(toString(circleColor)); - } - final Object circleBlur = data.get("circleBlur"); - if (circleBlur != null) { - sink.setCircleBlur(toFloat(circleBlur)); - } - final Object circleOpacity = data.get("circleOpacity"); - if (circleOpacity != null) { - sink.setCircleOpacity(toFloat(circleOpacity)); - } - final Object circleStrokeWidth = data.get("circleStrokeWidth"); - if (circleStrokeWidth != null) { - sink.setCircleStrokeWidth(toFloat(circleStrokeWidth)); - } - final Object circleStrokeColor = data.get("circleStrokeColor"); - if (circleStrokeColor != null) { - sink.setCircleStrokeColor(toString(circleStrokeColor)); - } - final Object circleStrokeOpacity = data.get("circleStrokeOpacity"); - if (circleStrokeOpacity != null) { - sink.setCircleStrokeOpacity(toFloat(circleStrokeOpacity)); - } - final Object geometry = data.get("geometry"); - if (geometry != null) { - sink.setGeometry(toLatLng(geometry)); - } - final Object draggable = data.get("draggable"); - if (draggable != null) { - sink.setDraggable(toBoolean(draggable)); - } - } - static void interpretLineOptions(Object o, LineOptionsSink sink) { - final Map data = toMap(o); - final Object lineJoin = data.get("lineJoin"); - if (lineJoin != null) { - Logger.e(TAG, "setLineJoin" + lineJoin); - sink.setLineJoin(toString(lineJoin)); - } - final Object lineOpacity = data.get("lineOpacity"); - if (lineOpacity != null) { - Logger.e(TAG, "setLineOpacity" + lineOpacity); - sink.setLineOpacity(toFloat(lineOpacity)); - } - final Object lineColor = data.get("lineColor"); - if (lineColor != null) { - Logger.e(TAG, "setLineColor" + lineColor); - sink.setLineColor(toString(lineColor)); - } - final Object lineWidth = data.get("lineWidth"); - if (lineWidth != null) { - Logger.e(TAG, "setLineWidth" + lineWidth); - sink.setLineWidth(toFloat(lineWidth)); - } - final Object lineGapWidth = data.get("lineGapWidth"); - if (lineGapWidth != null) { - Logger.e(TAG, "setLineGapWidth" + lineGapWidth); - sink.setLineGapWidth(toFloat(lineGapWidth)); - } - final Object lineOffset = data.get("lineOffset"); - if (lineOffset != null) { - Logger.e(TAG, "setLineOffset" + lineOffset); - sink.setLineOffset(toFloat(lineOffset)); - } - final Object lineBlur = data.get("lineBlur"); - if (lineBlur != null) { - Logger.e(TAG, "setLineBlur" + lineBlur); - sink.setLineBlur(toFloat(lineBlur)); - } - final Object linePattern = data.get("linePattern"); - if (linePattern != null) { - Logger.e(TAG, "setLinePattern" + linePattern); - sink.setLinePattern(toString(linePattern)); - } - final Object geometry = data.get("geometry"); - if (geometry != null) { - Logger.e(TAG, "SetGeometry"); - sink.setGeometry(toLatLngList(geometry, false)); - } - final Object draggable = data.get("draggable"); - if (draggable != null) { - Logger.e(TAG, "SetDraggable"); - sink.setDraggable(toBoolean(draggable)); - } - } - - static void interpretFillOptions(Object o, FillOptionsSink sink) { - final Map data = toMap(o); - final Object fillOpacity = data.get("fillOpacity"); - if (fillOpacity != null) { - sink.setFillOpacity(toFloat(fillOpacity)); - } - final Object fillColor = data.get("fillColor"); - if (fillColor != null) { - sink.setFillColor(toString(fillColor)); - } - final Object fillOutlineColor = data.get("fillOutlineColor"); - if (fillOutlineColor != null) { - sink.setFillOutlineColor(toString(fillOutlineColor)); - } - final Object fillPattern = data.get("fillPattern"); - if (fillPattern != null) { - sink.setFillPattern(toString(fillPattern)); - } - final Object geometry = data.get("geometry"); - if (geometry != null) { - sink.setGeometry(toLatLngListList(geometry)); - } - final Object draggable = data.get("draggable"); - if (draggable != null) { - sink.setDraggable(toBoolean(draggable)); - } - } } \ No newline at end of file diff --git a/android/src/main/java/com/mapbox/mapboxgl/FillBuilder.java b/android/src/main/java/com/mapbox/mapboxgl/FillBuilder.java deleted file mode 100644 index b70589cba..000000000 --- a/android/src/main/java/com/mapbox/mapboxgl/FillBuilder.java +++ /dev/null @@ -1,62 +0,0 @@ -// This file is generated. - -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package com.mapbox.mapboxgl; - -import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.plugins.annotation.Fill; -import com.mapbox.mapboxsdk.plugins.annotation.FillManager; -import com.mapbox.mapboxsdk.plugins.annotation.FillOptions; - -import java.util.List; - -class FillBuilder implements FillOptionsSink { - private final FillManager fillManager; - private final FillOptions fillOptions; - - FillBuilder(FillManager fillManager) { - this.fillManager = fillManager; - this.fillOptions = new FillOptions(); - } - - public FillOptions getFillOptions(){ - return this.fillOptions; - } - - Fill build() { - return fillManager.create(fillOptions); - } - - @Override - public void setFillOpacity(float fillOpacity) { - fillOptions.withFillOpacity(fillOpacity); - } - - @Override - public void setFillColor(String fillColor) { - fillOptions.withFillColor(fillColor); - } - - @Override - public void setFillOutlineColor(String fillOutlineColor) { - fillOptions.withFillOutlineColor(fillOutlineColor); - } - - @Override - public void setFillPattern(String fillPattern) { - fillOptions.withFillPattern(fillPattern); - } - - @Override - public void setGeometry(List> geometry) { - fillOptions.withGeometry(Convert.interpretListLatLng(geometry)); - } - - @Override - public void setDraggable(boolean draggable) { - fillOptions.withDraggable(draggable); - } -} \ No newline at end of file diff --git a/android/src/main/java/com/mapbox/mapboxgl/FillController.java b/android/src/main/java/com/mapbox/mapboxgl/FillController.java deleted file mode 100644 index 86bc01137..000000000 --- a/android/src/main/java/com/mapbox/mapboxgl/FillController.java +++ /dev/null @@ -1,78 +0,0 @@ -// This file is generated. - -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package com.mapbox.mapboxgl; - -import android.graphics.Color; -import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.plugins.annotation.Fill; -import com.mapbox.mapboxsdk.plugins.annotation.FillManager; - -import java.util.List; - -/** - * Controller of a single Fill on the map. - */ -class FillController implements FillOptionsSink { - private final Fill fill; - private final OnFillTappedListener onTappedListener; - private boolean consumeTapEvents; - - FillController(Fill fill, boolean consumeTapEvents, OnFillTappedListener onTappedListener) { - this.fill = fill; - this.consumeTapEvents = consumeTapEvents; - this.onTappedListener = onTappedListener; - } - - public Fill getFill(){ - return this.fill; - } - - boolean onTap() { - if (onTappedListener != null) { - onTappedListener.onFillTapped(fill); - } - return consumeTapEvents; - } - - void remove(FillManager fillManager) { - fillManager.delete(fill); - } - - @Override - public void setFillOpacity(float fillOpacity) { - fill.setFillOpacity(fillOpacity); - } - - @Override - public void setFillColor(String fillColor) { - fill.setFillColor(Color.parseColor(fillColor)); - } - - @Override - public void setFillOutlineColor(String fillOutlineColor) { - fill.setFillOutlineColor(Color.parseColor(fillOutlineColor)); - } - - @Override - public void setFillPattern(String fillPattern) { - fill.setFillPattern(fillPattern); - } - - @Override - public void setGeometry(List> geometry) { - fill.setGeometry(Convert.interpretListLatLng(geometry)); - } - - @Override - public void setDraggable(boolean draggable) { - fill.setDraggable(draggable); - } - - public void update(FillManager fillManager) { - fillManager.update(fill); - } -} diff --git a/android/src/main/java/com/mapbox/mapboxgl/FillOptionsSink.java b/android/src/main/java/com/mapbox/mapboxgl/FillOptionsSink.java deleted file mode 100644 index 849788103..000000000 --- a/android/src/main/java/com/mapbox/mapboxgl/FillOptionsSink.java +++ /dev/null @@ -1,27 +0,0 @@ -// This file is generated. - -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package com.mapbox.mapboxgl; - -import com.mapbox.mapboxsdk.geometry.LatLng; - -import java.util.List; - -/** Receiver of Fill configuration options. */ -interface FillOptionsSink { - - void setFillOpacity(float fillOpacity); - - void setFillColor(String fillColor); - - void setFillOutlineColor(String fillOutlineColor); - - void setFillPattern(String fillPattern); - - void setGeometry(List> geometry); - - void setDraggable(boolean draggable); -} diff --git a/android/src/main/java/com/mapbox/mapboxgl/LineBuilder.java b/android/src/main/java/com/mapbox/mapboxgl/LineBuilder.java deleted file mode 100644 index 5d7276143..000000000 --- a/android/src/main/java/com/mapbox/mapboxgl/LineBuilder.java +++ /dev/null @@ -1,82 +0,0 @@ -// This file is generated. - -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package com.mapbox.mapboxgl; - -import java.util.List; -import com.mapbox.geojson.Point; -import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.plugins.annotation.Line; -import com.mapbox.mapboxsdk.plugins.annotation.LineManager; -import com.mapbox.mapboxsdk.plugins.annotation.LineOptions; - -class LineBuilder implements LineOptionsSink { - private final LineManager lineManager; - private final LineOptions lineOptions; - - LineBuilder(LineManager lineManager) { - this.lineManager = lineManager; - this.lineOptions = new LineOptions(); - } - - public LineOptions getLineOptions(){ - return this.lineOptions; - } - - Line build() { - return lineManager.create(lineOptions); - } - - @Override - public void setLineJoin(String lineJoin) { - lineOptions.withLineJoin(lineJoin); - } - - @Override - public void setLineOpacity(float lineOpacity) { - lineOptions.withLineOpacity(lineOpacity); - } - - @Override - public void setLineColor(String lineColor) { - lineOptions.withLineColor(lineColor); - } - - @Override - public void setLineWidth(float lineWidth) { - lineOptions.withLineWidth(lineWidth); - } - - @Override - public void setLineGapWidth(float lineGapWidth) { - lineOptions.withLineGapWidth(lineGapWidth); - } - - @Override - public void setLineOffset(float lineOffset) { - lineOptions.withLineOffset(lineOffset); - } - - @Override - public void setLineBlur(float lineBlur) { - lineOptions.withLineBlur(lineBlur); - } - - @Override - public void setLinePattern(String linePattern) { - lineOptions.withLinePattern(linePattern); - } - - @Override - public void setGeometry(List geometry) { - lineOptions.withLatLngs(geometry); - } - - @Override - public void setDraggable(boolean draggable) { - lineOptions.withDraggable(draggable); - } -} \ No newline at end of file diff --git a/android/src/main/java/com/mapbox/mapboxgl/LineController.java b/android/src/main/java/com/mapbox/mapboxgl/LineController.java deleted file mode 100644 index 27ae7e06e..000000000 --- a/android/src/main/java/com/mapbox/mapboxgl/LineController.java +++ /dev/null @@ -1,112 +0,0 @@ -// This file is generated. - -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package com.mapbox.mapboxgl; - -import java.util.ArrayList; -import java.util.List; - -import android.graphics.PointF; -import android.util.Log; - -import com.mapbox.geojson.Point; -import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.plugins.annotation.Line; -import com.mapbox.mapboxsdk.plugins.annotation.LineManager; -import android.graphics.Color; - -/** - * Controller of a single Line on the map. - */ -class LineController implements LineOptionsSink { - private final Line line; - private final OnLineTappedListener onTappedListener; - private boolean consumeTapEvents; - - LineController(Line line, boolean consumeTapEvents, OnLineTappedListener onTappedListener) { - this.line = line; - this.consumeTapEvents = consumeTapEvents; - this.onTappedListener = onTappedListener; - } - - public Line getLine(){ - return this.line; - } - - boolean onTap() { - if (onTappedListener != null) { - onTappedListener.onLineTapped(line); - } - return consumeTapEvents; - } - - void remove(LineManager lineManager) { - lineManager.delete(line); - } - - @Override - public void setLineJoin(String lineJoin) { - line.setLineJoin(lineJoin); - } - - @Override - public void setLineOpacity(float lineOpacity) { - line.setLineOpacity(lineOpacity); - } - - @Override - public void setLineColor(String lineColor) { - line.setLineColor(Color.parseColor(lineColor)); - } - - @Override - public void setLineWidth(float lineWidth) { - line.setLineWidth(lineWidth); - } - - @Override - public void setLineGapWidth(float lineGapWidth) { - line.setLineGapWidth(lineGapWidth); - } - - @Override - public void setLineOffset(float lineOffset) { - line.setLineOffset(lineOffset); - } - - @Override - public void setLineBlur(float lineBlur) { - line.setLineBlur(lineBlur); - } - - @Override - public void setLinePattern(String linePattern) { - line.setLinePattern(linePattern); - } - - @Override - public void setGeometry(List geometry) { - line.setLatLngs(geometry); - } - - public List getGeometry() { - List points = line.getGeometry().coordinates(); - List latLngs = new ArrayList<>(); - for (Point point : points) { - latLngs.add(new LatLng(point.latitude(), point.longitude())); - } - return latLngs; - } - - @Override - public void setDraggable(boolean draggable) { - line.setDraggable(draggable); - } - - public void update(LineManager lineManager) { - lineManager.update(line); - } -} diff --git a/android/src/main/java/com/mapbox/mapboxgl/LineOptionsSink.java b/android/src/main/java/com/mapbox/mapboxgl/LineOptionsSink.java deleted file mode 100644 index ddd2646b7..000000000 --- a/android/src/main/java/com/mapbox/mapboxgl/LineOptionsSink.java +++ /dev/null @@ -1,36 +0,0 @@ -// This file is generated. - -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package com.mapbox.mapboxgl; - -import java.util.List; -import com.mapbox.mapboxsdk.geometry.LatLng; - -/** - * Receiver of Line configuration options. - */ -interface LineOptionsSink { - - void setLineJoin(String lineJoin); - - void setLineOpacity(float lineOpacity); - - void setLineColor(String lineColor); - - void setLineWidth(float lineWidth); - - void setLineGapWidth(float lineGapWidth); - - void setLineOffset(float lineOffset); - - void setLineBlur(float lineBlur); - - void setLinePattern(String linePattern); - - void setGeometry(List geometry); - - void setDraggable(boolean draggable); -} diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java index f5a273bf1..1d2d6bdf8 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java +++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java @@ -19,6 +19,8 @@ import android.util.Log; import android.view.Gravity; import android.view.View; +import android.view.MotionEvent; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -33,6 +35,8 @@ import com.mapbox.android.core.location.LocationEngineCallback; import com.mapbox.android.core.location.LocationEngineProvider; import com.mapbox.android.core.location.LocationEngineResult; +import com.mapbox.android.gestures.MoveGestureDetector; +import com.mapbox.android.gestures.AndroidGesturesManager; import com.mapbox.android.telemetry.TelemetryEnabler; import com.mapbox.geojson.Feature; import com.mapbox.geojson.FeatureCollection; @@ -86,6 +90,7 @@ import com.mapbox.mapboxsdk.style.layers.PropertyValue; import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; + import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.PluginRegistry; @@ -117,17 +122,12 @@ final class MapboxMapController MapboxMap.OnCameraMoveListener, MapboxMap.OnCameraMoveStartedListener, MapView.OnDidBecomeIdleListener, - OnAnnotationClickListener, MapboxMap.OnMapClickListener, MapboxMap.OnMapLongClickListener, MapboxMapOptionsSink, MethodChannel.MethodCallHandler, OnMapReadyCallback, OnCameraTrackingChangedListener, - OnSymbolTappedListener, - OnLineTappedListener, - OnCircleTappedListener, - OnFillTappedListener, PlatformView { private static final String TAG = "MapboxMapController"; private final int id; @@ -135,14 +135,6 @@ final class MapboxMapController private final MapboxMapsPlugin.LifecycleProvider lifecycleProvider; private MapView mapView; private MapboxMap mapboxMap; - private final Map symbols; - private final Map lines; - private final Map circles; - private final Map fills; - private SymbolManager symbolManager; - private LineManager lineManager; - private CircleManager circleManager; - private FillManager fillManager; private boolean trackCameraPosition = false; private boolean myLocationEnabled = false; private int myLocationTrackingMode = 0; @@ -157,12 +149,14 @@ final class MapboxMapController private LocationEngineCallback locationEngineCallback = null; private LocalizationPlugin localizationPlugin; private Style style; - private List annotationOrder; - private List annotationConsumeTapEvents; + private Feature dragFeature; + private AndroidGesturesManager androidGesturesManager; + + private LatLng dragOrigin; + private LatLng dragPrevious; + private Set featureLayerIdentifiers; private LatLngBounds bounds = null; - private static final String annotationManagerNotCreatedErrorCode = "NO ANNOTATION MANAGER"; - private static final String annotationManagerNotCreatedErrorMessage = "To use %ss please add it to the annotation list"; MapboxMapController( int id, @@ -180,16 +174,12 @@ final class MapboxMapController this.styleStringInitial = styleStringInitial; this.mapView = new MapView(context, options); this.featureLayerIdentifiers = new HashSet<>(); - this.symbols = new HashMap<>(); - this.lines = new HashMap<>(); - this.circles = new HashMap<>(); - this.fills = new HashMap<>(); this.density = context.getResources().getDisplayMetrics().density; this.lifecycleProvider = lifecycleProvider; + this.androidGesturesManager = new AndroidGesturesManager(this.mapView.getContext(), false); + methodChannel = new MethodChannel(messenger, "plugins.flutter.io/mapbox_maps_" + id); methodChannel.setMethodCallHandler(this); - this.annotationOrder = annotationOrder; - this.annotationConsumeTapEvents = annotationConsumeTapEvents; } @Override @@ -214,71 +204,6 @@ private CameraPosition getCameraPosition() { return trackCameraPosition ? mapboxMap.getCameraPosition() : null; } - private SymbolController symbol(String symbolId) { - final SymbolController symbol = symbols.get(symbolId); - if (symbol == null) { - throw new IllegalArgumentException("Unknown symbol: " + symbolId); - } - return symbol; - } - - private LineBuilder newLineBuilder() { - return new LineBuilder(lineManager); - } - - private void removeLine(String lineId) { - final LineController lineController = lines.remove(lineId); - if (lineController != null) { - lineController.remove(lineManager); - } - } - - private LineController line(String lineId) { - final LineController line = lines.get(lineId); - if (line == null) { - throw new IllegalArgumentException("Unknown line: " + lineId); - } - return line; - } - - private CircleBuilder newCircleBuilder() { - return new CircleBuilder(circleManager); - } - - private void removeCircle(String circleId) { - final CircleController circleController = circles.remove(circleId); - if (circleController != null) { - circleController.remove(circleManager); - } - } - - private CircleController circle(String circleId) { - final CircleController circle = circles.get(circleId); - if (circle == null) { - throw new IllegalArgumentException("Unknown circle: " + circleId); - } - return circle; - } - - private FillBuilder newFillBuilder() { - return new FillBuilder(fillManager); - } - - private void removeFill(String fillId) { - final FillController fillController = fills.remove(fillId); - if (fillController != null) { - fillController.remove(fillManager); - } - } - - private FillController fill(String fillId) { - final FillController fill = fills.get(fillId); - if (fill == null) { - throw new IllegalArgumentException("Unknown fill: " + fillId); - } - return fill; - } - @Override public void onMapReady(MapboxMap mapboxMap) { this.mapboxMap = mapboxMap; @@ -289,6 +214,7 @@ public void onMapReady(MapboxMap mapboxMap) { mapboxMap.addOnCameraMoveStartedListener(this); mapboxMap.addOnCameraMoveListener(this); mapboxMap.addOnCameraIdleListener(this); + androidGesturesManager.setMoveGestureListener(new MoveGestureListener()); mapView.addOnStyleImageMissingListener((id) -> { DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); @@ -331,32 +257,6 @@ public void setStyleString(String styleString) { public void onStyleLoaded(@NonNull Style style) { MapboxMapController.this.style = style; - // only add managers once to avoid issues with getLayerId after a style switch - if(symbolManager == null && circleManager == null && lineManager == null && fillManager == null) - { - final List orderReversed = new ArrayList(annotationOrder); - Collections.reverse(orderReversed); - String belowLayer = null; - for(String annotationType : orderReversed) { - switch (annotationType) { - case "AnnotationType.fill": - belowLayer = enableFillManager(style, belowLayer); - break; - case "AnnotationType.line": - belowLayer = enableLineManager(style, belowLayer); - break; - case "AnnotationType.circle": - belowLayer = enableCircleManager(style, belowLayer); - break; - case "AnnotationType.symbol": - belowLayer = enableSymbolManager(style, belowLayer); - break; - default: - throw new IllegalArgumentException("Unknown annotation type: " + annotationType + ", must be either 'fill', 'line', 'circle' or 'symbol'"); - } - } - } - if (myLocationEnabled) { enableLocationComponent(style); } @@ -365,8 +265,6 @@ public void onStyleLoaded(@NonNull Style style) { mapboxMap.setLatLngBoundsForCameraTarget(bounds); } - // needs to be placed after SymbolManager#addClickListener, - // is fixed with 0.6.0 of annotations plugin mapboxMap.addOnMapClickListener(MapboxMapController.this); mapboxMap.addOnMapLongClickListener(MapboxMapController.this); localizationPlugin = new LocalizationPlugin(mapView, mapboxMap, style); @@ -520,7 +418,7 @@ private void addCircleLayer(String layerName, style.addLayer(circleLayer); } } - + private void addRasterLayer(String layerName, String sourceName, String belowLayerId, @@ -538,7 +436,7 @@ private void addRasterLayer(String layerName, } } - private void addHillshadeLayer(String layerName, + private void addHillshadeLayer(String layerName, String sourceName, String belowLayerId, PropertyValue[] properties, @@ -555,42 +453,6 @@ private void addHillshadeLayer(String layerName, } } - private String enableSymbolManager(@NonNull Style style, @Nullable String belowLayer) { - if (symbolManager == null) { - symbolManager = new SymbolManager(mapView, mapboxMap, style, belowLayer); - symbolManager.setIconAllowOverlap(true); - symbolManager.setIconIgnorePlacement(true); - symbolManager.setTextAllowOverlap(true); - symbolManager.setTextIgnorePlacement(true); - symbolManager.addClickListener(MapboxMapController.this::onAnnotationClick); - } - return symbolManager.getLayerId(); - } - - private String enableLineManager(@NonNull Style style, @Nullable String belowLayer) { - if (lineManager == null) { - lineManager = new LineManager(mapView, mapboxMap, style, belowLayer); - lineManager.addClickListener(MapboxMapController.this::onAnnotationClick); - } - return lineManager.getLayerId(); - } - - private String enableCircleManager(@NonNull Style style, @Nullable String belowLayer) { - if (circleManager == null) { - circleManager = new CircleManager(mapView, mapboxMap, style, belowLayer); - circleManager.addClickListener(MapboxMapController.this::onAnnotationClick); - } - return circleManager.getLayerId(); - } - - private String enableFillManager(@NonNull Style style, @Nullable String belowLayer) { - if (fillManager == null) { - fillManager = new FillManager(mapView, mapboxMap, style, belowLayer); - fillManager.addClickListener(MapboxMapController.this::onAnnotationClick); - } - return fillManager.getLayerId(); - } - private Feature firstFeatureOnLayers(RectF in) { if(style != null){ final List layers = style.getLayers(); @@ -812,406 +674,6 @@ public void onError(@NonNull String message) { }); break; } - case "symbols#addAll": { - if(symbolManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "symbol"), null); - return; - } - List newSymbolIds = new ArrayList(); - final List options = call.argument("options"); - List symbolOptionsList = new ArrayList(); - if (options != null) { - SymbolBuilder symbolBuilder; - for (Object o : options) { - symbolBuilder = new SymbolBuilder(); - Convert.interpretSymbolOptions(o, symbolBuilder); - symbolOptionsList.add(symbolBuilder.getSymbolOptions()); - } - if (!symbolOptionsList.isEmpty()) { - List newSymbols = symbolManager.create(symbolOptionsList); - String symbolId; - for (Symbol symbol : newSymbols) { - symbolId = String.valueOf(symbol.getId()); - newSymbolIds.add(symbolId); - symbols.put(symbolId, new SymbolController(symbol, annotationConsumeTapEvents.contains("AnnotationType.symbol"), this)); - } - } - } - result.success(newSymbolIds); - break; - } - case "symbols#removeAll": { - if(symbolManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "symbol"), null); - return; - } - final ArrayList symbolIds = call.argument("ids"); - SymbolController symbolController; - - List symbolList = new ArrayList(); - for(String symbolId : symbolIds){ - symbolController = symbols.remove(symbolId); - if (symbolController != null) { - symbolList.add(symbolController.getSymbol()); - } - } - if(!symbolList.isEmpty()) { - symbolManager.delete(symbolList); - } - result.success(null); - break; - } - case "symbol#update": { - if(symbolManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "symbol"), null); - return; - } - final String symbolId = call.argument("symbol"); - final SymbolController symbol = symbol(symbolId); - Convert.interpretSymbolOptions(call.argument("options"), symbol); - symbol.update(symbolManager); - result.success(null); - break; - } - case "symbol#getGeometry": { - if(symbolManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "symbol"), null); - return; - } - final String symbolId = call.argument("symbol"); - final SymbolController symbol = symbol(symbolId); - final LatLng symbolLatLng = symbol.getGeometry(); - Map hashMapLatLng = new HashMap<>(); - hashMapLatLng.put("latitude", symbolLatLng.getLatitude()); - hashMapLatLng.put("longitude", symbolLatLng.getLongitude()); - result.success(hashMapLatLng); - } - case "symbolManager#iconAllowOverlap": { - if(symbolManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "symbol"), null); - return; - } - final Boolean value = call.argument("iconAllowOverlap"); - symbolManager.setIconAllowOverlap(value); - result.success(null); - break; - } - case "symbolManager#iconIgnorePlacement": { - if(symbolManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "symbol"), null); - return; - } - final Boolean value = call.argument("iconIgnorePlacement"); - symbolManager.setIconIgnorePlacement(value); - result.success(null); - break; - } - case "symbolManager#textAllowOverlap": { - if(symbolManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "symbol"), null); - return; - } - final Boolean value = call.argument("textAllowOverlap"); - symbolManager.setTextAllowOverlap(value); - result.success(null); - break; - } - case "symbolManager#textIgnorePlacement": { - if(symbolManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "symbol"), null); - return; - } - final Boolean iconAllowOverlap = call.argument("textIgnorePlacement"); - symbolManager.setTextIgnorePlacement(iconAllowOverlap); - result.success(null); - break; - } - case "line#add": { - if(lineManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "line"), null); - return; - } - final LineBuilder lineBuilder = newLineBuilder(); - Convert.interpretLineOptions(call.argument("options"), lineBuilder); - final Line line = lineBuilder.build(); - final String lineId = String.valueOf(line.getId()); - lines.put(lineId, new LineController(line, annotationConsumeTapEvents.contains("AnnotationType.line"), this)); - result.success(lineId); - break; - } - case "line#remove": { - if(lineManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "line"), null); - return; - } - final String lineId = call.argument("line"); - removeLine(lineId); - result.success(null); - break; - } - case "line#addAll": { - if(lineManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "line"), null); - return; - } - List newIds = new ArrayList(); - final List options = call.argument("options"); - List optionList = new ArrayList(); - if (options != null) { - LineBuilder builder; - for (Object o : options) { - builder = newLineBuilder(); - Convert.interpretLineOptions(o, builder); - optionList.add(builder.getLineOptions()); - } - if (!optionList.isEmpty()) { - List newLines = lineManager.create(optionList); - String id; - for (Line line : newLines) { - id = String.valueOf(line.getId()); - newIds.add(id); - lines.put(id, new LineController(line, true, this)); - } - } - } - result.success(newIds); - break; - } - case "line#removeAll": { - if(lineManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "line"), null); - return; - } - final ArrayList ids = call.argument("ids"); - LineController lineController; - - List toBeRemoved = new ArrayList(); - for(String id : ids){ - lineController = lines.remove(id); - if (lineController != null) { - toBeRemoved.add(lineController.getLine()); - } - } - if(!toBeRemoved.isEmpty()) { - lineManager.delete(toBeRemoved); - } - result.success(null); - break; - } - case "line#update": { - if(lineManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "line"), null); - return; - } - final String lineId = call.argument("line"); - final LineController line = line(lineId); - Convert.interpretLineOptions(call.argument("options"), line); - line.update(lineManager); - result.success(null); - break; - } - case "line#getGeometry": { - if(lineManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "line"), null); - return; - } - final String lineId = call.argument("line"); - final LineController line = line(lineId); - final List lineLatLngs = line.getGeometry(); - final List resultList = new ArrayList<>(); - for (LatLng latLng: lineLatLngs){ - Map hashMapLatLng = new HashMap<>(); - hashMapLatLng.put("latitude", latLng.getLatitude()); - hashMapLatLng.put("longitude", latLng.getLongitude()); - resultList.add(hashMapLatLng); - } - result.success(resultList); - break; - } - case "circle#add": { - if(circleManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "circle"), null); - return; - } - final CircleBuilder circleBuilder = newCircleBuilder(); - Convert.interpretCircleOptions(call.argument("options"), circleBuilder); - final Circle circle = circleBuilder.build(); - final String circleId = String.valueOf(circle.getId()); - circles.put(circleId, new CircleController(circle, annotationConsumeTapEvents.contains("AnnotationType.circle"), this)); - result.success(circleId); - break; - } - case "circle#addAll": { - if(circleManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "circle"), null); - return; - } - List newIds = new ArrayList(); - final List options = call.argument("options"); - List optionList = new ArrayList(); - if (options != null) { - CircleBuilder builder; - for (Object o : options) { - builder = newCircleBuilder(); - Convert.interpretCircleOptions(o, builder); - optionList.add(builder.getCircleOptions()); - } - if (!optionList.isEmpty()) { - List newCircles = circleManager.create(optionList); - String id; - for (Circle circle : newCircles) { - id = String.valueOf(circle.getId()); - newIds.add(id); - circles.put(id, new CircleController(circle, true, this)); - } - } - } - result.success(newIds); - break; - } - case "circle#removeAll": { - if(circleManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "circle"), null); - return; - } - final ArrayList ids = call.argument("ids"); - CircleController circleController; - - List toBeRemoved = new ArrayList(); - for(String id : ids){ - circleController = circles.remove(id); - if (circleController != null) { - toBeRemoved.add(circleController.getCircle()); - } - } - if(!toBeRemoved.isEmpty()) { - circleManager.delete(toBeRemoved); - } - result.success(null); - break; - } - case "circle#remove": { - if(circleManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "circle"), null); - return; - } - final String circleId = call.argument("circle"); - removeCircle(circleId); - result.success(null); - break; - } - case "circle#update": { - if(circleManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "circle"), null); - return; - } - Log.e(TAG, "update circle"); - final String circleId = call.argument("circle"); - final CircleController circle = circle(circleId); - Convert.interpretCircleOptions(call.argument("options"), circle); - circle.update(circleManager); - result.success(null); - break; - } - case "circle#getGeometry": { - if(circleManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "circle"), null); - return; - } - final String circleId = call.argument("circle"); - final CircleController circle = circle(circleId); - final LatLng circleLatLng = circle.getGeometry(); - Map hashMapLatLng = new HashMap<>(); - hashMapLatLng.put("latitude", circleLatLng.getLatitude()); - hashMapLatLng.put("longitude", circleLatLng.getLongitude()); - result.success(hashMapLatLng); - break; - } - case "fill#add": { - if(fillManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "fill"), null); - return; - } - final FillBuilder fillBuilder = newFillBuilder(); - Convert.interpretFillOptions(call.argument("options"), fillBuilder); - final Fill fill = fillBuilder.build(); - final String fillId = String.valueOf(fill.getId()); - fills.put(fillId, new FillController(fill, annotationConsumeTapEvents.contains("AnnotationType.fill"), this)); - result.success(fillId); - break; - } - - case "fill#addAll": { - if(fillManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "fill"), null); - return; - } - List newIds = new ArrayList(); - final List options = call.argument("options"); - List optionList = new ArrayList(); - if (options != null) { - FillBuilder builder; - for (Object o : options) { - builder = newFillBuilder(); - Convert.interpretFillOptions(o, builder); - optionList.add(builder.getFillOptions()); - } - if (!optionList.isEmpty()) { - List newFills = fillManager.create(optionList); - String id; - for (Fill fill : newFills) { - id = String.valueOf(fill.getId()); - newIds.add(id); - fills.put(id, new FillController(fill, true, this)); - } - } - } - result.success(newIds); - break; - } - case "fill#removeAll": { - if(fillManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "fill"), null); - return; - } - final ArrayList ids = call.argument("ids"); - FillController fillController; - - List toBeRemoved = new ArrayList(); - for(String id : ids){ - fillController = fills.remove(id); - if (fillController != null) { - toBeRemoved.add(fillController.getFill()); - } - } - if(!toBeRemoved.isEmpty()) { - fillManager.delete(toBeRemoved); - } - result.success(null); - break; - } - case "fill#remove": { - if(fillManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "fill"), null); - return; - } - final String fillId = call.argument("fill"); - removeFill(fillId); - result.success(null); - break; - } - case "fill#update": { - if(fillManager == null){ - result.error(annotationManagerNotCreatedErrorCode, String.format(annotationManagerNotCreatedErrorCode, "fill"), null); - return; - } - final String fillId = call.argument("fill"); - final FillController fill = fill(fillId); - Convert.interpretFillOptions(call.argument("options"), fill); - fill.update(fillManager); - result.success(null); - break; - } case "source#addGeoJson": { final String sourceId = call.argument("sourceId"); final String geojson = call.argument("geojson"); @@ -1428,65 +890,6 @@ public void onDidBecomeIdle() { methodChannel.invokeMethod("map#onIdle", new HashMap<>()); } - @Override - public boolean onAnnotationClick(Annotation annotation) { - if (annotation instanceof Symbol) { - final SymbolController symbolController = symbols.get(String.valueOf(annotation.getId())); - if (symbolController != null) { - return symbolController.onTap(); - } - } - - if (annotation instanceof Line) { - final LineController lineController = lines.get(String.valueOf(annotation.getId())); - if (lineController != null) { - return lineController.onTap(); - } - } - - if (annotation instanceof Circle) { - final CircleController circleController = circles.get(String.valueOf(annotation.getId())); - if (circleController != null) { - return circleController.onTap(); - } - } - if (annotation instanceof Fill) { - final FillController fillController = fills.get(String.valueOf(annotation.getId())); - if (fillController != null) { - return fillController.onTap(); - } - } - return false; - } - - @Override - public void onSymbolTapped(Symbol symbol) { - final Map arguments = new HashMap<>(2); - arguments.put("symbol", String.valueOf(symbol.getId())); - methodChannel.invokeMethod("symbol#onTap", arguments); - } - - @Override - public void onLineTapped(Line line) { - final Map arguments = new HashMap<>(2); - arguments.put("line", String.valueOf(line.getId())); - methodChannel.invokeMethod("line#onTap", arguments); - } - - @Override - public void onCircleTapped(Circle circle) { - final Map arguments = new HashMap<>(2); - arguments.put("circle", String.valueOf(circle.getId())); - methodChannel.invokeMethod("circle#onTap", arguments); - } - - @Override - public void onFillTapped(Fill fill) { - final Map arguments = new HashMap<>(2); - arguments.put("fill", String.valueOf(fill.getId())); - methodChannel.invokeMethod("fill#onTap", arguments); - } - @Override public boolean onMapClick(@NonNull LatLng point) { PointF pointf = mapboxMap.getProjection().toScreenLocation(point); @@ -1545,18 +948,6 @@ private void destroyMapViewIfNecessary() { if (locationComponent != null) { locationComponent.setLocationComponentEnabled(false); } - if (symbolManager != null) { - symbolManager.onDestroy(); - } - if (lineManager != null) { - lineManager.onDestroy(); - } - if (circleManager != null) { - circleManager.onDestroy(); - } - if (fillManager != null) { - fillManager.onDestroy(); - } stopListeningForLocationUpdates(); mapView.onDestroy(); @@ -1903,4 +1294,102 @@ public void onFinish() { public void onCancel() { } } + + boolean onMoveBegin(MoveGestureDetector detector) { + Log.d(TAG, "onMoveBegin"); + if (detector.getPointersCount() == 1) { + PointF pointf = detector.getFocalPoint(); + LatLng origin = mapboxMap.getProjection().fromScreenLocation(pointf); + RectF rectF = new RectF( + pointf.x - 10, + pointf.y - 10, + pointf.x + 10, + pointf.y + 10 + ); + Feature feature = firstFeatureOnLayers(rectF); + if (feature != null && startDragging(feature, origin)) { + return true; + } + } + return false; + } + + + boolean onMove(MoveGestureDetector detector) { + Log.d(TAG, "onMove"); + if (dragFeature != null && detector.getPointersCount() > 1) { + stopDragging(); + return true; + } + + if (dragFeature != null) { + PointF pointf = detector.getFocalPoint(); + LatLng current = mapboxMap.getProjection().fromScreenLocation(pointf); + + final Map arguments = new HashMap<>(9); + arguments.put("id", dragFeature.id()); + arguments.put("x", pointf.x); + arguments.put("y", pointf.y); + + arguments.put("originLng", dragOrigin.getLongitude()); + arguments.put("originLat", dragOrigin.getLatitude()); + arguments.put("currentLng", current.getLongitude()); + arguments.put("currentLat", current.getLatitude()); + arguments.put("deltaLng", current.getLongitude() - dragPrevious.getLongitude()); + arguments.put("deltaLat", current.getLatitude() - dragPrevious.getLatitude()); + + methodChannel.invokeMethod("feature#onDrag", arguments); + dragPrevious = current; + return false; + } + return true; + } + + void onMoveEnd() { + Log.d(TAG, "onMoveEnd"); + stopDragging(); + } + + boolean startDragging(@NonNull Feature feature, @NonNull LatLng origin) { + // try{ + //TODO draggable wrong type + Log.d(TAG, "startDragging"); + final boolean draggable = feature.getBooleanProperty("draggable"); + if (draggable) { + dragFeature = feature; + dragPrevious = origin; + dragOrigin = origin; + return true; + } + // }catch(GeoJsonException e){} + return false; + } + + + void stopDragging() { + Log.d(TAG, "stopDragging"); + dragFeature = null; + dragOrigin = null; + dragPrevious = null; + } + + + + private class MoveGestureListener implements MoveGestureDetector.OnMoveGestureListener { + + @Override + public boolean onMoveBegin(MoveGestureDetector detector) { + return MapboxMapController.this.onMoveBegin(detector); + } + + @Override + public boolean onMove(MoveGestureDetector detector, float distanceX, float distanceY) { + return MapboxMapController.this.onMove(detector); + } + + @Override + public void onMoveEnd(MoveGestureDetector detector, float velocityX, float velocityY) { + MapboxMapController.this.onMoveEnd(); + } + } } diff --git a/android/src/main/java/com/mapbox/mapboxgl/OnCircleTappedListener.java b/android/src/main/java/com/mapbox/mapboxgl/OnCircleTappedListener.java deleted file mode 100644 index c2988d596..000000000 --- a/android/src/main/java/com/mapbox/mapboxgl/OnCircleTappedListener.java +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package com.mapbox.mapboxgl; - -import com.mapbox.mapboxsdk.plugins.annotation.Circle; - -interface OnCircleTappedListener { - void onCircleTapped(Circle circle); -} diff --git a/android/src/main/java/com/mapbox/mapboxgl/OnFillTappedListener.java b/android/src/main/java/com/mapbox/mapboxgl/OnFillTappedListener.java deleted file mode 100644 index 27eb86425..000000000 --- a/android/src/main/java/com/mapbox/mapboxgl/OnFillTappedListener.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.mapbox.mapboxgl; - -import com.mapbox.mapboxsdk.plugins.annotation.Fill; - -public interface OnFillTappedListener { - void onFillTapped(Fill fill); -} diff --git a/android/src/main/java/com/mapbox/mapboxgl/OnLineTappedListener.java b/android/src/main/java/com/mapbox/mapboxgl/OnLineTappedListener.java deleted file mode 100644 index 325f5277c..000000000 --- a/android/src/main/java/com/mapbox/mapboxgl/OnLineTappedListener.java +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package com.mapbox.mapboxgl; - -import com.mapbox.mapboxsdk.plugins.annotation.Line; - -interface OnLineTappedListener { - void onLineTapped(Line line); -} diff --git a/android/src/main/java/com/mapbox/mapboxgl/OnSymbolTappedListener.java b/android/src/main/java/com/mapbox/mapboxgl/OnSymbolTappedListener.java deleted file mode 100644 index 9e567e74a..000000000 --- a/android/src/main/java/com/mapbox/mapboxgl/OnSymbolTappedListener.java +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package com.mapbox.mapboxgl; - -import com.mapbox.mapboxsdk.plugins.annotation.Symbol; - -interface OnSymbolTappedListener { - void onSymbolTapped(Symbol symbol); -} diff --git a/android/src/main/java/com/mapbox/mapboxgl/SymbolBuilder.java b/android/src/main/java/com/mapbox/mapboxgl/SymbolBuilder.java deleted file mode 100644 index 93e2718af..000000000 --- a/android/src/main/java/com/mapbox/mapboxgl/SymbolBuilder.java +++ /dev/null @@ -1,168 +0,0 @@ -// This file is generated. - -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package com.mapbox.mapboxgl; - -import com.mapbox.geojson.Point; -import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.plugins.annotation.Symbol; -import com.mapbox.mapboxsdk.plugins.annotation.SymbolManager; -import com.mapbox.mapboxsdk.plugins.annotation.SymbolOptions; - -class SymbolBuilder implements SymbolOptionsSink { - private final SymbolOptions symbolOptions; - private static boolean customImage; - - SymbolBuilder() { - this.symbolOptions = new SymbolOptions(); - } - - public SymbolOptions getSymbolOptions(){ - return this.symbolOptions; - } - - @Override - public void setIconSize(float iconSize) { - symbolOptions.withIconSize(iconSize); - } - - @Override - public void setIconImage(String iconImage) { - symbolOptions.withIconImage(iconImage); - } - - @Override - public void setIconRotate(float iconRotate) { - symbolOptions.withIconRotate(iconRotate); - } - - @Override - public void setIconOffset(float[] iconOffset) { - symbolOptions.withIconOffset(new Float[] {iconOffset[0], iconOffset[1]}); - } - - @Override - public void setIconAnchor(String iconAnchor) { - symbolOptions.withIconAnchor(iconAnchor); - } - - @Override - public void setFontNames(String[] fontNames) { symbolOptions.withTextFont(fontNames); } - - @Override - public void setTextField(String textField) { - symbolOptions.withTextField(textField); - } - - @Override - public void setTextSize(float textSize) { - symbolOptions.withTextSize(textSize); - } - - @Override - public void setTextMaxWidth(float textMaxWidth) { - symbolOptions.withTextMaxWidth(textMaxWidth); - } - - @Override - public void setTextLetterSpacing(float textLetterSpacing) { - symbolOptions.withTextLetterSpacing(textLetterSpacing); - } - - @Override - public void setTextJustify(String textJustify) { - symbolOptions.withTextJustify(textJustify); - } - - @Override - public void setTextAnchor(String textAnchor) { - symbolOptions.withTextAnchor(textAnchor); - } - - @Override - public void setTextRotate(float textRotate) { - symbolOptions.withTextRotate(textRotate); - } - - @Override - public void setTextTransform(String textTransform) { - symbolOptions.withTextTransform(textTransform); - } - - @Override - public void setTextOffset(float[] textOffset) { - symbolOptions.withTextOffset(new Float[] {textOffset[0], textOffset[1]}); - } - - @Override - public void setIconOpacity(float iconOpacity) { - symbolOptions.withIconOpacity(iconOpacity); - } - - @Override - public void setIconColor(String iconColor) { - symbolOptions.withIconColor(iconColor); - } - - @Override - public void setIconHaloColor(String iconHaloColor) { - symbolOptions.withIconHaloColor(iconHaloColor); - } - - @Override - public void setIconHaloWidth(float iconHaloWidth) { - symbolOptions.withIconHaloWidth(iconHaloWidth); - } - - @Override - public void setIconHaloBlur(float iconHaloBlur) { - symbolOptions.withIconHaloBlur(iconHaloBlur); - } - - @Override - public void setTextOpacity(float textOpacity) { - symbolOptions.withTextOpacity(textOpacity); - } - - @Override - public void setTextColor(String textColor) { - symbolOptions.withTextColor(textColor); - } - - @Override - public void setTextHaloColor(String textHaloColor) { - symbolOptions.withTextHaloColor(textHaloColor); - } - - @Override - public void setTextHaloWidth(float textHaloWidth) { - symbolOptions.withTextHaloWidth(textHaloWidth); - } - - @Override - public void setTextHaloBlur(float textHaloBlur) { - symbolOptions.withTextHaloBlur(textHaloBlur); - } - - @Override - public void setGeometry(LatLng geometry) { - symbolOptions.withGeometry(Point.fromLngLat(geometry.getLongitude(), geometry.getLatitude())); - } - - @Override - public void setSymbolSortKey(float symbolSortKey) { - symbolOptions.withSymbolSortKey(symbolSortKey); - } - - @Override - 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/SymbolController.java b/android/src/main/java/com/mapbox/mapboxgl/SymbolController.java deleted file mode 100644 index 348779527..000000000 --- a/android/src/main/java/com/mapbox/mapboxgl/SymbolController.java +++ /dev/null @@ -1,191 +0,0 @@ -// This file is generated. - -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package com.mapbox.mapboxgl; - -import android.graphics.Color; -import android.graphics.PointF; -import com.mapbox.geojson.Point; -import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.plugins.annotation.Symbol; -import com.mapbox.mapboxsdk.plugins.annotation.SymbolManager; - -/** - * Controller of a single Symbol on the map. - */ -class SymbolController implements SymbolOptionsSink { - private final Symbol symbol; - private final OnSymbolTappedListener onTappedListener; - private boolean consumeTapEvents; - - SymbolController(Symbol symbol, boolean consumeTapEvents, OnSymbolTappedListener onTappedListener) { - this.symbol = symbol; - this.consumeTapEvents = consumeTapEvents; - this.onTappedListener = onTappedListener; - } - - boolean onTap() { - if (onTappedListener != null) { - onTappedListener.onSymbolTapped(symbol); - } - return consumeTapEvents; - } - - public Symbol getSymbol(){ - return this.symbol; - } - - void remove(SymbolManager symbolManager) { - symbolManager.delete(symbol); - } - - @Override - public void setIconSize(float iconSize) { - symbol.setIconSize(iconSize); - } - - @Override - public void setIconImage(String iconImage) { - symbol.setIconImage(iconImage); - } - - @Override - public void setIconRotate(float iconRotate) { - symbol.setIconRotate(iconRotate); - } - - @Override - public void setIconOffset(float[] iconOffset) { - symbol.setIconOffset(new PointF(iconOffset[0], iconOffset[1])); - } - - @Override - public void setIconAnchor(String iconAnchor) { - symbol.setIconAnchor(iconAnchor); - } - - @Override - public void setFontNames(String[] fontNames) { symbol.setTextFont(fontNames); } - - @Override - public void setTextField(String textField) { - symbol.setTextField(textField); - } - - @Override - public void setTextSize(float textSize) { - symbol.setTextSize(textSize); - } - - @Override - public void setTextMaxWidth(float textMaxWidth) { - symbol.setTextMaxWidth(textMaxWidth); - } - - @Override - public void setTextLetterSpacing(float textLetterSpacing) { - symbol.setTextLetterSpacing(textLetterSpacing); - } - - @Override - public void setTextJustify(String textJustify) { - symbol.setTextJustify(textJustify); - } - - @Override - public void setTextAnchor(String textAnchor) { - symbol.setTextAnchor(textAnchor); - } - - @Override - public void setTextRotate(float textRotate) { - symbol.setTextRotate(textRotate); - } - - @Override - public void setTextTransform(String textTransform) { - symbol.setTextTransform(textTransform); - } - - @Override - public void setTextOffset(float[] textOffset) { - symbol.setTextOffset(new PointF(textOffset[0], textOffset[1])); - } - - @Override - public void setIconOpacity(float iconOpacity) { - symbol.setIconOpacity(iconOpacity); - } - - @Override - public void setIconColor(String iconColor) { - symbol.setIconColor(Color.parseColor(iconColor)); - } - - @Override - public void setIconHaloColor(String iconHaloColor) { - symbol.setIconHaloColor(Color.parseColor(iconHaloColor)); - } - - @Override - public void setIconHaloWidth(float iconHaloWidth) { - symbol.setIconHaloWidth(iconHaloWidth); - } - - @Override - public void setIconHaloBlur(float iconHaloBlur) { - symbol.setIconHaloBlur(iconHaloBlur); - } - - @Override - public void setTextOpacity(float textOpacity) { - symbol.setTextOpacity(textOpacity); - } - - @Override - public void setTextColor(String textColor) { - symbol.setTextColor(Color.parseColor(textColor)); - } - - @Override - public void setTextHaloColor(String textHaloColor) { - symbol.setTextHaloColor(Color.parseColor(textHaloColor)); - } - - @Override - public void setTextHaloWidth(float textHaloWidth) { - symbol.setTextHaloWidth(textHaloWidth); - } - - @Override - public void setTextHaloBlur(float textHaloBlur) { - symbol.setTextHaloBlur(textHaloBlur); - } - - @Override - public void setSymbolSortKey(float symbolSortKey) { - symbol.setSymbolSortKey(symbolSortKey); - } - - @Override - public void setGeometry(LatLng geometry) { - symbol.setGeometry(Point.fromLngLat(geometry.getLongitude(), geometry.getLatitude())); - } - - public LatLng getGeometry() { - Point point = symbol.getGeometry(); - return new LatLng(point.latitude(), point.longitude()); - } - - @Override - public void setDraggable(boolean draggable) { - symbol.setDraggable(draggable); - } - - public void update(SymbolManager symbolManager) { - symbolManager.update(symbol); - } -} diff --git a/android/src/main/java/com/mapbox/mapboxgl/SymbolOptionsSink.java b/android/src/main/java/com/mapbox/mapboxgl/SymbolOptionsSink.java deleted file mode 100644 index ee52e8672..000000000 --- a/android/src/main/java/com/mapbox/mapboxgl/SymbolOptionsSink.java +++ /dev/null @@ -1,72 +0,0 @@ -// This file is generated. - -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package com.mapbox.mapboxgl; - -import com.mapbox.mapboxsdk.geometry.LatLng; - -/** - * Receiver of Symbol configuration options. - */ -interface SymbolOptionsSink { - - void setIconSize(float iconSize); - - void setIconImage(String iconImage); - - void setIconRotate(float iconRotate); - - void setIconOffset(float[] iconOffset); - - void setIconAnchor(String iconAnchor); - - void setFontNames(String[] fontNames); - - void setTextField(String textField); - - void setTextSize(float textSize); - - void setTextMaxWidth(float textMaxWidth); - - void setTextLetterSpacing(float textLetterSpacing); - - void setTextJustify(String textJustify); - - void setTextAnchor(String textAnchor); - - void setTextRotate(float textRotate); - - void setTextTransform(String textTransform); - - void setTextOffset(float[] textOffset); - - void setIconOpacity(float iconOpacity); - - void setIconColor(String iconColor); - - void setIconHaloColor(String iconHaloColor); - - void setIconHaloWidth(float iconHaloWidth); - - void setIconHaloBlur(float iconHaloBlur); - - void setTextOpacity(float textOpacity); - - void setTextColor(String textColor); - - void setTextHaloColor(String textHaloColor); - - void setTextHaloWidth(float textHaloWidth); - - void setTextHaloBlur(float textHaloBlur); - - void setGeometry(LatLng geometry); - - void setSymbolSortKey(float symbolSortKey); - - void setDraggable(boolean draggable); - -} diff --git a/example/lib/line.dart b/example/lib/line.dart index 88925cf8d..7720bab2a 100644 --- a/example/lib/line.dart +++ b/example/lib/line.dart @@ -67,8 +67,8 @@ class LineBodyState extends State { } Future _updateSelectedLine(LineOptions changes) { - _selectedLine = _selectedLine! - .copyWith(options: _selectedLine!.options.copyWith(changes)); + _selectedLine!.options = _selectedLine!.options.copyWith(changes); + return lineManager!.set(_selectedLine!); } @@ -95,14 +95,8 @@ class LineBodyState extends State { } _move() async { - final currentStart = _selectedLine!.options.geometry![0]; - final currentEnd = _selectedLine!.options.geometry![1]; - final end = - LatLng(currentEnd.latitude + 0.001, currentEnd.longitude + 0.001); - final start = - LatLng(currentStart.latitude - 0.001, currentStart.longitude - 0.001); - await controller! - .updateLine(_selectedLine!, LineOptions(geometry: [start, end])); + _selectedLine!.translate(LatLng(0.1, 0.1)); + await lineManager!.set(_selectedLine!); } void _remove() { diff --git a/example/lib/place_symbol.dart b/example/lib/place_symbol.dart index 1e618d327..b25a71854 100644 --- a/example/lib/place_symbol.dart +++ b/example/lib/place_symbol.dart @@ -87,8 +87,8 @@ class PlaceSymbolBodyState extends State { ); } - void _updateSelectedSymbol(SymbolOptions changes) { - controller!.updateSymbol(_selectedSymbol!, changes); + void _updateSelectedSymbol(SymbolOptions changes) async { + await controller!.updateSymbol(_selectedSymbol!, changes); } void _add(String iconImage) { diff --git a/lib/mapbox_gl.dart b/lib/mapbox_gl.dart index 1af48b0e1..5d23bb1ac 100644 --- a/lib/mapbox_gl.dart +++ b/lib/mapbox_gl.dart @@ -58,5 +58,5 @@ part 'src/download_region_status.dart'; part 'src/layer_expressions.dart'; part 'src/layer_properties.dart'; part 'src/color_tools.dart'; -part 'src/annotation.dart'; +part 'src/annotation_manager.dart'; part 'src/util.dart'; diff --git a/lib/src/annotation.dart b/lib/src/annotation_manager.dart similarity index 93% rename from lib/src/annotation.dart rename to lib/src/annotation_manager.dart index ffcf61929..ae60aa288 100644 --- a/lib/src/annotation.dart +++ b/lib/src/annotation_manager.dart @@ -4,11 +4,13 @@ abstract class AnnotationManager { final MapboxMapController controller; final void Function(T)? onTap; final _idToAnnotation = {}; - final id; + final String id; LayerProperties get properties; T? byId(String id) => _idToAnnotation[id]; + Set get annotations => _idToAnnotation.values.toSet(); + AnnotationManager(this.controller, {this.onTap}) : id = getRandomString(10) { controller.addGeoJsonSource(id, buildFeatureCollection([]), promoteId: "id"); @@ -94,10 +96,16 @@ class FillManager extends AnnotationManager { : super(controller, onTap: onTap); @override LayerProperties get properties => const FillLayerProperties( + // fillColor: "#FF00FF", fillOpacity: [Expressions.get, 'fillOpacity'], fillColor: [Expressions.get, 'fillColor'], fillOutlineColor: [Expressions.get, 'fillOutlineColor'], - fillPattern: [Expressions.get, 'fillPattern'], + fillPattern: [ + Expressions.match, + [Expressions.get, 'fillPattern'], + [Expressions.get, 'fillPattern'], + "empty" + ], ); } @@ -127,7 +135,7 @@ class SymbolManager extends AnnotationManager { iconOffset: [Expressions.get, 'iconOffset'], iconAnchor: [Expressions.get, 'iconAnchor'], textFont: [Expressions.get, 'fontNames'], - textField: [Expressions.get, 'textField'], + // textField: [Expressions.get, 'textField'], textSize: [Expressions.get, 'textSize'], textMaxWidth: [Expressions.get, 'textMaxWidth'], textLetterSpacing: [Expressions.get, 'textLetterSpacing'], @@ -146,6 +154,6 @@ class SymbolManager extends AnnotationManager { textHaloColor: [Expressions.get, 'textHaloColor'], textHaloWidth: [Expressions.get, 'textHaloWidth'], textHaloBlur: [Expressions.get, 'textHaloBlur'], - symbolZOrder: [Expressions.get, 'zIndex'], + // symbolZOrder: [Expressions.get, 'zIndex'], ); } diff --git a/lib/src/controller.dart b/lib/src/controller.dart index c9f93da54..987989155 100644 --- a/lib/src/controller.dart +++ b/lib/src/controller.dart @@ -61,30 +61,6 @@ class MapboxMapController extends ChangeNotifier { this.onCameraIdle, }) : _mapboxGlPlatform = mapboxGlPlatform { _cameraPosition = initialCameraPosition; - for (var type in annotationOrder.toSet()) { - switch (type) { - case AnnotationType.fill: - fillManager = FillManager(this, onTap: onFillTapped); - break; - case AnnotationType.line: - lineManager = LineManager(this, onTap: onLineTapped); - break; - case AnnotationType.circle: - circleManager = CircleManager(this, onTap: onCircleTapped); - break; - case AnnotationType.symbol: - symbolManager = SymbolManager(this, onTap: onSymbolTapped); - break; - default: - } - } - - _mapboxGlPlatform.onInfoWindowTappedPlatform.add((symbolId) { - final symbol = _symbols[symbolId]; - if (symbol != null) { - onInfoWindowTapped(symbol); - } - }); _mapboxGlPlatform.onFeatureTappedPlatform.add((payload) { for (final fun @@ -125,6 +101,23 @@ class MapboxMapController extends ChangeNotifier { }); _mapboxGlPlatform.onMapStyleLoadedPlatform.add((_) { + for (var type in annotationOrder.toSet()) { + switch (type) { + case AnnotationType.fill: + fillManager = FillManager(this, onTap: onFillTapped); + break; + case AnnotationType.line: + lineManager = LineManager(this, onTap: onLineTapped); + break; + case AnnotationType.circle: + circleManager = CircleManager(this, onTap: onCircleTapped); + break; + case AnnotationType.symbol: + symbolManager = SymbolManager(this, onTap: onSymbolTapped); + break; + default: + } + } if (onStyleLoadedCallback != null) { onStyleLoadedCallback!(); } @@ -204,14 +197,14 @@ class MapboxMapController extends ChangeNotifier { final onFeatureDrag = []; /// Callbacks to receive tap events for info windows on symbols + @Deprecated("InfoWindow tapped is no longer supported") final ArgumentCallbacks onInfoWindowTapped = ArgumentCallbacks(); /// The current set of symbols on this map. /// /// The returned set will be a detached snapshot of the symbols collection. - Set get symbols => Set.from(_symbols.values); - final Map _symbols = {}; + Set get symbols => symbolManager!.annotations; /// Callbacks to receive tap events for lines placed on this map. final ArgumentCallbacks onLineTapped = ArgumentCallbacks(); @@ -219,20 +212,17 @@ class MapboxMapController extends ChangeNotifier { /// The current set of lines on this map. /// /// The returned set will be a detached snapshot of the lines collection. - Set get lines => Set.from(_lines.values); - final Map _lines = {}; + Set get lines => lineManager!.annotations; /// The current set of circles on this map. /// /// The returned set will be a detached snapshot of the circles collection. - Set get circles => Set.from(_circles.values); - final Map _circles = {}; + Set get circles => circleManager!.annotations; /// The current set of fills on this map. /// /// The returned set will be a detached snapshot of the fills collection. - Set get fills => Set.from(_fills.values); - final Map _fills = {}; + Set get fills => fillManager!.annotations; /// True if the map camera is currently moving. bool get isCameraMoving => _isCameraMoving; @@ -538,7 +528,8 @@ class MapboxMapController extends ChangeNotifier { /// /// The returned [Future] completes once listeners have been notified. Future updateSymbol(Symbol symbol, SymbolOptions changes) async { - await symbolManager!.set(symbol.copyWith(options: changes)); + await symbolManager! + .set(symbol..options = symbol.options.copyWith(changes)); notifyListeners(); } @@ -630,8 +621,8 @@ class MapboxMapController extends ChangeNotifier { /// /// The returned [Future] completes once listeners have been notified. Future updateLine(Line line, LineOptions changes) async { - await lineManager!.set(line.copyWith(options: changes)); - + line.options = line.options.copyWith(changes); + await lineManager!.set(line); notifyListeners(); } @@ -725,7 +716,8 @@ class MapboxMapController extends ChangeNotifier { /// /// The returned [Future] completes once listeners have been notified. Future updateCircle(Circle circle, CircleOptions changes) async { - await circleManager!.set(circle.copyWith(options: changes)); + circle.options = circle.options.copyWith(changes); + await circleManager!.set(circle); notifyListeners(); } @@ -821,7 +813,8 @@ class MapboxMapController extends ChangeNotifier { /// /// The returned [Future] completes once listeners have been notified. Future updateFill(Fill fill, FillOptions changes) async { - await fillManager!.set(fill.copyWith(options: changes)); + fill.options = fill.options.copyWith(changes); + await fillManager!.set(fill); notifyListeners(); } diff --git a/mapbox_gl_platform_interface/lib/src/annotation.dart b/mapbox_gl_platform_interface/lib/src/annotation.dart index 99c2c5c76..8478d34c3 100644 --- a/mapbox_gl_platform_interface/lib/src/annotation.dart +++ b/mapbox_gl_platform_interface/lib/src/annotation.dart @@ -4,5 +4,5 @@ abstract class Annotation { String get id; Map toGeoJson(); - Annotation translate(LatLng delta); + void translate(LatLng delta); } diff --git a/mapbox_gl_platform_interface/lib/src/circle.dart b/mapbox_gl_platform_interface/lib/src/circle.dart index 47fc71755..5e0000805 100644 --- a/mapbox_gl_platform_interface/lib/src/circle.dart +++ b/mapbox_gl_platform_interface/lib/src/circle.dart @@ -25,14 +25,6 @@ class Circle implements Annotation { /// touch events. Add listeners to the owning map controller to track those. CircleOptions options; - Circle copyWith({String? id, Map? data, CircleOptions? options}) { - return Circle( - id ?? this.id, - options ?? this.options, - data ?? this.data, - ); - } - @override Map toGeoJson() { final geojson = options.toGeoJson(); @@ -43,11 +35,9 @@ class Circle implements Annotation { } @override - Annotation translate(LatLng delta) { - final options = this - .options + void translate(LatLng delta) { + options = options .copyWith(CircleOptions(geometry: this.options.geometry! + delta)); - return copyWith(options: options); } } @@ -126,8 +116,8 @@ class CircleOptions { "type": "Feature", "properties": toJson(false), "geometry": { - "type": "LineString", - if (geometry != null) "coordinates": geometry!.toJson() + "type": "Point", + "coordinates": geometry!.toGeoJsonCoordinates() } }; } diff --git a/mapbox_gl_platform_interface/lib/src/fill.dart b/mapbox_gl_platform_interface/lib/src/fill.dart index 15570e790..28d447639 100644 --- a/mapbox_gl_platform_interface/lib/src/fill.dart +++ b/mapbox_gl_platform_interface/lib/src/fill.dart @@ -40,18 +40,6 @@ class Fill implements Annotation { /// touch events. Add listeners to the owning map controller to track those. FillOptions options; - Fill copyWith({String? id, Map? data, FillOptions? options}) { - return Fill( - id ?? this.id, - options ?? this.options, - data ?? this.data, - ); - } - - @override - // TODO: implement draggable - bool get draggable => throw UnimplementedError(); - @override Map toGeoJson() { final geojson = options.toGeoJson(); @@ -62,8 +50,8 @@ class Fill implements Annotation { } @override - Annotation translate(LatLng delta) { - return copyWith(options: translateFillOptions(options, delta)); + void translate(LatLng delta) { + options = translateFillOptions(options, delta); } } @@ -134,12 +122,12 @@ class FillOptions { "type": "Feature", "properties": toJson(false), "geometry": { - "type": "LineString", - if (geometry != null) - "coordinates": geometry - ?.map((List latLngList) => - latLngList.map((LatLng latLng) => latLng.toJson()).toList()) - .toList() + "type": "Polygon", + "coordinates": geometry! + .map((List latLngList) => latLngList + .map((LatLng latLng) => latLng.toGeoJsonCoordinates()) + .toList()) + .toList() } }; } diff --git a/mapbox_gl_platform_interface/lib/src/line.dart b/mapbox_gl_platform_interface/lib/src/line.dart index 958e286cc..092a69ab8 100644 --- a/mapbox_gl_platform_interface/lib/src/line.dart +++ b/mapbox_gl_platform_interface/lib/src/line.dart @@ -25,15 +25,7 @@ class Line implements Annotation { /// /// The returned value does not reflect any changes made to the line through /// touch events. Add listeners to the owning map controller to track those. - final LineOptions options; - - Line copyWith({String? id, Map? data, LineOptions? options}) { - return Line( - id ?? this.id, - options ?? this.options, - data ?? this.data, - ); - } + LineOptions options; Map toGeoJson() { final geojson = options.toGeoJson(); @@ -44,10 +36,9 @@ class Line implements Annotation { } @override - Line translate(LatLng delta) { - final options = this.options.copyWith(LineOptions( + void translate(LatLng delta) { + options = options.copyWith(LineOptions( geometry: this.options.geometry?.map((e) => e + delta).toList())); - return copyWith(options: options); } } @@ -132,8 +123,7 @@ class LineOptions { "properties": toJson(false), "geometry": { "type": "LineString", - if (geometry != null) - "coordinates": geometry?.map((c) => c.toGeoJsonCoordinates()).toList() + "coordinates": geometry!.map((c) => c.toGeoJsonCoordinates()).toList() } }; } diff --git a/mapbox_gl_platform_interface/lib/src/symbol.dart b/mapbox_gl_platform_interface/lib/src/symbol.dart index 023cb2842..7d6ff6a09 100644 --- a/mapbox_gl_platform_interface/lib/src/symbol.dart +++ b/mapbox_gl_platform_interface/lib/src/symbol.dart @@ -26,14 +26,6 @@ class Symbol implements Annotation { /// touch events. Add listeners to the owning map controller to track those. SymbolOptions options; - Symbol copyWith({String? id, Map? data, SymbolOptions? options}) { - return Symbol( - id ?? this.id, - options ?? this.options, - data ?? this.data, - ); - } - @override Map toGeoJson() { final geojson = options.toGeoJson(); @@ -44,11 +36,9 @@ class Symbol implements Annotation { } @override - Annotation translate(LatLng delta) { - final options = this - .options + void translate(LatLng delta) { + options = options .copyWith(SymbolOptions(geometry: this.options.geometry! + delta)); - return copyWith(options: options); } } @@ -210,8 +200,8 @@ class SymbolOptions { "type": "Feature", "properties": toJson(false), "geometry": { - "type": "LineString", - if (geometry != null) "coordinates": geometry!.toJson() + "type": "Point", + "coordinates": geometry!.toGeoJsonCoordinates() } }; } From c84789f0746f6f8847fe797a4dfe8781b5aa320f Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Sun, 19 Dec 2021 18:48:19 +0100 Subject: [PATCH 09/26] fixed symbol text issues --- example/lib/place_symbol.dart | 2 ++ lib/src/annotation_manager.dart | 16 ++++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/example/lib/place_symbol.dart b/example/lib/place_symbol.dart index b25a71854..ae8b51cd8 100644 --- a/example/lib/place_symbol.dart +++ b/example/lib/place_symbol.dart @@ -126,6 +126,8 @@ class PlaceSymbolBodyState extends State { ) : SymbolOptions( geometry: geometry, + textField: 'Airport', + textOffset: Offset(0, 0.8), iconImage: iconImage, ); } diff --git a/lib/src/annotation_manager.dart b/lib/src/annotation_manager.dart index ae60aa288..8476afafd 100644 --- a/lib/src/annotation_manager.dart +++ b/lib/src/annotation_manager.dart @@ -96,15 +96,14 @@ class FillManager extends AnnotationManager { : super(controller, onTap: onTap); @override LayerProperties get properties => const FillLayerProperties( - // fillColor: "#FF00FF", fillOpacity: [Expressions.get, 'fillOpacity'], fillColor: [Expressions.get, 'fillColor'], fillOutlineColor: [Expressions.get, 'fillOutlineColor'], fillPattern: [ - Expressions.match, + Expressions.caseExpression, + [Expressions.has, 'fillPattern'], [Expressions.get, 'fillPattern'], - [Expressions.get, 'fillPattern'], - "empty" + null, ], ); } @@ -134,8 +133,13 @@ class SymbolManager extends AnnotationManager { iconRotate: [Expressions.get, 'iconRotate'], iconOffset: [Expressions.get, 'iconOffset'], iconAnchor: [Expressions.get, 'iconAnchor'], - textFont: [Expressions.get, 'fontNames'], - // textField: [Expressions.get, 'textField'], + textFont: [ + Expressions.caseExpression, + [Expressions.has, 'fontNames'], + [Expressions.get, 'fontNames'], + ["Open Sans Regular", "Arial Unicode MS Regular"], + ], + textField: [Expressions.get, 'textField'], textSize: [Expressions.get, 'textSize'], textMaxWidth: [Expressions.get, 'textMaxWidth'], textLetterSpacing: [Expressions.get, 'textLetterSpacing'], From e5b9d0d0c08ba2bdbca391d9033f799a0b8de4e0 Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Sun, 19 Dec 2021 19:41:17 +0100 Subject: [PATCH 10/26] fixed fill pattern issue --- lib/src/annotation_manager.dart | 179 +++++++++++++++++++------------- 1 file changed, 107 insertions(+), 72 deletions(-) diff --git a/lib/src/annotation_manager.dart b/lib/src/annotation_manager.dart index 8476afafd..94240e2dd 100644 --- a/lib/src/annotation_manager.dart +++ b/lib/src/annotation_manager.dart @@ -1,20 +1,28 @@ part of mapbox_gl; +int _getFirst(Annotation _) => 0; + abstract class AnnotationManager { final MapboxMapController controller; final void Function(T)? onTap; final _idToAnnotation = {}; final String id; - LayerProperties get properties; + List get allLayerProperties; + final int Function(T)? selectLayer; T? byId(String id) => _idToAnnotation[id]; Set get annotations => _idToAnnotation.values.toSet(); - AnnotationManager(this.controller, {this.onTap}) : id = getRandomString(10) { - controller.addGeoJsonSource(id, buildFeatureCollection([]), - promoteId: "id"); - controller.addLayer(id, id, properties); + AnnotationManager(this.controller, {this.onTap, this.selectLayer}) + : id = getRandomString(10) { + for (var i = 0; i < allLayerProperties.length; i++) { + final layerId = _makeLayerId(i); + controller.addGeoJsonSource(layerId, buildFeatureCollection([]), + promoteId: "id"); + controller.addLayer(layerId, layerId, allLayerProperties[i]); + } + if (onTap != null) { controller.onFeatureTapped.add(_onFeatureTapped); } @@ -27,14 +35,30 @@ abstract class AnnotationManager { } } + String _makeLayerId(int layerIndex) => "${id}_$layerIndex"; + Future _setAll() async { - return controller.setGeoJsonSource( - id, - buildFeatureCollection( - [for (final l in _idToAnnotation.values) l.toGeoJson()])); + if (selectLayer != null) { + final featureBuckets = [for (final _ in allLayerProperties) []]; + + for (final annotation in _idToAnnotation.values) { + featureBuckets[selectLayer!(annotation)].add(annotation); + } + + for (var i = 0; i < featureBuckets.length; i++) { + await controller.setGeoJsonSource( + _makeLayerId(i), + buildFeatureCollection( + [for (final l in featureBuckets[i]) l.toGeoJson()])); + } + } else { + await controller.setGeoJsonSource( + _makeLayerId(0), + buildFeatureCollection( + [for (final l in _idToAnnotation.values) l.toGeoJson()])); + } } - @override Future addAll(Iterable annotations) async { for (var a in annotations) { _idToAnnotation[a.id] = a; @@ -81,83 +105,94 @@ class LineManager extends AnnotationManager { LineManager(MapboxMapController controller, {void Function(Line)? onTap}) : super(controller, onTap: onTap); @override - LayerProperties get properties => const LineLayerProperties( - lineOpacity: [Expressions.get, 'lineOpacity'], - lineColor: [Expressions.get, 'lineColor'], - lineWidth: [Expressions.get, 'lineWidth'], - lineGapWidth: [Expressions.get, 'lineGapWidth'], - lineOffset: [Expressions.get, 'lineOffset'], - lineBlur: [Expressions.get, 'lineBlur'], - ); + List get allLayerProperties => const [ + LineLayerProperties( + lineOpacity: [Expressions.get, 'lineOpacity'], + lineColor: [Expressions.get, 'lineColor'], + lineWidth: [Expressions.get, 'lineWidth'], + lineGapWidth: [Expressions.get, 'lineGapWidth'], + lineOffset: [Expressions.get, 'lineOffset'], + lineBlur: [Expressions.get, 'lineBlur'], + ) + ]; } class FillManager extends AnnotationManager { FillManager(MapboxMapController controller, {void Function(Fill)? onTap}) - : super(controller, onTap: onTap); + : super(controller, + onTap: onTap, + selectLayer: (Fill fill) => + fill.options.fillPattern == null ? 0 : 1); @override - LayerProperties get properties => const FillLayerProperties( - fillOpacity: [Expressions.get, 'fillOpacity'], - fillColor: [Expressions.get, 'fillColor'], - fillOutlineColor: [Expressions.get, 'fillOutlineColor'], - fillPattern: [ - Expressions.caseExpression, - [Expressions.has, 'fillPattern'], - [Expressions.get, 'fillPattern'], - null, - ], - ); + List get allLayerProperties => const [ + FillLayerProperties( + fillOpacity: [Expressions.get, 'fillOpacity'], + fillColor: [Expressions.get, 'fillColor'], + fillOutlineColor: [Expressions.get, 'fillOutlineColor'], + ), + FillLayerProperties( + fillOpacity: [Expressions.get, 'fillOpacity'], + fillColor: [Expressions.get, 'fillColor'], + fillOutlineColor: [Expressions.get, 'fillOutlineColor'], + fillPattern: [Expressions.get, 'fillPattern'], + ) + ]; } class CircleManager extends AnnotationManager { CircleManager(MapboxMapController controller, {void Function(Circle)? onTap}) : super(controller, onTap: onTap); @override - LayerProperties get properties => const CircleLayerProperties( - circleRadius: [Expressions.get, 'circleRadius'], - circleColor: [Expressions.get, 'circleColor'], - circleBlur: [Expressions.get, 'circleBlur'], - circleOpacity: [Expressions.get, 'circleOpacity'], - circleStrokeWidth: [Expressions.get, 'circleStrokeWidth'], - circleStrokeColor: [Expressions.get, 'circleStrokeColor'], - circleStrokeOpacity: [Expressions.get, 'circleStrokeOpacity'], - ); + List get allLayerProperties => const [ + CircleLayerProperties( + circleRadius: [Expressions.get, 'circleRadius'], + circleColor: [Expressions.get, 'circleColor'], + circleBlur: [Expressions.get, 'circleBlur'], + circleOpacity: [Expressions.get, 'circleOpacity'], + circleStrokeWidth: [Expressions.get, 'circleStrokeWidth'], + circleStrokeColor: [Expressions.get, 'circleStrokeColor'], + circleStrokeOpacity: [Expressions.get, 'circleStrokeOpacity'], + ) + ]; } class SymbolManager extends AnnotationManager { SymbolManager(MapboxMapController controller, {void Function(Symbol)? onTap}) : super(controller, onTap: onTap); @override - LayerProperties get properties => const SymbolLayerProperties( - iconSize: [Expressions.get, 'iconSize'], - iconImage: [Expressions.get, 'iconImage'], - iconRotate: [Expressions.get, 'iconRotate'], - iconOffset: [Expressions.get, 'iconOffset'], - iconAnchor: [Expressions.get, 'iconAnchor'], - textFont: [ - Expressions.caseExpression, - [Expressions.has, 'fontNames'], - [Expressions.get, 'fontNames'], - ["Open Sans Regular", "Arial Unicode MS Regular"], - ], - textField: [Expressions.get, 'textField'], - textSize: [Expressions.get, 'textSize'], - textMaxWidth: [Expressions.get, 'textMaxWidth'], - textLetterSpacing: [Expressions.get, 'textLetterSpacing'], - textJustify: [Expressions.get, 'textJustify'], - textAnchor: [Expressions.get, 'textAnchor'], - textRotate: [Expressions.get, 'textRotate'], - textTransform: [Expressions.get, 'textTransform'], - textOffset: [Expressions.get, 'textOffset'], - iconOpacity: [Expressions.get, 'iconOpacity'], - iconColor: [Expressions.get, 'iconColor'], - iconHaloColor: [Expressions.get, 'iconHaloColor'], - iconHaloWidth: [Expressions.get, 'iconHaloWidth'], - iconHaloBlur: [Expressions.get, 'iconHaloBlur'], - textOpacity: [Expressions.get, 'textOpacity'], - textColor: [Expressions.get, 'textColor'], - textHaloColor: [Expressions.get, 'textHaloColor'], - textHaloWidth: [Expressions.get, 'textHaloWidth'], - textHaloBlur: [Expressions.get, 'textHaloBlur'], - // symbolZOrder: [Expressions.get, 'zIndex'], - ); + List get allLayerProperties => const [ + SymbolLayerProperties( + iconSize: [Expressions.get, 'iconSize'], + iconImage: [Expressions.get, 'iconImage'], + iconRotate: [Expressions.get, 'iconRotate'], + iconOffset: [Expressions.get, 'iconOffset'], + iconAnchor: [Expressions.get, 'iconAnchor'], + textFont: [ + Expressions.caseExpression, + [Expressions.has, 'fontNames'], + [Expressions.get, 'fontNames'], + ["Open Sans Regular", "Arial Unicode MS Regular"], + ], + textField: [Expressions.get, 'textField'], + textSize: [Expressions.get, 'textSize'], + textMaxWidth: [Expressions.get, 'textMaxWidth'], + textLetterSpacing: [Expressions.get, 'textLetterSpacing'], + textJustify: [Expressions.get, 'textJustify'], + textAnchor: [Expressions.get, 'textAnchor'], + textRotate: [Expressions.get, 'textRotate'], + textTransform: [Expressions.get, 'textTransform'], + textOffset: [Expressions.get, 'textOffset'], + iconOpacity: [Expressions.get, 'iconOpacity'], + iconColor: [Expressions.get, 'iconColor'], + iconHaloColor: [Expressions.get, 'iconHaloColor'], + iconHaloWidth: [Expressions.get, 'iconHaloWidth'], + iconHaloBlur: [Expressions.get, 'iconHaloBlur'], + textOpacity: [Expressions.get, 'textOpacity'], + textColor: [Expressions.get, 'textColor'], + textHaloColor: [Expressions.get, 'textHaloColor'], + textHaloWidth: [Expressions.get, 'textHaloWidth'], + textHaloBlur: [Expressions.get, 'textHaloBlur'], + // symbolZOrder: [Expressions.get, 'zIndex'], + ) + ]; } From 76d55a449ca1d1308b5e79f645ed4225bc399a71 Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Sun, 19 Dec 2021 22:37:34 +0100 Subject: [PATCH 11/26] added support for symbol allow overlap --- example/lib/place_symbol.dart | 1 + lib/src/annotation_manager.dart | 70 +++++++++++++++++-- lib/src/controller.dart | 13 ++-- lib/src/mapbox_map.dart | 10 +-- mapbox_gl_web/lib/mapbox_gl_web.dart | 2 +- mapbox_gl_web/lib/src/mapbox_map_plugin.dart | 2 +- ...oller.dart => mapbox_web_gl_platform.dart} | 2 +- 7 files changed, 80 insertions(+), 20 deletions(-) rename mapbox_gl_web/lib/src/{mapbox_map_controller.dart => mapbox_web_gl_platform.dart} (99%) diff --git a/example/lib/place_symbol.dart b/example/lib/place_symbol.dart index ae8b51cd8..2edc59051 100644 --- a/example/lib/place_symbol.dart +++ b/example/lib/place_symbol.dart @@ -276,6 +276,7 @@ class PlaceSymbolBodyState extends State { _iconAllowOverlap = !_iconAllowOverlap; }); controller!.setSymbolIconAllowOverlap(_iconAllowOverlap); + controller!.setSymbolTextAllowOverlap(_iconAllowOverlap); } @override diff --git a/lib/src/annotation_manager.dart b/lib/src/annotation_manager.dart index 94240e2dd..1bb946c6c 100644 --- a/lib/src/annotation_manager.dart +++ b/lib/src/annotation_manager.dart @@ -28,6 +28,15 @@ abstract class AnnotationManager { } controller.onFeatureDrag.add(_onDrag); } + + Future rebuildLayers() async { + for (var i = 0; i < allLayerProperties.length; i++) { + final layerId = _makeLayerId(i); + await controller.removeLayer(layerId); + await controller.addLayer(layerId, layerId, allLayerProperties[i]); + } + } + _onFeatureTapped(dynamic id, Point point, LatLng coordinates) { final annotation = _idToAnnotation[id]; if (annotation != null) { @@ -82,6 +91,15 @@ abstract class AnnotationManager { await _setAll(); } + Future dispose() async { + _idToAnnotation.clear(); + await _setAll(); + for (var i = 0; i < allLayerProperties.length; i++) { + await controller.removeLayer(_makeLayerId(i)); + await controller.removeSource(_makeLayerId(i)); + } + } + _onDrag(dynamic id, {required Point point, required LatLng origin, @@ -157,10 +175,50 @@ class CircleManager extends AnnotationManager { } class SymbolManager extends AnnotationManager { - SymbolManager(MapboxMapController controller, {void Function(Symbol)? onTap}) - : super(controller, onTap: onTap); + SymbolManager( + MapboxMapController controller, { + void Function(Symbol)? onTap, + bool iconAllowOverlap = false, + bool textAllowOverlap = false, + bool iconIgnorePlacement = false, + bool textIgnorePlacement = false, + }) : _iconAllowOverlap = iconAllowOverlap, + _textAllowOverlap = textAllowOverlap, + _iconIgnorePlacement = iconIgnorePlacement, + _textIgnorePlacement = textIgnorePlacement, + super(controller, onTap: onTap); + + bool _iconAllowOverlap; + bool _textAllowOverlap; + bool _iconIgnorePlacement; + bool _textIgnorePlacement; + + /// For more information on what this does, see https://docs.mapbox.com/help/troubleshooting/optimize-map-label-placement/#label-collision + Future setIconAllowOverlap(bool value) async { + _iconAllowOverlap = value; + await rebuildLayers(); + } + + /// For more information on what this does, see https://docs.mapbox.com/help/troubleshooting/optimize-map-label-placement/#label-collision + Future setTextAllowOverlap(bool value) async { + _textAllowOverlap = value; + await rebuildLayers(); + } + + /// For more information on what this does, see https://docs.mapbox.com/help/troubleshooting/optimize-map-label-placement/#label-collision + Future setIconIgnorePlacement(bool value) async { + _iconIgnorePlacement = value; + await rebuildLayers(); + } + + /// For more information on what this does, see https://docs.mapbox.com/help/troubleshooting/optimize-map-label-placement/#label-collision + Future setTextIgnorePlacement(bool value) async { + _textIgnorePlacement = value; + await rebuildLayers(); + } + @override - List get allLayerProperties => const [ + List get allLayerProperties => [ SymbolLayerProperties( iconSize: [Expressions.get, 'iconSize'], iconImage: [Expressions.get, 'iconImage'], @@ -182,6 +240,8 @@ class SymbolManager extends AnnotationManager { textRotate: [Expressions.get, 'textRotate'], textTransform: [Expressions.get, 'textTransform'], textOffset: [Expressions.get, 'textOffset'], + iconAllowOverlap: _iconAllowOverlap, + iconIgnorePlacement: _iconIgnorePlacement, iconOpacity: [Expressions.get, 'iconOpacity'], iconColor: [Expressions.get, 'iconColor'], iconHaloColor: [Expressions.get, 'iconHaloColor'], @@ -192,7 +252,9 @@ class SymbolManager extends AnnotationManager { textHaloColor: [Expressions.get, 'textHaloColor'], textHaloWidth: [Expressions.get, 'textHaloWidth'], textHaloBlur: [Expressions.get, 'textHaloBlur'], - // symbolZOrder: [Expressions.get, 'zIndex'], + textAllowOverlap: _textAllowOverlap, + textIgnorePlacement: _textIgnorePlacement, + symbolSortKey: [Expressions.get, 'zIndex'], ) ]; } diff --git a/lib/src/controller.dart b/lib/src/controller.dart index 987989155..aa5f7b282 100644 --- a/lib/src/controller.dart +++ b/lib/src/controller.dart @@ -113,7 +113,10 @@ class MapboxMapController extends ChangeNotifier { circleManager = CircleManager(this, onTap: onCircleTapped); break; case AnnotationType.symbol: - symbolManager = SymbolManager(this, onTap: onSymbolTapped); + symbolManager = SymbolManager( + this, + onTap: onSymbolTapped, + ); break; default: } @@ -928,22 +931,22 @@ class MapboxMapController extends ChangeNotifier { /// For more information on what this does, see https://docs.mapbox.com/help/troubleshooting/optimize-map-label-placement/#label-collision Future setSymbolIconAllowOverlap(bool enable) async { - await _mapboxGlPlatform.setSymbolIconAllowOverlap(enable); + await symbolManager?.setIconAllowOverlap(enable); } /// For more information on what this does, see https://docs.mapbox.com/help/troubleshooting/optimize-map-label-placement/#label-collision Future setSymbolIconIgnorePlacement(bool enable) async { - await _mapboxGlPlatform.setSymbolIconIgnorePlacement(enable); + await symbolManager?.setIconIgnorePlacement(enable); } /// For more information on what this does, see https://docs.mapbox.com/help/troubleshooting/optimize-map-label-placement/#label-collision Future setSymbolTextAllowOverlap(bool enable) async { - await _mapboxGlPlatform.setSymbolTextAllowOverlap(enable); + await symbolManager?.setTextAllowOverlap(enable); } /// For more information on what this does, see https://docs.mapbox.com/help/troubleshooting/optimize-map-label-placement/#label-collision Future setSymbolTextIgnorePlacement(bool enable) async { - await _mapboxGlPlatform.setSymbolTextIgnorePlacement(enable); + await symbolManager?.setTextIgnorePlacement(enable); } /// Adds an image source to the style currently displayed in the map, so that it can later be referred to by the provided id. diff --git a/lib/src/mapbox_map.dart b/lib/src/mapbox_map.dart index 6b0819dce..f08171326 100644 --- a/lib/src/mapbox_map.dart +++ b/lib/src/mapbox_map.dart @@ -228,19 +228,13 @@ class _MapboxMapState extends State { @override Widget build(BuildContext context) { - final List annotationOrder = - widget.annotationOrder.map((e) => e.toString()).toList(); - assert(annotationOrder.toSet().length == annotationOrder.length, + assert( + widget.annotationOrder.toSet().length == widget.annotationOrder.length, "annotationOrder must not have duplicate types"); - final List annotationConsumeTapEvents = - widget.annotationConsumeTapEvents.map((e) => e.toString()).toList(); - final Map creationParams = { 'initialCameraPosition': widget.initialCameraPosition.toMap(), 'options': _MapboxMapOptions.fromWidget(widget).toMap(), 'accessToken': widget.accessToken, - 'annotationOrder': annotationOrder, - 'annotationConsumeTapEvents': annotationConsumeTapEvents, 'onAttributionClickOverride': widget.onAttributionClick != null, }; return _mapboxGlPlatform.buildView( diff --git a/mapbox_gl_web/lib/mapbox_gl_web.dart b/mapbox_gl_web/lib/mapbox_gl_web.dart index cf5af7666..14937246e 100644 --- a/mapbox_gl_web/lib/mapbox_gl_web.dart +++ b/mapbox_gl_web/lib/mapbox_gl_web.dart @@ -23,4 +23,4 @@ import 'package:mapbox_gl_web/src/layer_tools.dart'; part 'src/convert.dart'; part 'src/mapbox_map_plugin.dart'; part 'src/options_sink.dart'; -part 'src/mapbox_map_controller.dart'; +part 'src/mapbox_web_gl_platform.dart'; diff --git a/mapbox_gl_web/lib/src/mapbox_map_plugin.dart b/mapbox_gl_web/lib/src/mapbox_map_plugin.dart index dcc779d70..68f7975f5 100644 --- a/mapbox_gl_web/lib/src/mapbox_map_plugin.dart +++ b/mapbox_gl_web/lib/src/mapbox_map_plugin.dart @@ -3,6 +3,6 @@ part of mapbox_gl_web; class MapboxMapPlugin { /// Registers this class as the default instance of [MapboxGlPlatform]. static void registerWith(Registrar registrar) { - MapboxGlPlatform.createInstance = () => MapboxMapController(); + MapboxGlPlatform.createInstance = () => MapboxWebGlPlatform(); } } diff --git a/mapbox_gl_web/lib/src/mapbox_map_controller.dart b/mapbox_gl_web/lib/src/mapbox_web_gl_platform.dart similarity index 99% rename from mapbox_gl_web/lib/src/mapbox_map_controller.dart rename to mapbox_gl_web/lib/src/mapbox_web_gl_platform.dart index bdc602aba..e911d3089 100644 --- a/mapbox_gl_web/lib/src/mapbox_map_controller.dart +++ b/mapbox_gl_web/lib/src/mapbox_web_gl_platform.dart @@ -3,7 +3,7 @@ part of mapbox_gl_web; const _mapboxGlCssUrl = 'https://api.mapbox.com/mapbox-gl-js/v2.6.1/mapbox-gl.css'; -class MapboxMapController extends MapboxGlPlatform +class MapboxWebGlPlatform extends MapboxGlPlatform implements MapboxMapOptionsSink { late DivElement _mapElement; From bb3187ff6f35bc541f7c1ed21479467d89d7bc78 Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Sun, 19 Dec 2021 23:12:46 +0100 Subject: [PATCH 12/26] working android drag --- .../mapbox/mapboxgl/MapboxMapController.java | 30 +++++++++++-------- lib/src/annotation_manager.dart | 4 +-- .../lib/src/fill.dart | 2 +- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java index 1d2d6bdf8..91a3aeacc 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java +++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java @@ -149,7 +149,7 @@ final class MapboxMapController private LocationEngineCallback locationEngineCallback = null; private LocalizationPlugin localizationPlugin; private Style style; - private Feature dragFeature; + private Feature draggedFeature; private AndroidGesturesManager androidGesturesManager; private LatLng dragOrigin; @@ -216,6 +216,16 @@ public void onMapReady(MapboxMap mapboxMap) { mapboxMap.addOnCameraIdleListener(this); androidGesturesManager.setMoveGestureListener(new MoveGestureListener()); + mapView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + Feature feature = draggedFeature; + androidGesturesManager.onTouchEvent(event); + + return feature != null; + } + }); + mapView.addOnStyleImageMissingListener((id) -> { DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); final Bitmap bitmap = getScaledImage(id, displayMetrics.density); @@ -1296,7 +1306,6 @@ public void onCancel() { } boolean onMoveBegin(MoveGestureDetector detector) { - Log.d(TAG, "onMoveBegin"); if (detector.getPointersCount() == 1) { PointF pointf = detector.getFocalPoint(); LatLng origin = mapboxMap.getProjection().fromScreenLocation(pointf); @@ -1316,18 +1325,17 @@ boolean onMoveBegin(MoveGestureDetector detector) { boolean onMove(MoveGestureDetector detector) { - Log.d(TAG, "onMove"); - if (dragFeature != null && detector.getPointersCount() > 1) { + if (draggedFeature != null && detector.getPointersCount() > 1) { stopDragging(); return true; } - if (dragFeature != null) { + if (draggedFeature != null) { PointF pointf = detector.getFocalPoint(); LatLng current = mapboxMap.getProjection().fromScreenLocation(pointf); final Map arguments = new HashMap<>(9); - arguments.put("id", dragFeature.id()); + arguments.put("id", draggedFeature.id()); arguments.put("x", pointf.x); arguments.put("y", pointf.y); @@ -1346,17 +1354,16 @@ boolean onMove(MoveGestureDetector detector) { } void onMoveEnd() { - Log.d(TAG, "onMoveEnd"); stopDragging(); } boolean startDragging(@NonNull Feature feature, @NonNull LatLng origin) { // try{ //TODO draggable wrong type - Log.d(TAG, "startDragging"); - final boolean draggable = feature.getBooleanProperty("draggable"); + final boolean draggable = feature.hasNonNullValueForProperty("draggable") ? + feature.getBooleanProperty("draggable") : false; if (draggable) { - dragFeature = feature; + draggedFeature = feature; dragPrevious = origin; dragOrigin = origin; return true; @@ -1367,8 +1374,7 @@ boolean startDragging(@NonNull Feature feature, @NonNull LatLng origin) { void stopDragging() { - Log.d(TAG, "stopDragging"); - dragFeature = null; + draggedFeature = null; dragOrigin = null; dragPrevious = null; } diff --git a/lib/src/annotation_manager.dart b/lib/src/annotation_manager.dart index 1bb946c6c..1844ad7fb 100644 --- a/lib/src/annotation_manager.dart +++ b/lib/src/annotation_manager.dart @@ -107,8 +107,8 @@ abstract class AnnotationManager { required LatLng delta}) { final annotation = byId(id); if (annotation != null) { - final moved = annotation.translate(delta) as T; - set(moved); + annotation.translate(delta); + set(annotation); } } diff --git a/mapbox_gl_platform_interface/lib/src/fill.dart b/mapbox_gl_platform_interface/lib/src/fill.dart index 28d447639..d645de9a7 100644 --- a/mapbox_gl_platform_interface/lib/src/fill.dart +++ b/mapbox_gl_platform_interface/lib/src/fill.dart @@ -16,7 +16,7 @@ FillOptions translateFillOptions(FillOptions options, LatLng delta) { } newGeometry.add(newRing); } - return FillOptions(geometry: newGeometry); + return options.copyWith(FillOptions(geometry: newGeometry)); } return options; } From 0dd07ecc68818fc3367a0961b61c1be932f3926d Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Sun, 19 Dec 2021 23:41:52 +0100 Subject: [PATCH 13/26] fixed ios issues --- ios/Classes/MapboxMapController.swift | 103 ++++++++++++++------------ lib/src/annotation_manager.dart | 5 +- 2 files changed, 60 insertions(+), 48 deletions(-) diff --git a/ios/Classes/MapboxMapController.swift b/ios/Classes/MapboxMapController.swift index 30ef72af2..282265c6b 100644 --- a/ios/Classes/MapboxMapController.swift +++ b/ios/Classes/MapboxMapController.swift @@ -546,6 +546,62 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma mapView.style?.insertLayer(layer, below: belowLayer) result(nil) + case "symbolLayer#add": + guard let arguments = methodCall.arguments as? [String: Any] else { return } + guard let sourceId = arguments["sourceId"] as? String else { return } + guard let layerId = arguments["layerId"] as? String else { return } + guard let properties = arguments["properties"] as? [String: String] else { return } + let belowLayerId = arguments["belowLayerId"] as? String + addSymbolLayer( + sourceId: sourceId, + layerId: layerId, + belowLayerId: belowLayerId, + properties: properties + ) + result(nil) + + case "lineLayer#add": + guard let arguments = methodCall.arguments as? [String: Any] else { return } + guard let sourceId = arguments["sourceId"] as? String else { return } + guard let layerId = arguments["layerId"] as? String else { return } + guard let properties = arguments["properties"] as? [String: String] else { return } + let belowLayerId = arguments["belowLayerId"] as? String + addLineLayer( + sourceId: sourceId, + layerId: layerId, + belowLayerId: belowLayerId, + properties: properties + ) + result(nil) + + case "fillLayer#add": + guard let arguments = methodCall.arguments as? [String: Any] else { return } + guard let sourceId = arguments["sourceId"] as? String else { return } + guard let layerId = arguments["layerId"] as? String else { return } + guard let properties = arguments["properties"] as? [String: String] else { return } + let belowLayerId = arguments["belowLayerId"] as? String + addFillLayer( + sourceId: sourceId, + layerId: layerId, + belowLayerId: belowLayerId, + properties: properties + ) + result(nil) + + case "circleLayer#add": + guard let arguments = methodCall.arguments as? [String: Any] else { return } + guard let sourceId = arguments["sourceId"] as? String else { return } + guard let layerId = arguments["layerId"] as? String else { return } + guard let properties = arguments["properties"] as? [String: String] else { return } + let belowLayerId = arguments["belowLayerId"] as? String + addCircleLayer( + sourceId: sourceId, + layerId: layerId, + belowLayerId: belowLayerId, + properties: properties + ) + result(nil) + case "style#removeLayer": guard let arguments = methodCall.arguments as? [String: Any] else { return } guard let layerId = arguments["layerId"] as? String else { return } @@ -580,22 +636,6 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma } } - private func getSymbolForOptions(options: [String: Any]) -> MGLSymbolStyleAnnotation? { - // Parse geometry - if let geometry = options["geometry"] as? [Double] { - // Convert geometry to coordinate and create symbol. - let coordinate = CLLocationCoordinate2DMake(geometry[0], geometry[1]) - let symbol = MGLSymbolStyleAnnotation(coordinate: coordinate) - Convert.interpretSymbolOptions(options: options, delegate: symbol) - // Load icon image from asset if an icon name is supplied. - if let iconImage = options["iconImage"] as? String { - addIconImageToMap(iconImageName: iconImage) - } - return symbol - } - return nil - } - private func addIconImageToMap(iconImageName: String) { // Check if the image has already been added to the map. if mapView.style?.image(forName: iconImageName) == nil { @@ -679,9 +719,6 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma * On pan might invoke the feature#onDrag callback. */ @IBAction func handleMapPan(sender: UIPanGestureRecognizer) { - // Get the CGPoint where the user tapped. - print(sender.state) - let point = sender.location(in: mapView) let coordinate = mapView.convert(point, toCoordinateFrom: mapView) @@ -823,34 +860,6 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma 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[.. { Expressions.caseExpression, [Expressions.has, 'fontNames'], [Expressions.get, 'fontNames'], - ["Open Sans Regular", "Arial Unicode MS Regular"], + [ + Expressions.literal, + ["Open Sans Regular", "Arial Unicode MS Regular"] + ], ], textField: [Expressions.get, 'textField'], textSize: [Expressions.get, 'textSize'], From 1acc3452bb70007ed8e61cfd6b804dff50bf6c87 Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Mon, 20 Dec 2021 12:13:11 +0100 Subject: [PATCH 14/26] added source#setFeature to iOS --- ios/Classes/MapboxMapController.swift | 41 ++++ lib/src/annotation_manager.dart | 5 +- lib/src/controller.dart | 17 ++ .../lib/src/mapbox_gl_platform_interface.dart | 178 ++++-------------- .../lib/src/method_channel_mapbox_gl.dart | 56 +----- .../lib/src/mapbox_web_gl_platform.dart | 83 ++++---- 6 files changed, 156 insertions(+), 224 deletions(-) diff --git a/ios/Classes/MapboxMapController.swift b/ios/Classes/MapboxMapController.swift index 282265c6b..061094d25 100644 --- a/ios/Classes/MapboxMapController.swift +++ b/ios/Classes/MapboxMapController.swift @@ -25,6 +25,7 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma private var scrollingEnabled = true private var featureLayerIdentifiers = Set() + private var addedShapesByLayer = [String: MGLShape]() func view() -> UIView { return mapView @@ -631,6 +632,12 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma setSource(sourceId: sourceId, geojson: geojson) result(nil) + case "source#setFeature": + guard let arguments = methodCall.arguments as? [String: Any] else { return } + guard let sourceId = arguments["sourceId"] as? String else { return } + guard let geojson = arguments["geojsonFeature"] as? String else { return } + setFeature(sourceId: sourceId, geojsonFeature: geojson) + result(nil) default: result(FlutterMethodNotImplemented) } @@ -822,6 +829,9 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma mapView.setCamera(camera, animated: false) } + addedShapesByLayer.removeAll() + featureLayerIdentifiers.removeAll() + mapReadyResult?(nil) // On first launch we only call map#onStyleLoaded if map#waitForMap has already been called @@ -1105,7 +1115,9 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma encoding: String.Encoding.utf8.rawValue ) let source = MGLShapeSource(identifier: sourceId, shape: parsed, options: [:]) + addedShapesByLayer[sourceId] = parsed mapView.style?.addSource(source) + print(source) } catch {} } @@ -1116,11 +1128,40 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma encoding: String.Encoding.utf8.rawValue ) if let source = mapView.style?.source(withIdentifier: sourceId) as? MGLShapeSource { + addedShapesByLayer[sourceId] = parsed source.shape = parsed } } catch {} } + func setFeature(sourceId: String, geojsonFeature: String) { + do { + let newShape = try MGLShape( + data: geojsonFeature.data(using: .utf8)!, + encoding: String.Encoding.utf8.rawValue + ) + if let source = mapView.style?.source(withIdentifier: sourceId) as? MGLShapeSource, + let shape = addedShapesByLayer[sourceId] as? MGLShapeCollectionFeature, + let feature = newShape as? MGLShape & MGLFeature + { + if let index = shape.shapes + .firstIndex(where: { + if let id = $0.identifier as? String, + let featureId = feature.identifier as? String + { return id == featureId } + return false + }) + { + var shapes = shape.shapes; + shapes[index] = feature + + source.shape = MGLShapeCollectionFeature(shapes: shapes) + } + } + + } catch {} + } + /* * MapboxMapOptionsSink */ diff --git a/lib/src/annotation_manager.dart b/lib/src/annotation_manager.dart index cd322ab40..1a5782f02 100644 --- a/lib/src/annotation_manager.dart +++ b/lib/src/annotation_manager.dart @@ -114,8 +114,9 @@ abstract class AnnotationManager { Future set(T annoation) async { _idToAnnotation[annoation.id] = annoation; - //Todo: send only the changed line to plugin - await _setAll(); + final layerIndex = selectLayer != null ? selectLayer!(annoation) : 0; + await controller.setGeoJsonFeature( + _makeLayerId(layerIndex), annoation.toGeoJson()); } } diff --git a/lib/src/controller.dart b/lib/src/controller.dart index aa5f7b282..f3142b9a7 100644 --- a/lib/src/controller.dart +++ b/lib/src/controller.dart @@ -311,6 +311,23 @@ class MapboxMapController extends ChangeNotifier { await _mapboxGlPlatform.setGeoJsonSource(sourceId, geojson); } + /// Sets new geojson data to and existing source + /// + /// This only works as exected if the source has been created with + /// [addGeoJsonSource] before. This is very useful if you want to update and + /// existing source with modified data. + /// + /// The json in [geojson] has to comply with the schema for FeatureCollection + /// as specified in https://datatracker.ietf.org/doc/html/rfc7946#section-3.3 + /// + /// The returned [Future] completes after the change has been made on the + /// platform side. + Future setGeoJsonFeature( + String sourceId, Map geojsonFeature) async { + await _mapboxGlPlatform.setFeatureForGeoJsonSource( + sourceId, geojsonFeature); + } + /// Add a symbol layer to the map with the given properties /// /// The returned [Future] completes after the change has been made on the diff --git a/mapbox_gl_platform_interface/lib/src/mapbox_gl_platform_interface.dart b/mapbox_gl_platform_interface/lib/src/mapbox_gl_platform_interface.dart index 1c5c9c799..cacb52095 100644 --- a/mapbox_gl_platform_interface/lib/src/mapbox_gl_platform_interface.dart +++ b/mapbox_gl_platform_interface/lib/src/mapbox_gl_platform_interface.dart @@ -45,181 +45,77 @@ abstract class MapboxGlPlatform { final onUserLocationUpdatedPlatform = ArgumentCallbacks(); - Future initPlatform(int id) async { - throw UnimplementedError('initPlatform() has not been implemented.'); - } - + Future initPlatform(int id); Widget buildView( Map creationParams, OnPlatformViewCreatedCallback onPlatformViewCreated, - Set>? gestureRecognizers) { - throw UnimplementedError('buildView() has not been implemented.'); - } - - Future updateMapOptions( - Map optionsUpdate) async { - throw UnimplementedError('updateMapOptions() has not been implemented.'); - } - - Future animateCamera(CameraUpdate cameraUpdate) async { - throw UnimplementedError('animateCamera() has not been implemented.'); - } - - Future moveCamera(CameraUpdate cameraUpdate) async { - throw UnimplementedError('moveCamera() has not been implemented.'); - } - + Set>? gestureRecognizers); + Future updateMapOptions(Map optionsUpdate); + Future animateCamera(CameraUpdate cameraUpdate); + Future moveCamera(CameraUpdate cameraUpdate); Future updateMyLocationTrackingMode( - MyLocationTrackingMode myLocationTrackingMode) async { - throw UnimplementedError( - 'updateMyLocationTrackingMode() has not been implemented.'); - } - - Future matchMapLanguageWithDeviceDefault() async { - throw UnimplementedError( - 'matchMapLanguageWithDeviceDefault() has not been implemented.'); - } - - Future updateContentInsets(EdgeInsets insets, bool animated) async { - throw UnimplementedError('updateContentInsets() has not been implemented.'); - } + MyLocationTrackingMode myLocationTrackingMode); - Future setMapLanguage(String language) async { - throw UnimplementedError('setMapLanguage() has not been implemented.'); - } + Future matchMapLanguageWithDeviceDefault(); - Future setTelemetryEnabled(bool enabled) async { - throw UnimplementedError('setTelemetryEnabled() has not been implemented.'); - } - - Future getTelemetryEnabled() async { - throw UnimplementedError('getTelemetryEnabled() has not been implemented.'); - } + Future updateContentInsets(EdgeInsets insets, bool animated); + Future setMapLanguage(String language); + Future setTelemetryEnabled(bool enabled); + Future getTelemetryEnabled(); Future queryRenderedFeatures( - Point point, List layerIds, List? filter) async { - throw UnimplementedError( - 'queryRenderedFeatures() has not been implemented.'); - } + Point point, List layerIds, List? filter); Future queryRenderedFeaturesInRect( - Rect rect, List layerIds, String? filter) async { - throw UnimplementedError( - 'queryRenderedFeaturesInRect() has not been implemented.'); - } - - Future invalidateAmbientCache() async { - throw UnimplementedError( - 'invalidateAmbientCache() has not been implemented.'); - } - - Future requestMyLocationLatLng() async { - throw UnimplementedError( - 'requestMyLocationLatLng() has not been implemented.'); - } - - Future getVisibleRegion() async { - throw UnimplementedError('getVisibleRegion() has not been implemented.'); - } - - Future addImage(String name, Uint8List bytes, - [bool sdf = false]) async { - throw UnimplementedError('addImage() has not been implemented.'); - } - - Future setSymbolIconAllowOverlap(bool enable) async { - throw UnimplementedError( - 'setSymbolIconAllowOverlap() has not been implemented.'); - } - - Future setSymbolIconIgnorePlacement(bool enable) async { - throw UnimplementedError( - 'setSymbolIconIgnorePlacement() has not been implemented.'); - } - - Future setSymbolTextAllowOverlap(bool enable) async { - throw UnimplementedError( - 'setSymbolTextAllowOverlap() has not been implemented.'); - } - - Future setSymbolTextIgnorePlacement(bool enable) async { - throw UnimplementedError( - 'setSymbolTextIgnorePlacement() has not been implemented.'); - } + Rect rect, List layerIds, String? filter); + Future invalidateAmbientCache(); + Future requestMyLocationLatLng(); - Future addImageSource( - String imageSourceId, Uint8List bytes, LatLngQuad coordinates) async { - throw UnimplementedError('addImageSource() has not been implemented.'); - } + Future getVisibleRegion(); + + Future addImage(String name, Uint8List bytes, [bool sdf = false]); - Future addLayer(String imageLayerId, String imageSourceId) async { - throw UnimplementedError('addLayer() has not been implemented.'); - } + Future addImageSource( + String imageSourceId, Uint8List bytes, LatLngQuad coordinates); + Future addLayer(String imageLayerId, String imageSourceId); Future addLayerBelow( - String imageLayerId, String imageSourceId, String belowLayerId) async { - throw UnimplementedError('addLayerBelow() has not been implemented.'); - } + String imageLayerId, String imageSourceId, String belowLayerId); - Future removeLayer(String imageLayerId) async { - throw UnimplementedError('removeLayer() has not been implemented.'); - } + Future removeLayer(String imageLayerId); - Future toScreenLocation(LatLng latLng) async { - throw UnimplementedError('toScreenLocation() has not been implemented.'); - } + Future toScreenLocation(LatLng latLng); - Future> toScreenLocationBatch(Iterable latLngs) async { - throw UnimplementedError( - 'toScreenLocationList() has not been implemented.'); - } + Future> toScreenLocationBatch(Iterable latLngs); - Future toLatLng(Point screenLocation) async { - throw UnimplementedError('toLatLng() has not been implemented.'); - } + Future toLatLng(Point screenLocation); - Future getMetersPerPixelAtLatitude(double latitude) async { - throw UnimplementedError( - 'getMetersPerPixelAtLatitude() has not been implemented.'); - } + Future getMetersPerPixelAtLatitude(double latitude); Future addGeoJsonSource(String sourceId, Map geojson, - {String? promoteId}) async { - throw UnimplementedError('addGeoJsonSource() has not been implemented.'); - } + {String? promoteId}); + + Future setGeoJsonSource(String sourceId, Map geojson); - Future setGeoJsonSource( - String sourceId, Map geojson) async { - throw UnimplementedError('setGeoJsonSource() has not been implemented.'); - } + Future setFeatureForGeoJsonSource( + String sourceId, Map geojsonFeature); - Future removeSource(String sourceId) async { - throw UnimplementedError('removeSource() has not been implemented.'); - } + Future removeSource(String sourceId); Future addSymbolLayer( String sourceId, String layerId, Map properties, - {String? belowLayerId, String? sourceLayer}) async { - throw UnimplementedError('addSymbolLayer() has not been implemented.'); - } + {String? belowLayerId}); Future addLineLayer( String sourceId, String layerId, Map properties, - {String? belowLayerId, String? sourceLayer}) async { - throw UnimplementedError('addLineLayer() has not been implemented.'); - } + {String? belowLayerId}); Future addCircleLayer( String sourceId, String layerId, Map properties, - {String? belowLayerId, String? sourceLayer}) async { - throw UnimplementedError('addCircleLayer() has not been implemented.'); - } - + {String? belowLayerId}); Future addFillLayer( String sourceId, String layerId, Map properties, - {String? belowLayerId, String? sourceLayer}) async { - throw UnimplementedError('addFillLayer() has not been implemented.'); - } + {String? belowLayerId}); Future addRasterLayer( String sourceId, String layerId, Map properties, diff --git a/mapbox_gl_platform_interface/lib/src/method_channel_mapbox_gl.dart b/mapbox_gl_platform_interface/lib/src/method_channel_mapbox_gl.dart index e24cd1734..a14ee21ac 100644 --- a/mapbox_gl_platform_interface/lib/src/method_channel_mapbox_gl.dart +++ b/mapbox_gl_platform_interface/lib/src/method_channel_mapbox_gl.dart @@ -329,54 +329,6 @@ class MethodChannelMapboxGl extends MapboxGlPlatform { } } - @override - Future setSymbolIconAllowOverlap(bool enable) async { - try { - await _channel - .invokeMethod('symbolManager#iconAllowOverlap', { - 'iconAllowOverlap': enable, - }); - } on PlatformException catch (e) { - return new Future.error(e); - } - } - - @override - Future setSymbolIconIgnorePlacement(bool enable) async { - try { - await _channel - .invokeMethod('symbolManager#iconIgnorePlacement', { - 'iconIgnorePlacement': enable, - }); - } on PlatformException catch (e) { - return new Future.error(e); - } - } - - @override - Future setSymbolTextAllowOverlap(bool enable) async { - try { - await _channel - .invokeMethod('symbolManager#textAllowOverlap', { - 'textAllowOverlap': enable, - }); - } on PlatformException catch (e) { - return new Future.error(e); - } - } - - @override - Future setSymbolTextIgnorePlacement(bool enable) async { - try { - await _channel - .invokeMethod('symbolManager#textIgnorePlacement', { - 'textIgnorePlacement': enable, - }); - } on PlatformException catch (e) { - return new Future.error(e); - } - } - @override Future addImageSource( String imageSourceId, Uint8List bytes, LatLngQuad coordinates) async { @@ -617,4 +569,12 @@ class MethodChannelMapboxGl extends MapboxGlPlatform { .map((key, value) => MapEntry(key, jsonEncode(value))) }); } + + Future setFeatureForGeoJsonSource( + String sourceId, Map geojsonFeature) async { + await _channel.invokeMethod('source#setFeature', { + 'sourceId': sourceId, + 'geojsonFeature': jsonEncode(geojsonFeature) + }); + } } diff --git a/mapbox_gl_web/lib/src/mapbox_web_gl_platform.dart b/mapbox_gl_web/lib/src/mapbox_web_gl_platform.dart index e911d3089..71ec26d94 100644 --- a/mapbox_gl_web/lib/src/mapbox_web_gl_platform.dart +++ b/mapbox_gl_web/lib/src/mapbox_web_gl_platform.dart @@ -287,30 +287,6 @@ class MapboxWebGlPlatform extends MapboxGlPlatform _map.removeSource(sourceId); } - @override - Future setSymbolIconAllowOverlap(bool enable) async { - //TODO: to implement - print('setSymbolIconAllowOverlap not implemented yet'); - } - - @override - Future setSymbolIconIgnorePlacement(bool enable) async { - //TODO: to implement - print('setSymbolIconIgnorePlacement not implemented yet'); - } - - @override - Future setSymbolTextAllowOverlap(bool enable) async { - //TODO: to implement - print('setSymbolTextAllowOverlap not implemented yet'); - } - - @override - Future setSymbolTextIgnorePlacement(bool enable) async { - //TODO: to implement - print('setSymbolTextIgnorePlacement not implemented yet'); - } - CameraPosition? _getCameraPosition() { if (_trackCameraPosition) { final center = _map.getCenter(); @@ -652,19 +628,21 @@ class MapboxWebGlPlatform extends MapboxGlPlatform }); } + Feature _makeFeature(Map geojsonFeature) { + return Feature( + geometry: Geometry( + type: geojsonFeature["geometry"]["type"], + coordinates: geojsonFeature["geometry"]["coordinates"]), + properties: geojsonFeature["properties"], + id: geojsonFeature["properties"]?["id"] ?? geojsonFeature["id"]); + } + @override Future setGeoJsonSource( String sourceId, Map geojson) async { final source = _map.getSource(sourceId) as GeoJsonSource; - final data = FeatureCollection(features: [ - for (final f in geojson["features"] ?? []) - Feature( - geometry: Geometry( - type: f["geometry"]["type"], - coordinates: f["geometry"]["coordinates"]), - properties: f["properties"], - id: f["id"]) - ]); + final data = FeatureCollection( + features: [for (final f in geojson["features"] ?? []) _makeFeature(f)]); source.setData(data); } @@ -810,5 +788,44 @@ class MapboxWebGlPlatform extends MapboxGlPlatform {String? belowLayerId, String? sourceLayer}) async { await _addLayer(sourceId, layerId, properties, "raster", belowLayerId: belowLayerId, sourceLayer: sourceLayer); + Future addImageSource( + String imageSourceId, Uint8List bytes, LatLngQuad coordinates) { + // TODO: implement addImageSource + throw UnimplementedError(); + } + + @override + Future addLayer(String imageLayerId, String imageSourceId) { + // TODO: implement addLayer + throw UnimplementedError(); + } + + @override + Future addLayerBelow( + String imageLayerId, String imageSourceId, String belowLayerId) { + // TODO: implement addLayerBelow + throw UnimplementedError(); + } + + @override + Future updateContentInsets(EdgeInsets insets, bool animated) { + // TODO: implement updateContentInsets + throw UnimplementedError(); + } + + @override + Future setFeatureForGeoJsonSource( + String sourceId, Map geojsonFeature) async { + final source = _map.getSource(sourceId) as GeoJsonSource?; + + if (source != null) { + final feature = _makeFeature(geojsonFeature); + final data = source.data; + final index = data.features.indexWhere((f) => f.id == feature.id); + if (index >= 0) { + data.features[index] = feature; + source.setData(data); + } + } } } From e6bf60eac89e5b06b5fc1cf2c05e545d77144dfc Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Mon, 20 Dec 2021 14:15:11 +0100 Subject: [PATCH 15/26] added setGeoJsonFeature to android --- .../mapbox/mapboxgl/MapboxMapController.java | 42 ++++++++++++++----- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java index 91a3aeacc..2c06dc366 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java +++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java @@ -156,6 +156,8 @@ final class MapboxMapController private LatLng dragPrevious; private Set featureLayerIdentifiers; + private Map addedFeaturesByLayer; + private LatLngBounds bounds = null; MapboxMapController( @@ -174,6 +176,7 @@ final class MapboxMapController this.styleStringInitial = styleStringInitial; this.mapView = new MapView(context, options); this.featureLayerIdentifiers = new HashSet<>(); + this.addedFeaturesByLayer = new HashMap(); this.density = context.getResources().getDisplayMetrics().density; this.lifecycleProvider = lifecycleProvider; this.androidGesturesManager = new AndroidGesturesManager(this.mapView.getContext(), false); @@ -330,17 +333,37 @@ private void onUserLocationUpdate(Location location){ private void addGeoJsonSource(String sourceName, String source) { FeatureCollection featureCollection = FeatureCollection.fromJson(source); GeoJsonSource geoJsonSource = new GeoJsonSource(sourceName, featureCollection); + addedFeaturesByLayer.put(sourceName, featureCollection); style.addSource(geoJsonSource); } - private void setGeoJsonSource(String sourceName, String source) { - FeatureCollection featureCollection = FeatureCollection.fromJson(source); + private void setGeoJsonSource(String sourceName, String geojson) { + FeatureCollection featureCollection = FeatureCollection.fromJson(geojson); GeoJsonSource geoJsonSource = style.getSourceAs(sourceName); + addedFeaturesByLayer.put(sourceName, featureCollection); geoJsonSource.setGeoJson(featureCollection); } + private void setGeoJsonFeature(String sourceName, String geojsonFeature) { + Feature feature = Feature.fromJson(geojsonFeature); + FeatureCollection featureCollection = addedFeaturesByLayer.get(sourceName); + GeoJsonSource geoJsonSource = style.getSourceAs(sourceName); + if(featureCollection != null && geoJsonSource != null){ + final List features = featureCollection.features(); + for (int i = 0; i < features.size(); i++) { + final String id = features.get(i).id(); + if(id.equals(feature.id())){ + features.set(i, feature); + break; + } + } + + geoJsonSource.setGeoJson(featureCollection); + } + } + private void addSymbolLayer(String layerName, String sourceName, String belowLayerId, @@ -698,6 +721,13 @@ public void onError(@NonNull String message) { result.success(null); break; } + case "source#setFeature":{ + final String sourceId = call.argument("sourceId"); + final String geojsonFeature = call.argument("geojsonFeature"); + setGeoJsonFeature(sourceId, geojsonFeature); + result.success(null); + break; + } case "symbolLayer#add": { final String sourceId = call.argument("sourceId"); final String layerId = call.argument("layerId"); @@ -815,14 +845,6 @@ public void onFailure(@NonNull Exception exception) { result.success(null); break; } - case "style#setSource": { - if (style == null) { - result.error("STYLE IS NULL", "The style is null. Has onStyleLoaded() already been invoked?", null); - } - style.removeSource((String) call.argument("sourceId")); - result.success(null); - break; - } case "style#addLayer": { if (style == null) { result.error("STYLE IS NULL", "The style is null. Has onStyleLoaded() already been invoked?", null); From b9be177f8c7b9d3bb0ab8bba9c35606264d7d53a Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Mon, 20 Dec 2021 15:25:33 +0100 Subject: [PATCH 16/26] add support for dragEnabled --- .../java/com/mapbox/mapboxgl/Convert.java | 15 +--------- .../com/mapbox/mapboxgl/MapboxMapBuilder.java | 14 +++------ .../mapbox/mapboxgl/MapboxMapController.java | 29 +++++++++++-------- .../com/mapbox/mapboxgl/MapboxMapFactory.java | 11 +++---- example/lib/layer.dart | 23 +++++++-------- ios/Classes/MapboxMapController.swift | 23 +++++++++------ lib/src/mapbox_map.dart | 8 +++++ .../lib/src/mapbox_web_gl_platform.dart | 23 +++++++-------- 8 files changed, 69 insertions(+), 77 deletions(-) diff --git a/android/src/main/java/com/mapbox/mapboxgl/Convert.java b/android/src/main/java/com/mapbox/mapboxgl/Convert.java index 068f29490..745833380 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/Convert.java +++ b/android/src/main/java/com/mapbox/mapboxgl/Convert.java @@ -31,7 +31,7 @@ class Convert { private final static String TAG = "Convert"; - private static boolean toBoolean(Object o) { + static boolean toBoolean(Object o) { return (Boolean) o; } @@ -45,19 +45,6 @@ static CameraPosition toCameraPosition(Object o) { return builder.build(); } - static List toAnnotationOrder(Object o) { - final List data = toList(o); - List annotations = new ArrayList(); - for (int index = 0; index < data.size(); index++) { - annotations.add(toString(data.get(index))); - } - return annotations; - } - - static List toAnnotationConsumeTapEvents(Object o) { - return toAnnotationOrder(o); - } - static boolean isScrollByCameraUpdate(Object o) { return toString(toList(o).get(0)).equals("scrollBy"); } diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapBuilder.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapBuilder.java index a9e93cd82..0d5786287 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapBuilder.java +++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapBuilder.java @@ -27,17 +27,16 @@ class MapboxMapBuilder implements MapboxMapOptionsSink { .attributionEnabled(true); private boolean trackCameraPosition = false; private boolean myLocationEnabled = false; + private boolean dragEnabled = true; private int myLocationTrackingMode = 0; private int myLocationRenderMode = 0; private String styleString = Style.MAPBOX_STREETS; - private List annotationOrder = new ArrayList(); - private List annotationConsumeTapEvents = new ArrayList(); private LatLngBounds bounds = null; MapboxMapController build( int id, Context context, BinaryMessenger messenger, MapboxMapsPlugin.LifecycleProvider lifecycleProvider, String accessToken) { final MapboxMapController controller = - new MapboxMapController(id, context, messenger, lifecycleProvider, options, accessToken, styleString, annotationOrder, annotationConsumeTapEvents); + new MapboxMapController(id, context, messenger, lifecycleProvider, options, accessToken, styleString, dragEnabled); controller.init(); controller.setMyLocationEnabled(myLocationEnabled); controller.setMyLocationTrackingMode(myLocationTrackingMode); @@ -210,12 +209,7 @@ public void setAttributionButtonMargins(int x, int y) { } } - public void setAnnotationOrder(List annotations) { - this.annotationOrder = annotations; + public void setDragEnabled(boolean enabled){ + this.dragEnabled = enabled; } - - public void setAnnotationConsumeTapEvents(List annotations) { - this.annotationConsumeTapEvents = annotations; - } - } diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java index 2c06dc366..045d2f1d0 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java +++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java @@ -140,6 +140,7 @@ final class MapboxMapController private int myLocationTrackingMode = 0; private int myLocationRenderMode = 0; private boolean disposed = false; + private boolean dragEnabled = true; private final float density; private MethodChannel.Result mapReadyResult; private final Context context; @@ -168,18 +169,20 @@ final class MapboxMapController MapboxMapOptions options, String accessToken, String styleStringInitial, - List annotationOrder, - List annotationConsumeTapEvents) { + boolean dragEnabled) { MapBoxUtils.getMapbox(context, accessToken); this.id = id; this.context = context; + this.dragEnabled = dragEnabled; this.styleStringInitial = styleStringInitial; this.mapView = new MapView(context, options); this.featureLayerIdentifiers = new HashSet<>(); this.addedFeaturesByLayer = new HashMap(); this.density = context.getResources().getDisplayMetrics().density; this.lifecycleProvider = lifecycleProvider; - this.androidGesturesManager = new AndroidGesturesManager(this.mapView.getContext(), false); + if(dragEnabled){ + this.androidGesturesManager = new AndroidGesturesManager(this.mapView.getContext(), false); + } methodChannel = new MethodChannel(messenger, "plugins.flutter.io/mapbox_maps_" + id); methodChannel.setMethodCallHandler(this); @@ -217,17 +220,19 @@ public void onMapReady(MapboxMap mapboxMap) { mapboxMap.addOnCameraMoveStartedListener(this); mapboxMap.addOnCameraMoveListener(this); mapboxMap.addOnCameraIdleListener(this); - androidGesturesManager.setMoveGestureListener(new MoveGestureListener()); - mapView.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - Feature feature = draggedFeature; - androidGesturesManager.onTouchEvent(event); + if(androidGesturesManager != null){ + androidGesturesManager.setMoveGestureListener(new MoveGestureListener()); + mapView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + Feature feature = draggedFeature; + androidGesturesManager.onTouchEvent(event); - return feature != null; - } - }); + return feature != null; + } + }); + } mapView.addOnStyleImageMissingListener((id) -> { DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapFactory.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapFactory.java index 1b2c4c9c8..6e322098c 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapFactory.java +++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapFactory.java @@ -35,14 +35,11 @@ public PlatformView create(Context context, int id, Object args) { CameraPosition position = Convert.toCameraPosition(params.get("initialCameraPosition")); builder.setInitialCameraPosition(position); } - if (params.containsKey("annotationOrder")) { - List annotations = Convert.toAnnotationOrder(params.get("annotationOrder")); - builder.setAnnotationOrder(annotations); - } - if (params.containsKey("annotationConsumeTapEvents")) { - List annotations = Convert.toAnnotationConsumeTapEvents(params.get("annotationConsumeTapEvents")); - builder.setAnnotationConsumeTapEvents(annotations); + if (params.containsKey("dragEnabled")) { + boolean dragEnabled = Convert.toBoolean(params.get("dragEnabled")); + builder.setDragEnabled(dragEnabled); } + return builder.build(id, context, messenger, lifecycleProvider, (String) params.get("accessToken")); } } diff --git a/example/lib/layer.dart b/example/lib/layer.dart index 561fa53de..1d606c542 100644 --- a/example/lib/layer.dart +++ b/example/lib/layer.dart @@ -26,19 +26,18 @@ class LayerState extends State { @override Widget build(BuildContext context) { - return Container( - child: MapboxMap( - accessToken: MapsDemo.ACCESS_TOKEN, - onMapCreated: _onMapCreated, - onMapClick: (point, latLong) => - print(point.toString() + latLong.toString()), - onStyleLoadedCallback: _onStyleLoadedCallback, - initialCameraPosition: CameraPosition( - target: center, - zoom: 11.0, - ), - annotationOrder: const [], + return MapboxMap( + accessToken: MapsDemo.ACCESS_TOKEN, + dragEnabled: false, + onMapCreated: _onMapCreated, + onMapClick: (point, latLong) => + print(point.toString() + latLong.toString()), + onStyleLoadedCallback: _onStyleLoadedCallback, + initialCameraPosition: CameraPosition( + target: center, + zoom: 11.0, ), + annotationOrder: const [], ); } diff --git a/ios/Classes/MapboxMapController.swift b/ios/Classes/MapboxMapController.swift index 061094d25..af9fe858a 100644 --- a/ios/Classes/MapboxMapController.swift +++ b/ios/Classes/MapboxMapController.swift @@ -11,6 +11,7 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma private var mapView: MGLMapView private var isMapReady = false + private var dragEnabled = true private var isFirstStyleLoad = true private var onStyleLoadedCalled = false private var mapReadyResult: FlutterResult? @@ -77,14 +78,6 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma } mapView.addGestureRecognizer(longPress) - let pan = UIPanGestureRecognizer( - target: self, - action: #selector(handleMapPan(sender:)) - ) - - pan.delegate = self - mapView.addGestureRecognizer(pan) - if let args = args as? [String: Any] { Convert.interpretMapboxMapOptions(options: args["options"], delegate: self) if let initialCameraPosition = args["initialCameraPosition"] as? [String: Any], @@ -104,6 +97,18 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma setupAttribution(mapView) } } + + if let enabled = args["dragEnabled"] as? Bool { + dragEnabled = enabled + } + } + if dragEnabled { + let pan = UIPanGestureRecognizer( + target: self, + action: #selector(handleMapPan(sender:)) + ) + pan.delegate = self + mapView.addGestureRecognizer(pan) } } @@ -1152,7 +1157,7 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma return false }) { - var shapes = shape.shapes; + var shapes = shape.shapes shapes[index] = feature source.shape = MGLShapeCollectionFeature(shapes: shapes) diff --git a/lib/src/mapbox_map.dart b/lib/src/mapbox_map.dart index f08171326..3891b5939 100644 --- a/lib/src/mapbox_map.dart +++ b/lib/src/mapbox_map.dart @@ -25,6 +25,7 @@ class MapboxMap extends StatefulWidget { this.zoomGesturesEnabled = true, this.tiltGesturesEnabled = true, this.doubleClickZoomEnabled, + this.dragEnabled = true, this.trackCameraPosition = false, this.myLocationEnabled = false, this.myLocationTrackingMode = MyLocationTrackingMode.None, @@ -91,6 +92,12 @@ class MapboxMap extends StatefulWidget { /// True if the map should show a compass when rotated. final bool compassEnabled; + /// True if drag functionality should be enabled. + /// + /// Disable to avoid performance issues that from the drag event listeners. + /// Biggest impact in android + final bool dragEnabled; + /// Geographical bounding box for the camera target. final CameraTargetBounds cameraTargetBounds; @@ -236,6 +243,7 @@ class _MapboxMapState extends State { 'options': _MapboxMapOptions.fromWidget(widget).toMap(), 'accessToken': widget.accessToken, 'onAttributionClickOverride': widget.onAttributionClick != null, + 'dragEnabled': widget.dragEnabled }; return _mapboxGlPlatform.buildView( creationParams, onPlatformViewCreated, widget.gestureRecognizers); diff --git a/mapbox_gl_web/lib/src/mapbox_web_gl_platform.dart b/mapbox_gl_web/lib/src/mapbox_web_gl_platform.dart index 71ec26d94..cd05f072f 100644 --- a/mapbox_gl_web/lib/src/mapbox_web_gl_platform.dart +++ b/mapbox_gl_web/lib/src/mapbox_web_gl_platform.dart @@ -13,8 +13,8 @@ class MapboxWebGlPlatform extends MapboxGlPlatform dynamic _draggedFeatureId; LatLng? _dragOrigin; LatLng? _dragPrevious; + bool _dragEnabled = true; - List annotationOrder = []; final _featureLayerIdentifiers = Set(); bool _trackCameraPosition = false; @@ -52,6 +52,9 @@ class MapboxWebGlPlatform extends MapboxGlPlatform await _addStylesheetToShadowRoot(_mapElement); if (_creationParams.containsKey('initialCameraPosition')) { var camera = _creationParams['initialCameraPosition']; + + _dragEnabled = _creationParams['dragEnabled'] ?? true; + if (_creationParams.containsKey('accessToken')) { Mapbox.accessToken = _creationParams['accessToken']; } @@ -73,18 +76,12 @@ class MapboxWebGlPlatform extends MapboxGlPlatform _map.on('move', _onCameraMove); _map.on('moveend', _onCameraIdle); _map.on('resize', _onMapResize); - _map.on('mouseup', _onMouseUp); - _map.on('mousemove', _onMouseMove); + if (_dragEnabled) { + _map.on('mouseup', _onMouseUp); + _map.on('mousemove', _onMouseMove); + } } Convert.interpretMapboxMapOptions(_creationParams['options'], this); - - if (_creationParams.containsKey('annotationOrder')) { - annotationOrder = _creationParams['annotationOrder']; - } - } - - onDrag(dynamic id, LatLng coords) { - print("FOOOBAR"); } _onMouseDown(Event e) { @@ -565,7 +562,7 @@ class MapboxWebGlPlatform extends MapboxGlPlatform _map.off('mouseenter', layerId, _onMouseEnterFeature); _map.off('mousemouve', layerId, _onMouseEnterFeature); _map.off('mouseleave', layerId, _onMouseLeaveFeature); - _map.off('mousedown', layerId, _onMouseDown); + if (_dragEnabled) _map.off('mousedown', layerId, _onMouseDown); } _featureLayerIdentifiers.clear(); @@ -710,7 +707,7 @@ class MapboxWebGlPlatform extends MapboxGlPlatform _map.on('mouseenter', layerId, _onMouseEnterFeature); } _map.on('mouseleave', layerId, _onMouseLeaveFeature); - _map.on('mousedown', layerId, _onMouseDown); + if (_dragEnabled) _map.on('mousedown', layerId, _onMouseDown); } void _onMouseEnterFeature(_) { From 9fe1a5a99036033baa545da09b05a9e0ccdc2005 Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Mon, 20 Dec 2021 17:12:56 +0100 Subject: [PATCH 17/26] added option to toggle interaction for layers --- .../mapbox/mapboxgl/MapboxMapController.java | 43 ++++--- example/lib/layer.dart | 33 +++--- ios/Classes/MapboxMapController.swift | 38 ++++-- lib/src/annotation_manager.dart | 53 +++++++-- lib/src/controller.dart | 53 ++++++--- lib/src/mapbox_map.dart | 1 + .../lib/src/mapbox_gl_platform_interface.dart | 17 ++- .../lib/src/method_channel_mapbox_gl.dart | 20 +++- .../lib/src/mapbox_web_gl_platform.dart | 112 ++++++++++++------ 9 files changed, 257 insertions(+), 113 deletions(-) diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java index 045d2f1d0..c43ec29eb 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java +++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java @@ -156,7 +156,7 @@ final class MapboxMapController private LatLng dragOrigin; private LatLng dragPrevious; - private Set featureLayerIdentifiers; + private Set interactiveFeatureLayerIds; private Map addedFeaturesByLayer; private LatLngBounds bounds = null; @@ -176,7 +176,7 @@ final class MapboxMapController this.dragEnabled = dragEnabled; this.styleStringInitial = styleStringInitial; this.mapView = new MapView(context, options); - this.featureLayerIdentifiers = new HashSet<>(); + this.interactiveFeatureLayerIds = new HashSet<>(); this.addedFeaturesByLayer = new HashMap(); this.density = context.getResources().getDisplayMetrics().density; this.lifecycleProvider = lifecycleProvider; @@ -374,6 +374,7 @@ private void addSymbolLayer(String layerName, String belowLayerId, String sourceLayer, PropertyValue[] properties, + boolean enableInteraction, Expression filter) { SymbolLayer symbolLayer = new SymbolLayer(layerName, sourceName); symbolLayer.setProperties(properties); @@ -388,7 +389,9 @@ private void addSymbolLayer(String layerName, { style.addLayer(symbolLayer); } - featureLayerIdentifiers.add(layerName); + if(enableInteraction){ + interactiveFeatureLayerIds.add(layerName); + } } private void addLineLayer(String layerName, @@ -396,6 +399,7 @@ private void addLineLayer(String layerName, String belowLayerId, String sourceLayer, PropertyValue[] properties, + boolean enableInteraction, Expression filter) { LineLayer lineLayer = new LineLayer(layerName, sourceName); lineLayer.setProperties(properties); @@ -410,7 +414,9 @@ private void addLineLayer(String layerName, { style.addLayer(lineLayer); } - featureLayerIdentifiers.add(layerName); + if(enableInteraction){ + interactiveFeatureLayerIds.add(layerName); + } } private void addFillLayer(String layerName, @@ -418,6 +424,7 @@ private void addFillLayer(String layerName, String belowLayerId, String sourceLayer, PropertyValue[] properties, + boolean enableInteraction, Expression filter) { FillLayer fillLayer = new FillLayer(layerName, sourceName); fillLayer.setProperties(properties); @@ -432,7 +439,9 @@ private void addFillLayer(String layerName, { style.addLayer(fillLayer); } - featureLayerIdentifiers.add(layerName); + if(enableInteraction){ + interactiveFeatureLayerIds.add(layerName); + } } private void addCircleLayer(String layerName, @@ -440,6 +449,7 @@ private void addCircleLayer(String layerName, String belowLayerId, String sourceLayer, PropertyValue[] properties, + boolean enableInteraction, Expression filter) { CircleLayer circleLayer = new CircleLayer(layerName, sourceName); circleLayer.setProperties(properties); @@ -447,7 +457,6 @@ private void addCircleLayer(String layerName, circleLayer.setSourceLayer(sourceLayer); } - featureLayerIdentifiers.add(layerName); if(belowLayerId != null){ style.addLayerBelow(circleLayer, belowLayerId); } @@ -455,6 +464,9 @@ private void addCircleLayer(String layerName, { style.addLayer(circleLayer); } + if(enableInteraction){ + interactiveFeatureLayerIds.add(layerName); + }; } private void addRasterLayer(String layerName, @@ -497,7 +509,7 @@ private Feature firstFeatureOnLayers(RectF in) { final List layersInOrder = new ArrayList(); for (Layer layer : layers){ String id = layer.getId(); - if(featureLayerIdentifiers.contains(id)) + if(interactiveFeatureLayerIds.contains(id)) layersInOrder.add(id); } Collections.reverse(layersInOrder); @@ -737,9 +749,9 @@ public void onError(@NonNull String message) { final String sourceId = call.argument("sourceId"); final String layerId = call.argument("layerId"); final String belowLayerId = call.argument("belowLayerId"); - final String sourceLayer = call.argument("sourceLayer"); + final boolean enableInteraction = call.argument("enableInteraction"); final PropertyValue[] properties = LayerPropertyConverter.interpretSymbolLayerProperties(call.argument("properties")); - addSymbolLayer(layerId, sourceId, belowLayerId, sourceLayer, properties, null); + addSymbolLayer(layerId, sourceId, belowLayerId, sourceLayer, properties, enableInteraction, null); result.success(null); break; } @@ -747,9 +759,9 @@ public void onError(@NonNull String message) { final String sourceId = call.argument("sourceId"); final String layerId = call.argument("layerId"); final String belowLayerId = call.argument("belowLayerId"); - final String sourceLayer = call.argument("sourceLayer"); + final boolean enableInteraction = call.argument("enableInteraction"); final PropertyValue[] properties = LayerPropertyConverter.interpretLineLayerProperties(call.argument("properties")); - addLineLayer(layerId, sourceId, belowLayerId, sourceLayer, properties, null); + addLineLayer(layerId, sourceId, belowLayerId, sourceLayer, properties, enableInteraction, null); result.success(null); break; } @@ -757,9 +769,9 @@ public void onError(@NonNull String message) { final String sourceId = call.argument("sourceId"); final String layerId = call.argument("layerId"); final String belowLayerId = call.argument("belowLayerId"); - final String sourceLayer = call.argument("sourceLayer"); + final boolean enableInteraction = call.argument("enableInteraction"); final PropertyValue[] properties = LayerPropertyConverter.interpretFillLayerProperties(call.argument("properties")); - addFillLayer(layerId, sourceId, belowLayerId, sourceLayer, properties, null); + addFillLayer(layerId, sourceId, belowLayerId, sourceLayer, properties, enableInteraction, null); result.success(null); break; } @@ -768,8 +780,9 @@ public void onError(@NonNull String message) { final String layerId = call.argument("layerId"); final String belowLayerId = call.argument("belowLayerId"); final String sourceLayer = call.argument("sourceLayer"); + final boolean enableInteraction = call.argument("enableInteraction"); final PropertyValue[] properties = LayerPropertyConverter.interpretCircleLayerProperties(call.argument("properties")); - addCircleLayer(layerId, sourceId, belowLayerId, sourceLayer, properties, null); + addCircleLayer(layerId, sourceId, belowLayerId, sourceLayer, properties, enableInteraction, null); result.success(null); break; } @@ -872,7 +885,7 @@ public void onFailure(@NonNull Exception exception) { } String layerId = call.argument("layerId"); style.removeLayer(layerId); - featureLayerIdentifiers.remove(layerId); + interactiveFeatureLayerIds.remove(layerId); result.success(null); break; diff --git a/example/lib/layer.dart b/example/lib/layer.dart index 1d606c542..80b4e7c2b 100644 --- a/example/lib/layer.dart +++ b/example/lib/layer.dart @@ -117,22 +117,23 @@ class LayerState extends State { ); await controller.addSymbolLayer( - "moving", - "moving", - SymbolLayerProperties( - textField: [Expressions.get, "name"], - textHaloWidth: 1, - textSize: 10, - textHaloColor: Colors.white.toHexStringRGB(), - textOffset: [ - Expressions.literal, - [0, 2] - ], - iconImage: "bicycle-15", - iconSize: 2, - iconAllowOverlap: true, - textAllowOverlap: true, - )); + "moving", + "moving", + SymbolLayerProperties( + textField: [Expressions.get, "name"], + textHaloWidth: 1, + textSize: 10, + textHaloColor: Colors.white.toHexStringRGB(), + textOffset: [ + Expressions.literal, + [0, 2] + ], + iconImage: "bicycle-15", + iconSize: 2, + iconAllowOverlap: true, + textAllowOverlap: true, + ), + ); timer = Timer.periodic( Duration(milliseconds: 10), (t) => controller.setGeoJsonSource( diff --git a/ios/Classes/MapboxMapController.swift b/ios/Classes/MapboxMapController.swift index af9fe858a..ace2ef3c6 100644 --- a/ios/Classes/MapboxMapController.swift +++ b/ios/Classes/MapboxMapController.swift @@ -25,7 +25,7 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma private var myLocationEnabled = false private var scrollingEnabled = true - private var featureLayerIdentifiers = Set() + private var interactiveFeatureLayerIds = Set() private var addedShapesByLayer = [String: MGLShape]() func view() -> UIView { @@ -556,12 +556,14 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma guard let arguments = methodCall.arguments as? [String: Any] else { return } guard let sourceId = arguments["sourceId"] as? String else { return } guard let layerId = arguments["layerId"] as? String else { return } + guard let enableInteraction = arguments["enableInteraction"] as? Bool else { return } guard let properties = arguments["properties"] as? [String: String] else { return } let belowLayerId = arguments["belowLayerId"] as? String addSymbolLayer( sourceId: sourceId, layerId: layerId, belowLayerId: belowLayerId, + enableInteraction: enableInteraction, properties: properties ) result(nil) @@ -570,12 +572,14 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma guard let arguments = methodCall.arguments as? [String: Any] else { return } guard let sourceId = arguments["sourceId"] as? String else { return } guard let layerId = arguments["layerId"] as? String else { return } + guard let enableInteraction = arguments["enableInteraction"] as? Bool else { return } guard let properties = arguments["properties"] as? [String: String] else { return } let belowLayerId = arguments["belowLayerId"] as? String addLineLayer( sourceId: sourceId, layerId: layerId, belowLayerId: belowLayerId, + enableInteraction: enableInteraction, properties: properties ) result(nil) @@ -584,12 +588,14 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma guard let arguments = methodCall.arguments as? [String: Any] else { return } guard let sourceId = arguments["sourceId"] as? String else { return } guard let layerId = arguments["layerId"] as? String else { return } + guard let enableInteraction = arguments["enableInteraction"] as? Bool else { return } guard let properties = arguments["properties"] as? [String: String] else { return } let belowLayerId = arguments["belowLayerId"] as? String addFillLayer( sourceId: sourceId, layerId: layerId, belowLayerId: belowLayerId, + enableInteraction: enableInteraction, properties: properties ) result(nil) @@ -598,12 +604,14 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma guard let arguments = methodCall.arguments as? [String: Any] else { return } guard let sourceId = arguments["sourceId"] as? String else { return } guard let layerId = arguments["layerId"] as? String else { return } + guard let enableInteraction = arguments["enableInteraction"] as? Bool else { return } guard let properties = arguments["properties"] as? [String: String] else { return } let belowLayerId = arguments["belowLayerId"] as? String addCircleLayer( sourceId: sourceId, layerId: layerId, belowLayerId: belowLayerId, + enableInteraction: enableInteraction, properties: properties ) result(nil) @@ -612,7 +620,7 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma guard let arguments = methodCall.arguments as? [String: Any] else { return } guard let layerId = arguments["layerId"] as? String else { return } guard let layer = mapView.style?.layer(withIdentifier: layerId) else { return } - featureLayerIdentifiers.remove(layerId) + interactiveFeatureLayerIds.remove(layerId) mapView.style?.removeLayer(layer) result(nil) @@ -682,9 +690,9 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma private func firstFeatureOnLayers(at: CGPoint) -> MGLFeature? { guard let style = mapView.style else { return nil } - // get layers in order (featureLayerIdentifiers is unordered) + // get layers in order (interactiveFeatureLayerIds is unordered) let clickableLayers = style.layers.filter { layer in - featureLayerIdentifiers.contains(layer.identifier) + interactiveFeatureLayerIds.contains(layer.identifier) } for layer in clickableLayers.reversed() { @@ -835,7 +843,7 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma } addedShapesByLayer.removeAll() - featureLayerIdentifiers.removeAll() + interactiveFeatureLayerIds.removeAll() mapReadyResult?(nil) @@ -900,6 +908,7 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma layerId: String, belowLayerId: String?, sourceLayerIdentifier: String?, + enableInteraction: Bool, properties: [String: String] ) { if let style = mapView.style { @@ -917,7 +926,9 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma } else { style.addLayer(layer) } - featureLayerIdentifiers.insert(layerId) + if enableInteraction { + interactiveFeatureLayerIds.insert(layerId) + } } } } @@ -927,6 +938,7 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma layerId: String, belowLayerId: String?, sourceLayerIdentifier: String?, + enableInteraction: Bool, properties: [String: String] ) { if let style = mapView.style { @@ -941,7 +953,9 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma } else { style.addLayer(layer) } - featureLayerIdentifiers.insert(layerId) + if enableInteraction { + interactiveFeatureLayerIds.insert(layerId) + } } } } @@ -951,6 +965,7 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma layerId: String, belowLayerId: String?, sourceLayerIdentifier: String?, + enableInteraction: Bool, properties: [String: String] ) { if let style = mapView.style { @@ -965,7 +980,9 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma } else { style.addLayer(layer) } - featureLayerIdentifiers.insert(layerId) + if enableInteraction { + interactiveFeatureLayerIds.insert(layerId) + } } } } @@ -975,6 +992,7 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma layerId: String, belowLayerId: String?, sourceLayerIdentifier: String?, + enableInteraction: Bool, properties: [String: String] ) { if let style = mapView.style { @@ -1015,7 +1033,9 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma } else { style.addLayer(layer) } - featureLayerIdentifiers.insert(layerId) + if enableInteraction { + interactiveFeatureLayerIds.insert(layerId) + } } } } diff --git a/lib/src/annotation_manager.dart b/lib/src/annotation_manager.dart index 1a5782f02..95d582295 100644 --- a/lib/src/annotation_manager.dart +++ b/lib/src/annotation_manager.dart @@ -6,7 +6,9 @@ abstract class AnnotationManager { final MapboxMapController controller; final void Function(T)? onTap; final _idToAnnotation = {}; + final _idToLayerIndex = {}; final String id; + final bool enableInteraction; List get allLayerProperties; final int Function(T)? selectLayer; @@ -14,8 +16,9 @@ abstract class AnnotationManager { Set get annotations => _idToAnnotation.values.toSet(); - AnnotationManager(this.controller, {this.onTap, this.selectLayer}) - : id = getRandomString(10) { + AnnotationManager(this.controller, + {this.onTap, this.selectLayer, required this.enableInteraction}) + : id = getRandomString() { for (var i = 0; i < allLayerProperties.length; i++) { final layerId = _makeLayerId(i); controller.addGeoJsonSource(layerId, buildFeatureCollection([]), @@ -51,7 +54,9 @@ abstract class AnnotationManager { final featureBuckets = [for (final _ in allLayerProperties) []]; for (final annotation in _idToAnnotation.values) { - featureBuckets[selectLayer!(annotation)].add(annotation); + final layerIndex = selectLayer!(annotation); + _idToLayerIndex[annotation.id] = layerIndex; + featureBuckets[layerIndex].add(annotation); } for (var i = 0; i < featureBuckets.length; i++) { @@ -114,15 +119,23 @@ abstract class AnnotationManager { Future set(T annoation) async { _idToAnnotation[annoation.id] = annoation; + final oldLayerIndex = _idToLayerIndex[annoation.id]; final layerIndex = selectLayer != null ? selectLayer!(annoation) : 0; - await controller.setGeoJsonFeature( - _makeLayerId(layerIndex), annoation.toGeoJson()); + if (oldLayerIndex != layerIndex) { + // if the annotation has to be moved to another layer/source we have to + // set all + await _setAll(); + } else { + await controller.setGeoJsonFeature( + _makeLayerId(layerIndex), annoation.toGeoJson()); + } } } class LineManager extends AnnotationManager { - LineManager(MapboxMapController controller, {void Function(Line)? onTap}) - : super(controller, onTap: onTap); + LineManager(MapboxMapController controller, + {void Function(Line)? onTap, bool enableInteraction = true}) + : super(controller, onTap: onTap, enableInteraction: enableInteraction); @override List get allLayerProperties => const [ LineLayerProperties( @@ -137,9 +150,13 @@ class LineManager extends AnnotationManager { } class FillManager extends AnnotationManager { - FillManager(MapboxMapController controller, {void Function(Fill)? onTap}) - : super(controller, + FillManager( + MapboxMapController controller, { + void Function(Fill)? onTap, + bool enableInteraction = true, + }) : super(controller, onTap: onTap, + enableInteraction: enableInteraction, selectLayer: (Fill fill) => fill.options.fillPattern == null ? 0 : 1); @override @@ -159,8 +176,15 @@ class FillManager extends AnnotationManager { } class CircleManager extends AnnotationManager { - CircleManager(MapboxMapController controller, {void Function(Circle)? onTap}) - : super(controller, onTap: onTap); + CircleManager( + MapboxMapController controller, { + void Function(Circle)? onTap, + bool enableInteraction = true, + }) : super( + controller, + enableInteraction: enableInteraction, + onTap: onTap, + ); @override List get allLayerProperties => const [ CircleLayerProperties( @@ -183,11 +207,16 @@ class SymbolManager extends AnnotationManager { bool textAllowOverlap = false, bool iconIgnorePlacement = false, bool textIgnorePlacement = false, + bool enableInteraction = true, }) : _iconAllowOverlap = iconAllowOverlap, _textAllowOverlap = textAllowOverlap, _iconIgnorePlacement = iconIgnorePlacement, _textIgnorePlacement = textIgnorePlacement, - super(controller, onTap: onTap); + super( + controller, + enableInteraction: enableInteraction, + onTap: onTap, + ); bool _iconAllowOverlap; bool _textAllowOverlap; diff --git a/lib/src/controller.dart b/lib/src/controller.dart index f3142b9a7..1a47bf093 100644 --- a/lib/src/controller.dart +++ b/lib/src/controller.dart @@ -50,6 +50,7 @@ class MapboxMapController extends ChangeNotifier { required MapboxGlPlatform mapboxGlPlatform, required CameraPosition initialCameraPosition, required Iterable annotationOrder, + required Iterable annotationConsumeTapEvents, this.onStyleLoadedCallback, this.onMapClick, this.onMapLongClick, @@ -101,22 +102,25 @@ class MapboxMapController extends ChangeNotifier { }); _mapboxGlPlatform.onMapStyleLoadedPlatform.add((_) { + final interactionEnabled = annotationConsumeTapEvents.toSet(); for (var type in annotationOrder.toSet()) { + final enableInteraction = interactionEnabled.contains(type); switch (type) { case AnnotationType.fill: - fillManager = FillManager(this, onTap: onFillTapped); + fillManager = FillManager(this, + onTap: onFillTapped, enableInteraction: enableInteraction); break; case AnnotationType.line: - lineManager = LineManager(this, onTap: onLineTapped); + lineManager = LineManager(this, + onTap: onLineTapped, enableInteraction: enableInteraction); break; case AnnotationType.circle: - circleManager = CircleManager(this, onTap: onCircleTapped); + circleManager = CircleManager(this, + onTap: onCircleTapped, enableInteraction: enableInteraction); break; case AnnotationType.symbol: - symbolManager = SymbolManager( - this, - onTap: onSymbolTapped, - ); + symbolManager = SymbolManager(this, + onTap: onSymbolTapped, enableInteraction: enableInteraction); break; default: } @@ -289,6 +293,7 @@ class MapboxMapController extends ChangeNotifier { /// /// The returned [Future] completes after the change has been made on the /// platform side. + /// Future addGeoJsonSource(String sourceId, Map geojson, {String? promoteId}) async { await _mapboxGlPlatform.addGeoJsonSource(sourceId, geojson, @@ -336,13 +341,16 @@ class MapboxMapController extends ChangeNotifier { /// Note: [belowLayerId] is currently ignored on the web Future addSymbolLayer( String sourceId, String layerId, SymbolLayerProperties properties, - {String? belowLayerId, String? sourceLayer}) async { + {String? belowLayerId, + String? sourceLayer, + bool enableInteraction = true}) async { await _mapboxGlPlatform.addSymbolLayer( sourceId, layerId, properties.toJson(), belowLayerId: belowLayerId, sourceLayer: sourceLayer, + enableInteraction: enableInteraction, ); } @@ -354,13 +362,16 @@ class MapboxMapController extends ChangeNotifier { /// Note: [belowLayerId] is currently ignored on the web Future addLineLayer( String sourceId, String layerId, LineLayerProperties properties, - {String? belowLayerId, String? sourceLayer}) async { + {String? belowLayerId, + String? sourceLayer, + bool enableInteraction = true}) async { await _mapboxGlPlatform.addLineLayer( sourceId, layerId, properties.toJson(), belowLayerId: belowLayerId, sourceLayer: sourceLayer, + enableInteraction: enableInteraction, ); } @@ -372,13 +383,16 @@ class MapboxMapController extends ChangeNotifier { /// Note: [belowLayerId] is currently ignored on the web Future addFillLayer( String sourceId, String layerId, FillLayerProperties properties, - {String? belowLayerId, String? sourceLayer}) async { + {String? belowLayerId, + String? sourceLayer, + bool enableInteraction = true}) async { await _mapboxGlPlatform.addFillLayer( sourceId, layerId, properties.toJson(), belowLayerId: belowLayerId, sourceLayer: sourceLayer, + enableInteraction: enableInteraction, ); } @@ -390,13 +404,16 @@ class MapboxMapController extends ChangeNotifier { /// Note: [belowLayerId] is currently ignored on the web Future addCircleLayer( String sourceId, String layerId, CircleLayerProperties properties, - {String? belowLayerId, String? sourceLayer}) async { + {String? belowLayerId, + String? sourceLayer, + bool enableInteraction = true}) async { await _mapboxGlPlatform.addCircleLayer( sourceId, layerId, properties.toJson(), belowLayerId: belowLayerId, sourceLayer: sourceLayer, + enableInteraction: enableInteraction, ); } @@ -432,15 +449,19 @@ class MapboxMapController extends ChangeNotifier { Future addLayer( String sourceId, String layerId, LayerProperties properties, - {String? belowLayerId}) async { + {String? belowLayerId, bool enableInteraction = true}) async { if (properties is FillLayerProperties) { - addFillLayer(sourceId, layerId, properties); + addFillLayer(sourceId, layerId, properties, + enableInteraction: enableInteraction); } else if (properties is LineLayerProperties) { - addLineLayer(sourceId, layerId, properties); + addLineLayer(sourceId, layerId, properties, + enableInteraction: enableInteraction); } else if (properties is SymbolLayerProperties) { - addSymbolLayer(sourceId, layerId, properties); + addSymbolLayer(sourceId, layerId, properties, + enableInteraction: enableInteraction); } else if (properties is CircleLayerProperties) { - addCircleLayer(sourceId, layerId, properties); + addCircleLayer(sourceId, layerId, properties, + enableInteraction: enableInteraction); } } diff --git a/lib/src/mapbox_map.dart b/lib/src/mapbox_map.dart index 3891b5939..3e2c92856 100644 --- a/lib/src/mapbox_map.dart +++ b/lib/src/mapbox_map.dart @@ -302,6 +302,7 @@ class _MapboxMapState extends State { onCameraIdle: widget.onCameraIdle, onMapIdle: widget.onMapIdle, annotationOrder: widget.annotationOrder, + annotationConsumeTapEvents: widget.annotationConsumeTapEvents, ); await _mapboxGlPlatform.initPlatform(id); _controller.complete(controller); diff --git a/mapbox_gl_platform_interface/lib/src/mapbox_gl_platform_interface.dart b/mapbox_gl_platform_interface/lib/src/mapbox_gl_platform_interface.dart index cacb52095..25e0c4d85 100644 --- a/mapbox_gl_platform_interface/lib/src/mapbox_gl_platform_interface.dart +++ b/mapbox_gl_platform_interface/lib/src/mapbox_gl_platform_interface.dart @@ -104,18 +104,27 @@ abstract class MapboxGlPlatform { Future addSymbolLayer( String sourceId, String layerId, Map properties, - {String? belowLayerId}); + {String? belowLayerId, + String? sourceLayer, + required bool enableInteraction}); Future addLineLayer( String sourceId, String layerId, Map properties, - {String? belowLayerId}); + {String? belowLayerId, + String? sourceLayer, + required bool enableInteraction}); Future addCircleLayer( String sourceId, String layerId, Map properties, - {String? belowLayerId}); + {String? belowLayerId, + String? sourceLayer, + required bool enableInteraction}); + Future addFillLayer( String sourceId, String layerId, Map properties, - {String? belowLayerId}); + {String? belowLayerId, + String? sourceLayer, + required bool enableInteraction}); Future addRasterLayer( String sourceId, String layerId, Map properties, diff --git a/mapbox_gl_platform_interface/lib/src/method_channel_mapbox_gl.dart b/mapbox_gl_platform_interface/lib/src/method_channel_mapbox_gl.dart index a14ee21ac..b53ef9100 100644 --- a/mapbox_gl_platform_interface/lib/src/method_channel_mapbox_gl.dart +++ b/mapbox_gl_platform_interface/lib/src/method_channel_mapbox_gl.dart @@ -477,12 +477,15 @@ class MethodChannelMapboxGl extends MapboxGlPlatform { @override Future addSymbolLayer( String sourceId, String layerId, Map properties, - {String? belowLayerId, String? sourceLayer}) async { + {String? belowLayerId, + String? sourceLayer, + required bool enableInteraction}) async { await _channel.invokeMethod('symbolLayer#add', { 'sourceId': sourceId, 'layerId': layerId, 'belowLayerId': belowLayerId, 'sourceLayer': sourceLayer, + 'enableInteraction': enableInteraction, 'properties': properties .map((key, value) => MapEntry(key, jsonEncode(value))) }); @@ -491,12 +494,15 @@ class MethodChannelMapboxGl extends MapboxGlPlatform { @override Future addLineLayer( String sourceId, String layerId, Map properties, - {String? belowLayerId, String? sourceLayer}) async { + {String? belowLayerId, + String? sourceLayer, + required bool enableInteraction}) async { await _channel.invokeMethod('lineLayer#add', { 'sourceId': sourceId, 'layerId': layerId, 'belowLayerId': belowLayerId, 'sourceLayer': sourceLayer, + 'enableInteraction': enableInteraction, 'properties': properties .map((key, value) => MapEntry(key, jsonEncode(value))) }); @@ -505,12 +511,15 @@ class MethodChannelMapboxGl extends MapboxGlPlatform { @override Future addCircleLayer( String sourceId, String layerId, Map properties, - {String? belowLayerId, String? sourceLayer}) async { + {String? belowLayerId, + String? sourceLayer, + required bool enableInteraction}) async { await _channel.invokeMethod('circleLayer#add', { 'sourceId': sourceId, 'layerId': layerId, 'belowLayerId': belowLayerId, 'sourceLayer': sourceLayer, + 'enableInteraction': enableInteraction, 'properties': properties .map((key, value) => MapEntry(key, jsonEncode(value))) }); @@ -519,12 +528,15 @@ class MethodChannelMapboxGl extends MapboxGlPlatform { @override Future addFillLayer( String sourceId, String layerId, Map properties, - {String? belowLayerId, String? sourceLayer}) async { + {String? belowLayerId, + String? sourceLayer, + required bool enableInteraction}) async { await _channel.invokeMethod('fillLayer#add', { 'sourceId': sourceId, 'layerId': layerId, 'belowLayerId': belowLayerId, 'sourceLayer': sourceLayer, + 'enableInteraction': enableInteraction, 'properties': properties .map((key, value) => MapEntry(key, jsonEncode(value))) }); diff --git a/mapbox_gl_web/lib/src/mapbox_web_gl_platform.dart b/mapbox_gl_web/lib/src/mapbox_web_gl_platform.dart index cd05f072f..2f839d036 100644 --- a/mapbox_gl_web/lib/src/mapbox_web_gl_platform.dart +++ b/mapbox_gl_web/lib/src/mapbox_web_gl_platform.dart @@ -14,8 +14,9 @@ class MapboxWebGlPlatform extends MapboxGlPlatform LatLng? _dragOrigin; LatLng? _dragPrevious; bool _dragEnabled = true; + final _addedFeaturesByLayer = {}; - final _featureLayerIdentifiers = Set(); + final _interactiveFeatureLayerIds = Set(); bool _trackCameraPosition = false; GeolocateControl? _geolocateControl; @@ -316,8 +317,8 @@ class MapboxWebGlPlatform extends MapboxGlPlatform } void _onMapClick(Event e) { - final features = _map.queryRenderedFeatures( - [e.point.x, e.point.y], {"layers": _featureLayerIdentifiers.toList()}); + final features = _map.queryRenderedFeatures([e.point.x, e.point.y], + {"layers": _interactiveFeatureLayerIds.toList()}); final payload = { 'point': Point(e.point.x.toDouble(), e.point.y.toDouble()), 'latLng': LatLng(e.lngLat.lat.toDouble(), e.lngLat.lng.toDouble()), @@ -558,13 +559,13 @@ class MapboxWebGlPlatform extends MapboxGlPlatform @override void setStyleString(String? styleString) { //remove old mouseenter callbacks to avoid multicalling - for (var layerId in _featureLayerIdentifiers) { + for (var layerId in _interactiveFeatureLayerIds) { _map.off('mouseenter', layerId, _onMouseEnterFeature); _map.off('mousemouve', layerId, _onMouseEnterFeature); _map.off('mouseleave', layerId, _onMouseLeaveFeature); if (_dragEnabled) _map.off('mousedown', layerId, _onMouseDown); } - _featureLayerIdentifiers.clear(); + _interactiveFeatureLayerIds.clear(); _map.setStyle(styleString); // catch style loaded for later style changes @@ -611,16 +612,18 @@ class MapboxWebGlPlatform extends MapboxGlPlatform @override Future removeLayer(String layerId) async { - _featureLayerIdentifiers.remove(layerId); + _interactiveFeatureLayerIds.remove(layerId); _map.removeLayer(layerId); } @override Future addGeoJsonSource(String sourceId, Map geojson, {String? promoteId}) async { + final data = _makeFeatureCollection(geojson); + _addedFeaturesByLayer[sourceId] = data; _map.addSource(sourceId, { "type": 'geojson', - "data": geojson, + "data": geojson, // pass the raw string here to avoid errors if (promoteId != null) "promoteId": promoteId }); } @@ -634,45 +637,66 @@ class MapboxWebGlPlatform extends MapboxGlPlatform id: geojsonFeature["properties"]?["id"] ?? geojsonFeature["id"]); } + FeatureCollection _makeFeatureCollection(Map geojson) { + return FeatureCollection( + features: [for (final f in geojson["features"] ?? []) _makeFeature(f)]); + } + @override Future setGeoJsonSource( String sourceId, Map geojson) async { final source = _map.getSource(sourceId) as GeoJsonSource; - final data = FeatureCollection( - features: [for (final f in geojson["features"] ?? []) _makeFeature(f)]); + final data = _makeFeatureCollection(geojson); + _addedFeaturesByLayer[sourceId] = data; source.setData(data); } @override Future addCircleLayer( String sourceId, String layerId, Map properties, - {String? belowLayerId, String? sourceLayer}) async { + {String? belowLayerId, + String? sourceLayer, + required bool enableInteraction}) async { return _addLayer(sourceId, layerId, properties, "circle", - belowLayerId: belowLayerId, sourceLayer: sourceLayer); + belowLayerId: belowLayerId, + sourceLayer: sourceLayer, + enableInteraction: enableInteraction); } @override Future addFillLayer( String sourceId, String layerId, Map properties, - {String? belowLayerId, String? sourceLayer}) async { + {String? belowLayerId, + String? sourceLayer, + required bool enableInteraction}) async { return _addLayer(sourceId, layerId, properties, "fill", - belowLayerId: belowLayerId, sourceLayer: sourceLayer); + belowLayerId: belowLayerId, + sourceLayer: sourceLayer, + enableInteraction: enableInteraction); } @override Future addLineLayer( String sourceId, String layerId, Map properties, - {String? belowLayerId, String? sourceLayer}) async { + {String? belowLayerId, + String? sourceLayer, + required bool enableInteraction}) async { return _addLayer(sourceId, layerId, properties, "line", - belowLayerId: belowLayerId, sourceLayer: sourceLayer); + belowLayerId: belowLayerId, + sourceLayer: sourceLayer, + enableInteraction: enableInteraction); } @override Future addSymbolLayer( String sourceId, String layerId, Map properties, - {String? belowLayerId, String? sourceLayer}) async { + {String? belowLayerId, + String? sourceLayer, + required bool enableInteraction}) async { return _addLayer(sourceId, layerId, properties, "symbol", - belowLayerId: belowLayerId, sourceLayer: sourceLayer); + belowLayerId: belowLayerId, + sourceLayer: sourceLayer, + enableInteraction: enableInteraction); } @override @@ -680,12 +704,26 @@ class MapboxWebGlPlatform extends MapboxGlPlatform String sourceId, String layerId, Map properties, {String? belowLayerId, String? sourceLayer}) async { return _addLayer(sourceId, layerId, properties, "hillshade", - belowLayerId: belowLayerId, sourceLayer: sourceLayer); + belowLayerId: belowLayerId, + sourceLayer: sourceLayer, + enableInteraction: false); + } + + @override + Future addRasterLayer( + String sourceId, String layerId, Map properties, + {String? belowLayerId, String? sourceLayer}) async { + await _addLayer(sourceId, layerId, properties, "raster", + belowLayerId: belowLayerId, + sourceLayer: sourceLayer, + enableInteraction: false); } Future _addLayer(String sourceId, String layerId, Map properties, String layerType, - {String? belowLayerId, String? sourceLayer}) async { + {String? belowLayerId, + String? sourceLayer, + required bool enableInteraction}) async { final layout = Map.fromEntries( properties.entries.where((entry) => isLayoutProperty(entry.key))); final paint = Map.fromEntries( @@ -700,14 +738,16 @@ class MapboxWebGlPlatform extends MapboxGlPlatform if (sourceLayer != null) 'source-layer': sourceLayer }, belowLayerId); - _featureLayerIdentifiers.add(layerId); - if (layerType == "fill") { - _map.on('mousemove', layerId, _onMouseEnterFeature); - } else { - _map.on('mouseenter', layerId, _onMouseEnterFeature); + if (enableInteraction) { + _interactiveFeatureLayerIds.add(layerId); + if (layerType == "fill") { + _map.on('mousemove', layerId, _onMouseEnterFeature); + } else { + _map.on('mouseenter', layerId, _onMouseEnterFeature); + } + _map.on('mouseleave', layerId, _onMouseLeaveFeature); + if (_dragEnabled) _map.on('mousedown', layerId, _onMouseDown); } - _map.on('mouseleave', layerId, _onMouseLeaveFeature); - if (_dragEnabled) _map.on('mousedown', layerId, _onMouseDown); } void _onMouseEnterFeature(_) { @@ -779,12 +819,6 @@ class MapboxWebGlPlatform extends MapboxGlPlatform _map.addSource(sourceId, source.toJson()); } - @override - Future addRasterLayer( - String sourceId, String layerId, Map properties, - {String? belowLayerId, String? sourceLayer}) async { - await _addLayer(sourceId, layerId, properties, "raster", - belowLayerId: belowLayerId, sourceLayer: sourceLayer); Future addImageSource( String imageSourceId, Uint8List bytes, LatLngQuad coordinates) { // TODO: implement addImageSource @@ -814,14 +848,18 @@ class MapboxWebGlPlatform extends MapboxGlPlatform Future setFeatureForGeoJsonSource( String sourceId, Map geojsonFeature) async { final source = _map.getSource(sourceId) as GeoJsonSource?; + final data = _addedFeaturesByLayer[sourceId]; - if (source != null) { + if (source != null && data != null) { final feature = _makeFeature(geojsonFeature); - final data = source.data; - final index = data.features.indexWhere((f) => f.id == feature.id); + final features = data.features.toList(); + final index = features.indexWhere((f) => f.id == feature.id); if (index >= 0) { - data.features[index] = feature; - source.setData(data); + features[index] = feature; + final newData = FeatureCollection(features: features); + _addedFeaturesByLayer[sourceId] = newData; + + source.setData(newData); } } } From d80262bd1b686ddc30b46b203f6b5721837ab911 Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Mon, 20 Dec 2021 17:33:07 +0100 Subject: [PATCH 18/26] fixed web issue with textFont --- lib/src/annotation_manager.dart | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/src/annotation_manager.dart b/lib/src/annotation_manager.dart index 95d582295..b45ef615a 100644 --- a/lib/src/annotation_manager.dart +++ b/lib/src/annotation_manager.dart @@ -255,15 +255,19 @@ class SymbolManager extends AnnotationManager { iconRotate: [Expressions.get, 'iconRotate'], iconOffset: [Expressions.get, 'iconOffset'], iconAnchor: [Expressions.get, 'iconAnchor'], - textFont: [ - Expressions.caseExpression, - [Expressions.has, 'fontNames'], - [Expressions.get, 'fontNames'], - [ - Expressions.literal, - ["Open Sans Regular", "Arial Unicode MS Regular"] - ], - ], + // note that web does not support setting this in a fully data driven + // way this is a upstream issue + textFont: kIsWeb + ? null + : [ + Expressions.caseExpression, + [Expressions.has, 'fontNames'], + [Expressions.get, 'fontNames'], + [ + Expressions.literal, + ["Open Sans Regular", "Arial Unicode MS Regular"] + ], + ], textField: [Expressions.get, 'textField'], textSize: [Expressions.get, 'textSize'], textMaxWidth: [Expressions.get, 'textMaxWidth'], From e48e2fa922e5bc79f006be612b022d17cfe2c04b Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Mon, 20 Dec 2021 18:36:30 +0100 Subject: [PATCH 19/26] removed unused imports --- .../com/mapbox/mapboxgl/MapboxMapController.java | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java index c43ec29eb..85d45b5ae 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java +++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java @@ -59,20 +59,6 @@ import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.offline.OfflineManager; -import com.mapbox.mapboxsdk.plugins.annotation.Annotation; -import com.mapbox.mapboxsdk.plugins.annotation.Circle; -import com.mapbox.mapboxsdk.plugins.annotation.CircleManager; -import com.mapbox.mapboxsdk.plugins.annotation.CircleOptions; -import com.mapbox.mapboxsdk.plugins.annotation.Fill; -import com.mapbox.mapboxsdk.plugins.annotation.FillManager; -import com.mapbox.mapboxsdk.plugins.annotation.FillOptions; -import com.mapbox.mapboxsdk.plugins.annotation.Line; -import com.mapbox.mapboxsdk.plugins.annotation.LineManager; -import com.mapbox.mapboxsdk.plugins.annotation.LineOptions; -import com.mapbox.mapboxsdk.plugins.annotation.OnAnnotationClickListener; -import com.mapbox.mapboxsdk.plugins.annotation.Symbol; -import com.mapbox.mapboxsdk.plugins.annotation.SymbolManager; -import com.mapbox.mapboxsdk.plugins.annotation.SymbolOptions; import com.mapbox.mapboxsdk.plugins.localization.LocalizationPlugin; import com.mapbox.mapboxsdk.style.expressions.Expression; import com.mapbox.mapboxsdk.style.layers.Layer; From 833f3de34fa6aae63b5a286716ddbd6fde4e1aaa Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Fri, 24 Dec 2021 11:40:14 +0100 Subject: [PATCH 20/26] better documentation added missing options to line manager --- lib/src/annotation_manager.dart | 99 +++++++++++++------ .../lib/src/symbol.dart | 2 + 2 files changed, 70 insertions(+), 31 deletions(-) diff --git a/lib/src/annotation_manager.dart b/lib/src/annotation_manager.dart index b45ef615a..f2fda633b 100644 --- a/lib/src/annotation_manager.dart +++ b/lib/src/annotation_manager.dart @@ -1,17 +1,30 @@ part of mapbox_gl; -int _getFirst(Annotation _) => 0; - abstract class AnnotationManager { final MapboxMapController controller; - final void Function(T)? onTap; final _idToAnnotation = {}; final _idToLayerIndex = {}; + + /// Called if a annotation is tapped + final void Function(T)? onTap; + + /// base id of the manager. User [layerdIds] to get the actual ids. final String id; + + List get layerIds => + [for (int i = 0; i < allLayerProperties.length; i++) _makeLayerId(i)]; + + /// If disabled the manager offers no interaction for the created symbols final bool enableInteraction; + + /// implemented to define the layer properties List get allLayerProperties; + + /// used to spedicy the layer and annotation will life on + /// This can be replaced by layer filters a soon as they are implemented final int Function(T)? selectLayer; + /// get the an annotation by its id T? byId(String id) => _idToAnnotation[id]; Set get annotations => _idToAnnotation.values.toSet(); @@ -32,7 +45,9 @@ abstract class AnnotationManager { controller.onFeatureDrag.add(_onDrag); } - Future rebuildLayers() async { + /// This function can be used to rebuild all layers after their properties + /// changed + Future _rebuildLayers() async { for (var i = 0; i < allLayerProperties.length; i++) { final layerId = _makeLayerId(i); await controller.removeLayer(layerId); @@ -73,6 +88,8 @@ abstract class AnnotationManager { } } + /// Adds a multiple annotations to the map. This much faster than calling add + /// multiple times Future addAll(Iterable annotations) async { for (var a in annotations) { _idToAnnotation[a.id] = a; @@ -80,22 +97,27 @@ abstract class AnnotationManager { await _setAll(); } + /// add a single annotation to the map Future add(T annotation) async { _idToAnnotation[annotation.id] = annotation; await _setAll(); } + /// Remove a single annotation form the map Future remove(T annotation) async { _idToAnnotation.remove(annotation.id); await _setAll(); } + /// Removes all annotations from the map Future clear() async { _idToAnnotation.clear(); await _setAll(); } + /// Fully dipose of all the the resouces managed by the annotation manager. + /// The manager cannot be used after this has been called Future dispose() async { _idToAnnotation.clear(); await _setAll(); @@ -117,7 +139,11 @@ abstract class AnnotationManager { } } + /// Set an existing anntotation to the map. Use this to do a fast update for a + /// single annotation Future set(T annoation) async { + assert(_idToAnnotation.containsKey(annoation.id), + "you can only set existing annotations"); _idToAnnotation[annoation.id] = annoation; final oldLayerIndex = _idToLayerIndex[annoation.id]; final layerIndex = selectLayer != null ? selectLayer!(annoation) : 0; @@ -135,17 +161,27 @@ abstract class AnnotationManager { class LineManager extends AnnotationManager { LineManager(MapboxMapController controller, {void Function(Line)? onTap, bool enableInteraction = true}) - : super(controller, onTap: onTap, enableInteraction: enableInteraction); + : super( + controller, + onTap: onTap, + enableInteraction: enableInteraction, + selectLayer: (Line line) => line.options.linePattern == null ? 0 : 1, + ); + + static const _baseProperties = LineLayerProperties( + lineJoin: [Expressions.get, 'lineJoin'], + lineOpacity: [Expressions.get, 'lineOpacity'], + lineColor: [Expressions.get, 'lineColor'], + lineWidth: [Expressions.get, 'lineWidth'], + lineGapWidth: [Expressions.get, 'lineGapWidth'], + lineOffset: [Expressions.get, 'lineOffset'], + lineBlur: [Expressions.get, 'lineBlur'], + ); @override - List get allLayerProperties => const [ - LineLayerProperties( - lineOpacity: [Expressions.get, 'lineOpacity'], - lineColor: [Expressions.get, 'lineColor'], - lineWidth: [Expressions.get, 'lineWidth'], - lineGapWidth: [Expressions.get, 'lineGapWidth'], - lineOffset: [Expressions.get, 'lineOffset'], - lineBlur: [Expressions.get, 'lineBlur'], - ) + List get allLayerProperties => [ + _baseProperties, + _baseProperties.copyWith( + LineLayerProperties(linePattern: [Expressions.get, 'linePattern'])), ]; } @@ -154,11 +190,12 @@ class FillManager extends AnnotationManager { MapboxMapController controller, { void Function(Fill)? onTap, bool enableInteraction = true, - }) : super(controller, - onTap: onTap, - enableInteraction: enableInteraction, - selectLayer: (Fill fill) => - fill.options.fillPattern == null ? 0 : 1); + }) : super( + controller, + onTap: onTap, + enableInteraction: enableInteraction, + selectLayer: (Fill fill) => fill.options.fillPattern == null ? 0 : 1, + ); @override List get allLayerProperties => const [ FillLayerProperties( @@ -226,25 +263,25 @@ class SymbolManager extends AnnotationManager { /// For more information on what this does, see https://docs.mapbox.com/help/troubleshooting/optimize-map-label-placement/#label-collision Future setIconAllowOverlap(bool value) async { _iconAllowOverlap = value; - await rebuildLayers(); + await _rebuildLayers(); } /// For more information on what this does, see https://docs.mapbox.com/help/troubleshooting/optimize-map-label-placement/#label-collision Future setTextAllowOverlap(bool value) async { _textAllowOverlap = value; - await rebuildLayers(); + await _rebuildLayers(); } /// For more information on what this does, see https://docs.mapbox.com/help/troubleshooting/optimize-map-label-placement/#label-collision Future setIconIgnorePlacement(bool value) async { _iconIgnorePlacement = value; - await rebuildLayers(); + await _rebuildLayers(); } /// For more information on what this does, see https://docs.mapbox.com/help/troubleshooting/optimize-map-label-placement/#label-collision Future setTextIgnorePlacement(bool value) async { _textIgnorePlacement = value; - await rebuildLayers(); + await _rebuildLayers(); } @override @@ -255,6 +292,11 @@ class SymbolManager extends AnnotationManager { iconRotate: [Expressions.get, 'iconRotate'], iconOffset: [Expressions.get, 'iconOffset'], iconAnchor: [Expressions.get, 'iconAnchor'], + iconOpacity: [Expressions.get, 'iconOpacity'], + iconColor: [Expressions.get, 'iconColor'], + iconHaloColor: [Expressions.get, 'iconHaloColor'], + iconHaloWidth: [Expressions.get, 'iconHaloWidth'], + iconHaloBlur: [Expressions.get, 'iconHaloBlur'], // note that web does not support setting this in a fully data driven // way this is a upstream issue textFont: kIsWeb @@ -277,21 +319,16 @@ class SymbolManager extends AnnotationManager { textRotate: [Expressions.get, 'textRotate'], textTransform: [Expressions.get, 'textTransform'], textOffset: [Expressions.get, 'textOffset'], - iconAllowOverlap: _iconAllowOverlap, - iconIgnorePlacement: _iconIgnorePlacement, - iconOpacity: [Expressions.get, 'iconOpacity'], - iconColor: [Expressions.get, 'iconColor'], - iconHaloColor: [Expressions.get, 'iconHaloColor'], - iconHaloWidth: [Expressions.get, 'iconHaloWidth'], - iconHaloBlur: [Expressions.get, 'iconHaloBlur'], textOpacity: [Expressions.get, 'textOpacity'], textColor: [Expressions.get, 'textColor'], textHaloColor: [Expressions.get, 'textHaloColor'], textHaloWidth: [Expressions.get, 'textHaloWidth'], textHaloBlur: [Expressions.get, 'textHaloBlur'], + symbolSortKey: [Expressions.get, 'zIndex'], + iconAllowOverlap: _iconAllowOverlap, + iconIgnorePlacement: _iconIgnorePlacement, textAllowOverlap: _textAllowOverlap, textIgnorePlacement: _textIgnorePlacement, - symbolSortKey: [Expressions.get, 'zIndex'], ) ]; } diff --git a/mapbox_gl_platform_interface/lib/src/symbol.dart b/mapbox_gl_platform_interface/lib/src/symbol.dart index 7d6ff6a09..5e088d538 100644 --- a/mapbox_gl_platform_interface/lib/src/symbol.dart +++ b/mapbox_gl_platform_interface/lib/src/symbol.dart @@ -94,6 +94,8 @@ class SymbolOptions { final double? iconRotate; final Offset? iconOffset; final String? iconAnchor; + + /// Not supported on web final List? fontNames; final String? textField; final double? textSize; From e5e03d88d86c11ef973a3f1af6264e0f09167775 Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Fri, 24 Dec 2021 12:00:21 +0100 Subject: [PATCH 21/26] revert line example changes --- example/lib/line.dart | 46 ++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/example/lib/line.dart b/example/lib/line.dart index 7720bab2a..cc8e541df 100644 --- a/example/lib/line.dart +++ b/example/lib/line.dart @@ -34,19 +34,18 @@ class LineBodyState extends State { static final LatLng center = const LatLng(-33.86711, 151.1947171); MapboxMapController? controller; - LineManager? lineManager; - int lineId = 0; - int _lineCount = 0; Line? _selectedLine; final String _linePatternImage = "assets/fill/cat_silhouette_pattern.png"; void _onMapCreated(MapboxMapController controller) { this.controller = controller; + controller.onLineTapped.add(_onLineTapped); } @override void dispose() { + controller?.onLineTapped.remove(_onLineTapped); super.dispose(); } @@ -58,23 +57,23 @@ class LineBodyState extends State { } _onLineTapped(Line line) async { + await _updateSelectedLine( + LineOptions(lineColor: "#ff0000"), + ); setState(() { _selectedLine = line; }); await _updateSelectedLine( - LineOptions(lineColor: "#ff0000"), + LineOptions(lineColor: "#ffe100"), ); } - Future _updateSelectedLine(LineOptions changes) { - _selectedLine!.options = _selectedLine!.options.copyWith(changes); - - return lineManager!.set(_selectedLine!); + _updateSelectedLine(LineOptions changes) async { + if (_selectedLine != null) controller!.updateLine(_selectedLine!, changes); } void _add() { - lineManager!.add(Line( - lineId.toString(), + controller!.addLine( LineOptions( geometry: [ LatLng(-33.86711, 151.1947171), @@ -83,24 +82,28 @@ class LineBodyState extends State { LatLng(-33.86711, 152.1947171), ], lineColor: "#ff0000", - lineWidth: 30.0, + lineWidth: 14.0, lineOpacity: 0.5, draggable: true), - )); - + ); setState(() { - lineId++; _lineCount += 1; }); } _move() async { - _selectedLine!.translate(LatLng(0.1, 0.1)); - await lineManager!.set(_selectedLine!); + final currentStart = _selectedLine!.options.geometry![0]; + final currentEnd = _selectedLine!.options.geometry![1]; + final end = + LatLng(currentEnd.latitude + 0.001, currentEnd.longitude + 0.001); + final start = + LatLng(currentStart.latitude - 0.001, currentStart.longitude - 0.001); + await controller! + .updateLine(_selectedLine!, LineOptions(geometry: [start, end])); } void _remove() { - lineManager!.remove(_selectedLine!); + controller!.removeLine(_selectedLine!); setState(() { _selectedLine = null; _lineCount -= 1; @@ -162,7 +165,7 @@ class LineBodyState extends State { child: MapboxMap( accessToken: MapsDemo.ACCESS_TOKEN, onMapCreated: _onMapCreated, - onStyleLoadedCallback: onStyleLoadedCallback, + onStyleLoadedCallback: _onStyleLoadedCallback, initialCameraPosition: const CameraPosition( target: LatLng(-33.852, 151.211), zoom: 11.0, @@ -220,10 +223,9 @@ class LineBodyState extends State { onPressed: (_selectedLine == null) ? null : () async { - var current = - lineManager!.byId(_selectedLine!.id)!; - for (var latLng - in current.options.geometry!) { + var latLngs = await controller! + .getLineLatLngs(_selectedLine!); + for (var latLng in latLngs) { print(latLng.toString()); } }, From 1baec4499fd78652685fcd3bf80c151e4f05480b Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Fri, 14 Jan 2022 14:40:43 +0100 Subject: [PATCH 22/26] added a fix for the android performance issues --- .../com/mapbox/mapboxgl/MapboxMapController.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java index 85d45b5ae..b90bbe920 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java +++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java @@ -146,6 +146,7 @@ final class MapboxMapController private Map addedFeaturesByLayer; private LatLngBounds bounds = null; + private Long currentMoveGestureDuration = Long.MAX_VALUE; MapboxMapController( int id, @@ -1332,7 +1333,13 @@ public void onCancel() { } boolean onMoveBegin(MoveGestureDetector detector) { - if (detector.getPointersCount() == 1) { + final Long lastMoveDuration = currentMoveGestureDuration; + currentMoveGestureDuration = detector.getGestureDuration(); + + // onMoveBegin gets called even during a move - move end is also not called unless this function returns + // true at least once. To avoid redundant queries to firstFeatureOnLayers it is only invoked + // if lastMoveDuration is larger than currentMoveGestureDuration so we know that a new move has started + if (lastMoveDuration > currentMoveGestureDuration && detector.getPointersCount() == 1) { PointF pointf = detector.getFocalPoint(); LatLng origin = mapboxMap.getProjection().fromScreenLocation(pointf); RectF rectF = new RectF( @@ -1384,8 +1391,6 @@ void onMoveEnd() { } boolean startDragging(@NonNull Feature feature, @NonNull LatLng origin) { - // try{ - //TODO draggable wrong type final boolean draggable = feature.hasNonNullValueForProperty("draggable") ? feature.getBooleanProperty("draggable") : false; if (draggable) { @@ -1394,7 +1399,6 @@ boolean startDragging(@NonNull Feature feature, @NonNull LatLng origin) { dragOrigin = origin; return true; } - // }catch(GeoJsonException e){} return false; } @@ -1416,7 +1420,7 @@ public boolean onMoveBegin(MoveGestureDetector detector) { @Override public boolean onMove(MoveGestureDetector detector, float distanceX, float distanceY) { - return MapboxMapController.this.onMove(detector); + return MapboxMapController.this.onMove(detector); } @Override From d0f8707db75f834bfb827abe69bd88660e85a610 Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Fri, 14 Jan 2022 14:59:40 +0100 Subject: [PATCH 23/26] improved code for detecting drag starts --- .../java/com/mapbox/mapboxgl/MapboxMapController.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java index b90bbe920..9b164f583 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java +++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java @@ -146,7 +146,6 @@ final class MapboxMapController private Map addedFeaturesByLayer; private LatLngBounds bounds = null; - private Long currentMoveGestureDuration = Long.MAX_VALUE; MapboxMapController( int id, @@ -1333,13 +1332,9 @@ public void onCancel() { } boolean onMoveBegin(MoveGestureDetector detector) { - final Long lastMoveDuration = currentMoveGestureDuration; - currentMoveGestureDuration = detector.getGestureDuration(); - // onMoveBegin gets called even during a move - move end is also not called unless this function returns - // true at least once. To avoid redundant queries to firstFeatureOnLayers it is only invoked - // if lastMoveDuration is larger than currentMoveGestureDuration so we know that a new move has started - if (lastMoveDuration > currentMoveGestureDuration && detector.getPointersCount() == 1) { + // true at least once. To avoid redundant queries only check for feature if the previous event was ACTION_DOWN + if (detector.getPreviousEvent().getActionMasked() == MotionEvent.ACTION_DOWN && detector.getPointersCount() == 1) { PointF pointf = detector.getFocalPoint(); LatLng origin = mapboxMap.getProjection().fromScreenLocation(pointf); RectF rectF = new RectF( From 01d4a1410c5ecf11cc84666f4697838c2a4428d1 Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Mon, 17 Jan 2022 11:12:48 +0100 Subject: [PATCH 24/26] code review changes --- .../mapbox/mapboxgl/MapboxMapController.java | 49 +++++++++---------- lib/src/annotation_manager.dart | 12 ++--- 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java index 9b164f583..65c962db3 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java +++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java @@ -212,10 +212,9 @@ public void onMapReady(MapboxMap mapboxMap) { mapView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { - Feature feature = draggedFeature; androidGesturesManager.onTouchEvent(event); - return feature != null; + return draggedFeature != null; } }); } @@ -1353,30 +1352,30 @@ boolean onMoveBegin(MoveGestureDetector detector) { boolean onMove(MoveGestureDetector detector) { - if (draggedFeature != null && detector.getPointersCount() > 1) { - stopDragging(); - return true; - } - if (draggedFeature != null) { - PointF pointf = detector.getFocalPoint(); - LatLng current = mapboxMap.getProjection().fromScreenLocation(pointf); - - final Map arguments = new HashMap<>(9); - arguments.put("id", draggedFeature.id()); - arguments.put("x", pointf.x); - arguments.put("y", pointf.y); - - arguments.put("originLng", dragOrigin.getLongitude()); - arguments.put("originLat", dragOrigin.getLatitude()); - arguments.put("currentLng", current.getLongitude()); - arguments.put("currentLat", current.getLatitude()); - arguments.put("deltaLng", current.getLongitude() - dragPrevious.getLongitude()); - arguments.put("deltaLat", current.getLatitude() - dragPrevious.getLatitude()); - - methodChannel.invokeMethod("feature#onDrag", arguments); - dragPrevious = current; - return false; + if (detector.getPointersCount() > 1) { + stopDragging(); + return true; + } + + PointF pointf = detector.getFocalPoint(); + LatLng current = mapboxMap.getProjection().fromScreenLocation(pointf); + + final Map arguments = new HashMap<>(9); + arguments.put("id", draggedFeature.id()); + arguments.put("x", pointf.x); + arguments.put("y", pointf.y); + + arguments.put("originLng", dragOrigin.getLongitude()); + arguments.put("originLat", dragOrigin.getLatitude()); + arguments.put("currentLng", current.getLongitude()); + arguments.put("currentLat", current.getLatitude()); + arguments.put("deltaLng", current.getLongitude() - dragPrevious.getLongitude()); + arguments.put("deltaLat", current.getLatitude() - dragPrevious.getLatitude()); + + methodChannel.invokeMethod("feature#onDrag", arguments); + dragPrevious = current; + return false; } return true; } diff --git a/lib/src/annotation_manager.dart b/lib/src/annotation_manager.dart index f2fda633b..446ee4b76 100644 --- a/lib/src/annotation_manager.dart +++ b/lib/src/annotation_manager.dart @@ -141,19 +141,19 @@ abstract class AnnotationManager { /// Set an existing anntotation to the map. Use this to do a fast update for a /// single annotation - Future set(T annoation) async { - assert(_idToAnnotation.containsKey(annoation.id), + Future set(T anntotation) async { + assert(_idToAnnotation.containsKey(anntotation.id), "you can only set existing annotations"); - _idToAnnotation[annoation.id] = annoation; - final oldLayerIndex = _idToLayerIndex[annoation.id]; - final layerIndex = selectLayer != null ? selectLayer!(annoation) : 0; + _idToAnnotation[anntotation.id] = anntotation; + final oldLayerIndex = _idToLayerIndex[anntotation.id]; + final layerIndex = selectLayer != null ? selectLayer!(anntotation) : 0; if (oldLayerIndex != layerIndex) { // if the annotation has to be moved to another layer/source we have to // set all await _setAll(); } else { await controller.setGeoJsonFeature( - _makeLayerId(layerIndex), annoation.toGeoJson()); + _makeLayerId(layerIndex), anntotation.toGeoJson()); } } } From 1967050ab8cea9a7f2e259aaf75de24858d728e6 Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Mon, 17 Jan 2022 16:32:55 +0100 Subject: [PATCH 25/26] post rebase fixes --- .../mapbox/mapboxgl/MapboxMapController.java | 3 + ios/Classes/MapboxMapController.swift | 27 ++++-- lib/mapbox_gl.dart | 1 - lib/src/controller.dart | 91 +++++++++++++------ mapbox_gl_web/lib/mapbox_gl_web.dart | 1 + 5 files changed, 87 insertions(+), 36 deletions(-) diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java index 65c962db3..eac17f712 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java +++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java @@ -734,6 +734,7 @@ public void onError(@NonNull String message) { final String sourceId = call.argument("sourceId"); final String layerId = call.argument("layerId"); final String belowLayerId = call.argument("belowLayerId"); + final String sourceLayer = call.argument("sourceLayer"); final boolean enableInteraction = call.argument("enableInteraction"); final PropertyValue[] properties = LayerPropertyConverter.interpretSymbolLayerProperties(call.argument("properties")); addSymbolLayer(layerId, sourceId, belowLayerId, sourceLayer, properties, enableInteraction, null); @@ -744,6 +745,7 @@ public void onError(@NonNull String message) { final String sourceId = call.argument("sourceId"); final String layerId = call.argument("layerId"); final String belowLayerId = call.argument("belowLayerId"); + final String sourceLayer = call.argument("sourceLayer"); final boolean enableInteraction = call.argument("enableInteraction"); final PropertyValue[] properties = LayerPropertyConverter.interpretLineLayerProperties(call.argument("properties")); addLineLayer(layerId, sourceId, belowLayerId, sourceLayer, properties, enableInteraction, null); @@ -754,6 +756,7 @@ public void onError(@NonNull String message) { final String sourceId = call.argument("sourceId"); final String layerId = call.argument("layerId"); final String belowLayerId = call.argument("belowLayerId"); + final String sourceLayer = call.argument("sourceLayer"); final boolean enableInteraction = call.argument("enableInteraction"); final PropertyValue[] properties = LayerPropertyConverter.interpretFillLayerProperties(call.argument("properties")); addFillLayer(layerId, sourceId, belowLayerId, sourceLayer, properties, enableInteraction, null); diff --git a/ios/Classes/MapboxMapController.swift b/ios/Classes/MapboxMapController.swift index ace2ef3c6..127d24d0b 100644 --- a/ios/Classes/MapboxMapController.swift +++ b/ios/Classes/MapboxMapController.swift @@ -328,12 +328,13 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma mapView.setCamera(camera, animated: true) } result(nil) - + case "symbolLayer#add": guard let arguments = methodCall.arguments as? [String: Any] else { return } guard let sourceId = arguments["sourceId"] as? String else { return } guard let layerId = arguments["layerId"] as? String else { return } guard let properties = arguments["properties"] as? [String: String] else { return } + guard let enableInteraction = arguments["enableInteraction"] as? Bool else { return } let belowLayerId = arguments["belowLayerId"] as? String let sourceLayer = arguments["sourceLayer"] as? String addSymbolLayer( @@ -341,6 +342,7 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma layerId: layerId, belowLayerId: belowLayerId, sourceLayerIdentifier: sourceLayer, + enableInteraction: enableInteraction, properties: properties ) result(nil) @@ -350,6 +352,7 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma guard let sourceId = arguments["sourceId"] as? String else { return } guard let layerId = arguments["layerId"] as? String else { return } guard let properties = arguments["properties"] as? [String: String] else { return } + guard let enableInteraction = arguments["enableInteraction"] as? Bool else { return } let belowLayerId = arguments["belowLayerId"] as? String let sourceLayer = arguments["sourceLayer"] as? String addLineLayer( @@ -357,6 +360,7 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma layerId: layerId, belowLayerId: belowLayerId, sourceLayerIdentifier: sourceLayer, + enableInteraction: enableInteraction, properties: properties ) result(nil) @@ -366,6 +370,7 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma guard let sourceId = arguments["sourceId"] as? String else { return } guard let layerId = arguments["layerId"] as? String else { return } guard let properties = arguments["properties"] as? [String: String] else { return } + guard let enableInteraction = arguments["enableInteraction"] as? Bool else { return } let belowLayerId = arguments["belowLayerId"] as? String let sourceLayer = arguments["sourceLayer"] as? String addFillLayer( @@ -373,6 +378,7 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma layerId: layerId, belowLayerId: belowLayerId, sourceLayerIdentifier: sourceLayer, + enableInteraction: enableInteraction, properties: properties ) result(nil) @@ -382,6 +388,7 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma guard let sourceId = arguments["sourceId"] as? String else { return } guard let layerId = arguments["layerId"] as? String else { return } guard let properties = arguments["properties"] as? [String: String] else { return } + guard let enableInteraction = arguments["enableInteraction"] as? Bool else { return } let belowLayerId = arguments["belowLayerId"] as? String let sourceLayer = arguments["sourceLayer"] as? String addCircleLayer( @@ -389,6 +396,7 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma layerId: layerId, belowLayerId: belowLayerId, sourceLayerIdentifier: sourceLayer, + enableInteraction: enableInteraction, properties: properties ) result(nil) @@ -421,7 +429,6 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma ) result(nil) - case "style#addImage": guard let arguments = methodCall.arguments as? [String: Any] else { return } guard let name = arguments["name"] as? String else { return } @@ -559,10 +566,12 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma guard let enableInteraction = arguments["enableInteraction"] as? Bool else { return } guard let properties = arguments["properties"] as? [String: String] else { return } let belowLayerId = arguments["belowLayerId"] as? String + let sourceLayer = arguments["sourceLayer"] as? String addSymbolLayer( sourceId: sourceId, layerId: layerId, belowLayerId: belowLayerId, + sourceLayerIdentifier: sourceLayer, enableInteraction: enableInteraction, properties: properties ) @@ -575,10 +584,12 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma guard let enableInteraction = arguments["enableInteraction"] as? Bool else { return } guard let properties = arguments["properties"] as? [String: String] else { return } let belowLayerId = arguments["belowLayerId"] as? String + let sourceLayer = arguments["sourceLayer"] as? String addLineLayer( sourceId: sourceId, layerId: layerId, belowLayerId: belowLayerId, + sourceLayerIdentifier: sourceLayer, enableInteraction: enableInteraction, properties: properties ) @@ -591,10 +602,12 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma guard let enableInteraction = arguments["enableInteraction"] as? Bool else { return } guard let properties = arguments["properties"] as? [String: String] else { return } let belowLayerId = arguments["belowLayerId"] as? String + let sourceLayer = arguments["sourceLayer"] as? String addFillLayer( sourceId: sourceId, layerId: layerId, belowLayerId: belowLayerId, + sourceLayerIdentifier: sourceLayer, enableInteraction: enableInteraction, properties: properties ) @@ -607,10 +620,12 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma guard let enableInteraction = arguments["enableInteraction"] as? Bool else { return } guard let properties = arguments["properties"] as? [String: String] else { return } let belowLayerId = arguments["belowLayerId"] as? String + let sourceLayer = arguments["sourceLayer"] as? String addCircleLayer( sourceId: sourceId, layerId: layerId, belowLayerId: belowLayerId, + sourceLayerIdentifier: sourceLayer, enableInteraction: enableInteraction, properties: properties ) @@ -1010,7 +1025,9 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma } else { style.addLayer(layer) } - featureLayerIdentifiers.insert(layerId) + if enableInteraction { + interactiveFeatureLayerIds.insert(layerId) + } } } } @@ -1033,9 +1050,6 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma } else { style.addLayer(layer) } - if enableInteraction { - interactiveFeatureLayerIds.insert(layerId) - } } } } @@ -1058,7 +1072,6 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma } else { style.addLayer(layer) } - featureLayerIdentifiers.insert(layerId) } } } diff --git a/lib/mapbox_gl.dart b/lib/mapbox_gl.dart index 5d23bb1ac..0c836a3e5 100644 --- a/lib/mapbox_gl.dart +++ b/lib/mapbox_gl.dart @@ -13,7 +13,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:collection/collection.dart'; import 'package:mapbox_gl_platform_interface/mapbox_gl_platform_interface.dart'; export 'package:mapbox_gl_platform_interface/mapbox_gl_platform_interface.dart' diff --git a/lib/src/controller.dart b/lib/src/controller.dart index 1a47bf093..39e0eecea 100644 --- a/lib/src/controller.dart +++ b/lib/src/controller.dart @@ -335,10 +335,15 @@ class MapboxMapController extends ChangeNotifier { /// Add a symbol layer to the map with the given properties /// + /// Consider using [addLayer] for an unified layer api. + /// /// The returned [Future] completes after the change has been made on the /// platform side. /// - /// Note: [belowLayerId] is currently ignored on the web + /// Setting [belowLayerId] adds the new layer below the given id. + /// If [enableInteraction] is set the layer is considered for touch or drag + /// events. [sourceLayer] is used to selected a specific source layer from + /// Vector source Future addSymbolLayer( String sourceId, String layerId, SymbolLayerProperties properties, {String? belowLayerId, @@ -356,10 +361,15 @@ class MapboxMapController extends ChangeNotifier { /// Add a line layer to the map with the given properties /// + /// Consider using [addLayer] for an unified layer api. + /// /// The returned [Future] completes after the change has been made on the /// platform side. /// - /// Note: [belowLayerId] is currently ignored on the web + /// Setting [belowLayerId] adds the new layer below the given id. + /// If [enableInteraction] is set the layer is considered for touch or drag + /// events. [sourceLayer] is used to selected a specific source layer from + /// Vector source Future addLineLayer( String sourceId, String layerId, LineLayerProperties properties, {String? belowLayerId, @@ -377,10 +387,15 @@ class MapboxMapController extends ChangeNotifier { /// Add a fill layer to the map with the given properties /// + /// Consider using [addLayer] for an unified layer api. + /// /// The returned [Future] completes after the change has been made on the /// platform side. /// - /// Note: [belowLayerId] is currently ignored on the web + /// Setting [belowLayerId] adds the new layer below the given id. + /// If [enableInteraction] is set the layer is considered for touch or drag + /// events. [sourceLayer] is used to selected a specific source layer from + /// Vector source Future addFillLayer( String sourceId, String layerId, FillLayerProperties properties, {String? belowLayerId, @@ -398,10 +413,15 @@ class MapboxMapController extends ChangeNotifier { /// Add a circle layer to the map with the given properties /// + /// Consider using [addLayer] for an unified layer api. + /// /// The returned [Future] completes after the change has been made on the /// platform side. /// - /// Note: [belowLayerId] is currently ignored on the web + /// Setting [belowLayerId] adds the new layer below the given id. + /// If [enableInteraction] is set the layer is considered for touch or drag + /// events. [sourceLayer] is used to selected a specific source layer from + /// Vector source Future addCircleLayer( String sourceId, String layerId, CircleLayerProperties properties, {String? belowLayerId, @@ -417,12 +437,16 @@ class MapboxMapController extends ChangeNotifier { ); } - /// Add a circle layer to the map with the given properties + /// Add a raster layer to the map with the given properties + /// + /// Consider using [addLayer] for an unified layer api. /// /// The returned [Future] completes after the change has been made on the /// platform side. /// - /// Note: [belowLayerId] is currently ignored on the web + /// Setting [belowLayerId] adds the new layer below the given id. + /// [sourceLayer] is used to selected a specific source layer from + /// Raster source Future addRasterLayer( String sourceId, String layerId, RasterLayerProperties properties, {String? belowLayerId, String? sourceLayer}) async { @@ -435,6 +459,16 @@ class MapboxMapController extends ChangeNotifier { ); } + /// Add a hillshade layer to the map with the given properties + /// + /// Consider using [addLayer] for an unified layer api. + /// + /// The returned [Future] completes after the change has been made on the + /// platform side. + /// + /// Setting [belowLayerId] adds the new layer below the given id. + /// [sourceLayer] is used to selected a specific source layer from + /// Raster source Future addHillshadeLayer( String sourceId, String layerId, HillshadeLayerProperties properties, {String? belowLayerId, String? sourceLayer}) async { @@ -447,24 +481,6 @@ class MapboxMapController extends ChangeNotifier { ); } - Future addLayer( - String sourceId, String layerId, LayerProperties properties, - {String? belowLayerId, bool enableInteraction = true}) async { - if (properties is FillLayerProperties) { - addFillLayer(sourceId, layerId, properties, - enableInteraction: enableInteraction); - } else if (properties is LineLayerProperties) { - addLineLayer(sourceId, layerId, properties, - enableInteraction: enableInteraction); - } else if (properties is SymbolLayerProperties) { - addSymbolLayer(sourceId, layerId, properties, - enableInteraction: enableInteraction); - } else if (properties is CircleLayerProperties) { - addCircleLayer(sourceId, layerId, properties, - enableInteraction: enableInteraction); - } - } - /// Updates user location tracking mode. /// /// The returned [Future] completes after the change has been made on the @@ -1057,6 +1073,17 @@ class MapboxMapController extends ChangeNotifier { return _mapboxGlPlatform.addSource(sourceid, properties); } + /// Add a layer to the map with the given properties + /// + /// The returned [Future] completes after the change has been made on the + /// platform side. + /// + /// Setting [belowLayerId] adds the new layer below the given id. + /// If [enableInteraction] is set the layer is considered for touch or drag + /// events this has no effect for [RasterLayerProperties] and + /// [HillshadeLayerProperties]. + /// [sourceLayer] is used to selected a specific source layer from Vector + /// source. Future addLayer( String sourceId, String layerId, LayerProperties properties, {String? belowLayerId, @@ -1064,16 +1091,24 @@ class MapboxMapController extends ChangeNotifier { String? sourceLayer}) async { if (properties is FillLayerProperties) { addFillLayer(sourceId, layerId, properties, - belowLayerId: belowLayerId, sourceLayer: sourceLayer); + belowLayerId: belowLayerId, + enableInteraction: enableInteraction, + sourceLayer: sourceLayer); } else if (properties is LineLayerProperties) { addLineLayer(sourceId, layerId, properties, - belowLayerId: belowLayerId, sourceLayer: sourceLayer); + belowLayerId: belowLayerId, + enableInteraction: enableInteraction, + sourceLayer: sourceLayer); } else if (properties is SymbolLayerProperties) { addSymbolLayer(sourceId, layerId, properties, - belowLayerId: belowLayerId, sourceLayer: sourceLayer); + belowLayerId: belowLayerId, + enableInteraction: enableInteraction, + sourceLayer: sourceLayer); } else if (properties is CircleLayerProperties) { addCircleLayer(sourceId, layerId, properties, - belowLayerId: belowLayerId, sourceLayer: sourceLayer); + belowLayerId: belowLayerId, + enableInteraction: enableInteraction, + sourceLayer: sourceLayer); } else if (properties is RasterLayerProperties) { addRasterLayer(sourceId, layerId, properties, belowLayerId: belowLayerId, sourceLayer: sourceLayer); diff --git a/mapbox_gl_web/lib/mapbox_gl_web.dart b/mapbox_gl_web/lib/mapbox_gl_web.dart index 14937246e..1a6702d54 100644 --- a/mapbox_gl_web/lib/mapbox_gl_web.dart +++ b/mapbox_gl_web/lib/mapbox_gl_web.dart @@ -4,6 +4,7 @@ import 'dart:async'; // FIXED HERE: https://github.com/dart-lang/linter/pull/1985 // ignore_for_file: avoid_web_libraries_in_flutter import 'dart:html'; +// ignore: unused_import import 'dart:js'; import 'dart:math'; import 'dart:typed_data'; From d02764ca9ce3fa588171af85d44e3dc0461ce8b0 Mon Sep 17 00:00:00 2001 From: Felix Horvat Date: Tue, 18 Jan 2022 10:20:58 +0100 Subject: [PATCH 26/26] fix build issue with location --- example/android/app/build.gradle | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index cfe29c302..364c91ab1 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -69,4 +69,12 @@ dependencies { testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.1.0-alpha4' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4' + constraints { + implementation('com.google.android.gms:play-services-location') { + version { + strictly "16.0.0" + } + because 'location: 4.2.3 does not specify version play-services-location' + } + } }