diff --git a/example/lib/pages/polygon.dart b/example/lib/pages/polygon.dart index 369b2eb18..0ef3f8e9c 100644 --- a/example/lib/pages/polygon.dart +++ b/example/lib/pages/polygon.dart @@ -437,6 +437,40 @@ class _PolygonPageState extends State { ), ], ), + IgnorePointer( + child: ValueListenableBuilder( + valueListenable: _hitNotifier, + builder: (context, value, _) => MarkerLayer( + rotate: true, + markers: [ + if (value != null) + Marker( + height: 22, + width: 24, + alignment: Alignment.topCenter, + point: value.coordinate, + child: DecoratedBox( + decoration: BoxDecoration( + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + blurRadius: 15, + spreadRadius: 5, + color: Colors.black.withAlpha(255 ~/ 3), + offset: const Offset(0, 11), + ), + ], + ), + child: const Icon( + Icons.location_on, + color: Colors.green, + ), + ), + ), + ], + ), + ), + ), ], ), Positioned( diff --git a/lib/src/layer/polygon_layer/painter.dart b/lib/src/layer/polygon_layer/painter.dart index 4d1c7662c..10d6a5f7b 100644 --- a/lib/src/layer/polygon_layer/painter.dart +++ b/lib/src/layer/polygon_layer/painter.dart @@ -62,10 +62,7 @@ class _PolygonPainter extends CustomPainter required this.invertedFill, required this.hitNotifier, }) : bounds = camera.visibleBounds { - _helper = OffsetHelper( - camera: camera, - origin: origin, - ); + _helper = OffsetHelper(camera: camera); } late final OffsetHelper _helper; @@ -255,7 +252,7 @@ class _PolygonPainter extends CustomPainter polygon.labelPosition, shift: shift, ), - bounds: _getBounds(origin, polygon), + bounds: _getBounds(camera.pixelOrigin, polygon), textPainter: polygon.textPainter!, rotationRad: camera.rotationRad, rotate: polygon.rotateLabel, diff --git a/lib/src/layer/polyline_layer/painter.dart b/lib/src/layer/polyline_layer/painter.dart index 2669c2c46..4656f83a4 100644 --- a/lib/src/layer/polyline_layer/painter.dart +++ b/lib/src/layer/polyline_layer/painter.dart @@ -21,10 +21,7 @@ class _PolylinePainter extends CustomPainter required this.camera, required this.hitNotifier, }) { - _helper = OffsetHelper( - camera: camera, - origin: origin, - ); + _helper = OffsetHelper(camera: camera); } late final OffsetHelper _helper; diff --git a/lib/src/layer/shared/feature_layer_utils.dart b/lib/src/layer/shared/feature_layer_utils.dart index 513aaec70..0513b544c 100644 --- a/lib/src/layer/shared/feature_layer_utils.dart +++ b/lib/src/layer/shared/feature_layer_utils.dart @@ -96,10 +96,6 @@ mixin FeatureLayerUtils on CustomPainter { } } - /// Returns the origin of the camera. - Offset get origin => - camera.projectAtZoom(camera.center) - camera.size.center(Offset.zero); - /// Returns the world size in pixels. /// /// Equivalent to [MapCamera.getWorldWidthAtZoom]. diff --git a/lib/src/layer/shared/layer_interactivity/internal_hit_detectable.dart b/lib/src/layer/shared/layer_interactivity/internal_hit_detectable.dart index 85e2e89c9..996f72d89 100644 --- a/lib/src/layer/shared/layer_interactivity/internal_hit_detectable.dart +++ b/lib/src/layer/shared/layer_interactivity/internal_hit_detectable.dart @@ -1,6 +1,5 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_map/flutter_map.dart'; -import 'package:flutter_map/src/layer/shared/feature_layer_utils.dart'; import 'package:latlong2/latlong.dart'; import 'package:meta/meta.dart'; @@ -42,8 +41,7 @@ mixin HitDetectablePainter> /// Avoid performing calculations that are not dependent on [element]. Instead, /// override [hitTest], store the necessary calculation results in /// (`late` non-`null`able) members, and call `super.hitTest(position)` at the - /// end. To calculate the camera origin in this way, instead mix in and use - /// [FeatureLayerUtils.origin]. + /// end. The camera origin may be retrieved with [MapCamera.pixelOrigin]. /// /// Should return whether an element has been hit. bool elementHitTest( @@ -60,13 +58,12 @@ mixin HitDetectablePainter> _hits.clear(); bool hasHit = false; - final point = position; - final coordinate = camera.screenOffsetToLatLng(point); + final coordinate = camera.unprojectAtZoom(camera.pixelOrigin + position); for (int i = elements.length - 1; i >= 0; i--) { final element = elements.elementAt(i); if (hasHit && element.hitValue == null) continue; - if (elementHitTest(element, point: point, coordinate: coordinate)) { + if (elementHitTest(element, point: position, coordinate: coordinate)) { if (element.hitValue != null) _hits.add(element.hitValue!); hasHit = true; } @@ -80,7 +77,7 @@ mixin HitDetectablePainter> hitNotifier?.value = LayerHitResult( hitValues: _hits, coordinate: coordinate, - point: point, + point: position, ); return true; } diff --git a/lib/src/map/camera/camera.dart b/lib/src/map/camera/camera.dart index 4f54cc36d..ab9d3a4bf 100644 --- a/lib/src/map/camera/camera.dart +++ b/lib/src/map/camera/camera.dart @@ -88,6 +88,28 @@ class MapCamera { /// The offset of the top-left corner of the bounding rectangle of this /// camera. This will not equal the offset of the top-left visible pixel when /// the map is rotated. + /* (jaffaketchup) This is used for painters & hit testing extensively. We want + to convert [position], which is in the canvas' coordinate space to a + [coordinate]. See `screenOffsetToLatLng` - it uses `nonRotatedSize` then + does more rotations after. We don't want to do this. So we copy the + implementation, and replace/remove the necessary parts, resulting in the + code below. + + final pointCenterDistance = camera.size.center(Offset.zero) - position; + final a = camera.crs.latLngToOffset(camera.center, camera.zoom); + final coordinate = camera.crs.offsetToLatLng( + a - pointCenterDistance, + camera.zoom, + ); + + `camera.crs.latLngToOffset` is longhand for `projectAtZoom`. So we have + `a - (b - c)`, where `c` is [position]. This is equivalent to `(a - b) + c`. + `(a - b)` is this. + + This was provided in [FeatureLayerUtils.origin] for a few versions. It has + been removed, because this exists, so I'm not sure why it needed to be + duplicated. See [HitDetectablePainter.hitTest] for an easy usage example. + */ Offset get pixelOrigin => _pixelOrigin ??= projectAtZoom(center, zoom) - size.center(Offset.zero); diff --git a/lib/src/misc/offsets.dart b/lib/src/misc/offsets.dart index 51337f43d..7f679ec6d 100644 --- a/lib/src/misc/offsets.dart +++ b/lib/src/misc/offsets.dart @@ -9,13 +9,12 @@ import 'package:meta/meta.dart'; class OffsetHelper { OffsetHelper({ required this.camera, - required this.origin, - }) : _replicatesWorldLongitude = camera.crs.replicatesWorldLongitude; + }) : _replicatesWorldLongitude = camera.crs.replicatesWorldLongitude, + _origin = camera.pixelOrigin; final MapCamera camera; - final Offset origin; - + final Offset _origin; final bool _replicatesWorldLongitude; /// Calculate the [Offset] for the [LatLng] point. @@ -26,18 +25,18 @@ class OffsetHelper { final crs = camera.crs; final zoomScale = crs.scale(camera.zoom); final (x, y) = crs.latLngToXY(point, zoomScale); - return Offset(x - origin.dx + shift, y - origin.dy); + return Offset(x - _origin.dx + shift, y - _origin.dy); } -// TODO not sure if still relevant + // TODO not sure if still relevant /// Calculate the [Offset]s for the list of [LatLng] points. List getOffsets(List points) { // Critically create as little garbage as possible. This is called on every frame. final crs = camera.crs; final zoomScale = crs.scale(camera.zoom); - final ox = -origin.dx; - final oy = -origin.dy; + final ox = -_origin.dx; + final oy = -_origin.dy; final len = points.length; // Optimization: monomorphize the Epsg3857-case to avoid the virtual function overhead. @@ -74,8 +73,8 @@ class OffsetHelper { ? points : points.followedBy(holePoints.expand((e) => e)); - final ox = -origin.dx; - final oy = -origin.dy; + final ox = -_origin.dx; + final oy = -_origin.dy; final len = realPoints.length; /// Returns additional world width in order to have visible points.