Skip to content

Commit ec217c3

Browse files
authored
fix: calculate LayerHitResult.coordinate correctly (fleaflet#2093)
1 parent ea3b412 commit ec217c3

File tree

7 files changed

+74
-30
lines changed

7 files changed

+74
-30
lines changed

example/lib/pages/polygon.dart

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,42 @@ class _PolygonPageState extends State<PolygonPage> {
437437
),
438438
],
439439
),
440+
IgnorePointer(
441+
// Ignore the marker so it doesn't capture the pointer
442+
// (as the marker is over the pointer)
443+
child: ValueListenableBuilder(
444+
valueListenable: _hitNotifier,
445+
builder: (context, value, _) => MarkerLayer(
446+
rotate: true,
447+
markers: [
448+
if (value != null)
449+
Marker(
450+
height: 22,
451+
width: 24,
452+
alignment: Alignment.topCenter,
453+
point: value.coordinate,
454+
child: DecoratedBox(
455+
decoration: BoxDecoration(
456+
shape: BoxShape.circle,
457+
boxShadow: [
458+
BoxShadow(
459+
blurRadius: 15,
460+
spreadRadius: 5,
461+
color: Colors.black.withAlpha(255 ~/ 3),
462+
offset: const Offset(0, 11),
463+
),
464+
],
465+
),
466+
child: const Icon(
467+
Icons.location_on,
468+
color: Colors.green,
469+
),
470+
),
471+
),
472+
],
473+
),
474+
),
475+
),
440476
],
441477
),
442478
Positioned(

lib/src/layer/polygon_layer/painter.dart

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,7 @@ class _PolygonPainter<R extends Object> extends CustomPainter
6262
required this.invertedFill,
6363
required this.hitNotifier,
6464
}) : bounds = camera.visibleBounds {
65-
_helper = OffsetHelper(
66-
camera: camera,
67-
origin: origin,
68-
);
65+
_helper = OffsetHelper(camera: camera);
6966
}
7067

7168
late final OffsetHelper _helper;
@@ -255,7 +252,7 @@ class _PolygonPainter<R extends Object> extends CustomPainter
255252
polygon.labelPosition,
256253
shift: shift,
257254
),
258-
bounds: _getBounds(origin, polygon),
255+
bounds: _getBounds(camera.pixelOrigin, polygon),
259256
textPainter: polygon.textPainter!,
260257
rotationRad: camera.rotationRad,
261258
rotate: polygon.rotateLabel,

lib/src/layer/polyline_layer/painter.dart

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,7 @@ class _PolylinePainter<R extends Object> extends CustomPainter
2121
required this.camera,
2222
required this.hitNotifier,
2323
}) {
24-
_helper = OffsetHelper(
25-
camera: camera,
26-
origin: origin,
27-
);
24+
_helper = OffsetHelper(camera: camera);
2825
}
2926

3027
late final OffsetHelper _helper;

lib/src/layer/shared/feature_layer_utils.dart

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,6 @@ mixin FeatureLayerUtils on CustomPainter {
102102
}
103103
}
104104

105-
/// Returns the origin of the camera.
106-
Offset get origin =>
107-
camera.projectAtZoom(camera.center) - camera.size.center(Offset.zero);
108-
109105
/// Returns the world size in pixels.
110106
///
111107
/// Equivalent to [MapCamera.getWorldWidthAtZoom].

lib/src/layer/shared/layer_interactivity/internal_hit_detectable.dart

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import 'package:flutter/widgets.dart';
22
import 'package:flutter_map/flutter_map.dart';
3-
import 'package:flutter_map/src/layer/shared/feature_layer_utils.dart';
43
import 'package:latlong2/latlong.dart';
54
import 'package:meta/meta.dart';
65

@@ -42,8 +41,7 @@ mixin HitDetectablePainter<R extends Object, E extends HitDetectableElement<R>>
4241
/// Avoid performing calculations that are not dependent on [element]. Instead,
4342
/// override [hitTest], store the necessary calculation results in
4443
/// (`late` non-`null`able) members, and call `super.hitTest(position)` at the
45-
/// end. To calculate the camera origin in this way, instead mix in and use
46-
/// [FeatureLayerUtils.origin].
44+
/// end. The camera origin may be retrieved with [MapCamera.pixelOrigin].
4745
///
4846
/// Should return whether an element has been hit.
4947
bool elementHitTest(
@@ -60,13 +58,12 @@ mixin HitDetectablePainter<R extends Object, E extends HitDetectableElement<R>>
6058
_hits.clear();
6159
bool hasHit = false;
6260

63-
final point = position;
64-
final coordinate = camera.screenOffsetToLatLng(point);
61+
final coordinate = camera.unprojectAtZoom(camera.pixelOrigin + position);
6562

6663
for (int i = elements.length - 1; i >= 0; i--) {
6764
final element = elements.elementAt(i);
6865
if (hasHit && element.hitValue == null) continue;
69-
if (elementHitTest(element, point: point, coordinate: coordinate)) {
66+
if (elementHitTest(element, point: position, coordinate: coordinate)) {
7067
if (element.hitValue != null) _hits.add(element.hitValue!);
7168
hasHit = true;
7269
}
@@ -80,7 +77,7 @@ mixin HitDetectablePainter<R extends Object, E extends HitDetectableElement<R>>
8077
hitNotifier?.value = LayerHitResult(
8178
hitValues: _hits,
8279
coordinate: coordinate,
83-
point: point,
80+
point: position,
8481
);
8582
return true;
8683
}

lib/src/map/camera/camera.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,28 @@ class MapCamera {
8888
/// The offset of the top-left corner of the bounding rectangle of this
8989
/// camera. This will not equal the offset of the top-left visible pixel when
9090
/// the map is rotated.
91+
/* (jaffaketchup) This is used for painters & hit testing extensively. We want
92+
to convert [position], which is in the canvas' coordinate space to a
93+
[coordinate]. See `screenOffsetToLatLng` - it uses `nonRotatedSize` then
94+
does more rotations after. We don't want to do this. So we copy the
95+
implementation, and replace/remove the necessary parts, resulting in the
96+
code below.
97+
98+
final pointCenterDistance = camera.size.center(Offset.zero) - position;
99+
final a = camera.crs.latLngToOffset(camera.center, camera.zoom);
100+
final coordinate = camera.crs.offsetToLatLng(
101+
a - pointCenterDistance,
102+
camera.zoom,
103+
);
104+
105+
`camera.crs.latLngToOffset` is longhand for `projectAtZoom`. So we have
106+
`a - (b - c)`, where `c` is [position]. This is equivalent to `(a - b) + c`.
107+
`(a - b)` is this.
108+
109+
This was provided in [FeatureLayerUtils.origin] for a few versions. It has
110+
been removed, because this exists, so I'm not sure why it needed to be
111+
duplicated. See [HitDetectablePainter.hitTest] for an easy usage example.
112+
*/
91113
Offset get pixelOrigin =>
92114
_pixelOrigin ??= projectAtZoom(center, zoom) - size.center(Offset.zero);
93115

lib/src/misc/offsets.dart

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,12 @@ import 'package:meta/meta.dart';
99
class OffsetHelper {
1010
OffsetHelper({
1111
required this.camera,
12-
required this.origin,
13-
}) : _replicatesWorldLongitude = camera.crs.replicatesWorldLongitude;
12+
}) : _replicatesWorldLongitude = camera.crs.replicatesWorldLongitude,
13+
_origin = camera.pixelOrigin;
1414

1515
final MapCamera camera;
1616

17-
final Offset origin;
18-
17+
final Offset _origin;
1918
final bool _replicatesWorldLongitude;
2019

2120
/// Calculate the [Offset] for the [LatLng] point.
@@ -26,18 +25,18 @@ class OffsetHelper {
2625
final crs = camera.crs;
2726
final zoomScale = crs.scale(camera.zoom);
2827
final (x, y) = crs.latLngToXY(point, zoomScale);
29-
return Offset(x - origin.dx + shift, y - origin.dy);
28+
return Offset(x - _origin.dx + shift, y - _origin.dy);
3029
}
3130

32-
// TODO not sure if still relevant
31+
// TODO not sure if still relevant
3332
/// Calculate the [Offset]s for the list of [LatLng] points.
3433
List<Offset> getOffsets(List<LatLng> points) {
3534
// Critically create as little garbage as possible. This is called on every frame.
3635
final crs = camera.crs;
3736
final zoomScale = crs.scale(camera.zoom);
3837

39-
final ox = -origin.dx;
40-
final oy = -origin.dy;
38+
final ox = -_origin.dx;
39+
final oy = -_origin.dy;
4140
final len = points.length;
4241

4342
// Optimization: monomorphize the Epsg3857-case to avoid the virtual function overhead.
@@ -74,8 +73,8 @@ class OffsetHelper {
7473
? points
7574
: points.followedBy(holePoints.expand((e) => e));
7675

77-
final ox = -origin.dx;
78-
final oy = -origin.dy;
76+
final ox = -_origin.dx;
77+
final oy = -_origin.dy;
7978
final len = realPoints.length;
8079

8180
/// Returns additional world width in order to have visible points.

0 commit comments

Comments
 (0)