fleaflet / flutter_map

A versatile mapping package for Flutter. Simple and easy to learn, yet completely customizable and configurable, it's the best choice for mapping in your Flutter app.
https://pub.dev/packages/flutter_map
BSD 3-Clause "New" or "Revised" License
2.75k stars 860 forks source link

[BUG] Markers without symmetrical anchors disappear before they are out of bounds #918

Closed aytunch closed 2 years ago

aytunch commented 3 years ago

I believe the fix below handles the markers which have anchors in the center or edges.

https://github.com/fleaflet/flutter_map/pull/313

I have printed the marker width and height values and they are all as they are supposed to be. If I increase the marker width artificially then the disappearing stops but the anchors are getting corrupted of course. So I think it might be a bug in the package. I might be wrong though.

https://user-images.githubusercontent.com/6442915/120219586-1e7ceb80-c244-11eb-92ad-954b0f8ebb60.mov

aytunch commented 3 years ago

@lpongetti sorry to bother you but do you think this might be a bug? Or am I doing something wrong?

rorystephenson commented 3 years ago

@aytunch can you provide a minimal code example?

github-actions[bot] commented 3 years ago

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

github-actions[bot] commented 3 years ago

This issue was closed because it has been stalled for 5 days with no activity.

aytunch commented 2 years ago

@JaffaKetchup @ibrierley Hi:) I am still having this issue with anchors not in the horizontal middle. Have you encountered something similar? I checked my code multiple times and the anchor position and marker width/height are right. When I zoom in/out the notch below the marker always stays on the center latLng as expected. But For some reason, the markers disappear while leaving the map bounds. I am thinking maybe there is something wrong with the optimization calculations done to not display out of bound markers. It might assume that anchors are always in the middle horizontally.

This calculation in lib/src/layer/marker_layer.dart assumes that the marker is symmetric around pixelPoint which is the center latLng (anchor) As seen in my video, some markers have different space on the left and right side of the anchor points. So when calculating, sw and ne we need to add different widths which are calculated using non existent anchor.right and anchor.bottom (we can deduce them though)

  bool _boundsContainsMarker(Marker marker) {
    var pixelPoint = map.project(marker.point);

    final width = marker.width - marker.anchor.left;
    final height = marker.height - marker.anchor.top;

    var sw = CustomPoint(pixelPoint.x + width, pixelPoint.y - height);
    var ne = CustomPoint(pixelPoint.x - width, pixelPoint.y + height);
    return map.pixelBounds.containsPartialBounds(Bounds(sw, ne));
  }
ibrierley commented 2 years ago

Out of interest, what are your marker and anchor details ?

aytunch commented 2 years ago

@ibrierley This is what I have. Nothing special. Just some arithmetic to calculate the width and anchorX positions according to how many icons will be inside the marker. Now that I tried putting the anchor in width/2, and saw no disappearing, I am very positive the NE and SW calculations are assuming symmetry.

Screen Shot 2022-06-28 at 23 11 47
aytunch commented 2 years ago

@ibrierley You can see what double and triple icon markers look like and please see where the notch (anchor) is. It is unsymmetrical according to the width.

Screen Shot 2022-06-28 at 23 14 35

I am positive that my markers fall in to this condition when they are half way off screen's left edge and they don't get displayed. The for loop continues from the next marker.

if (!_boundsContainsMarker(markerOpt)) {
   continue;
}
JaffaKetchup commented 2 years ago

Hi there,

This is quite interesting, as I've never come across this before - I've always had symmetrical markers.

I would also agree that you are correct about the calculations wrongly assuming symmetry, although I'm struggling to understand the below code fully.

bool _boundsContainsMarker(Marker marker) {
  var pixelPoint = map.project(marker.point);

  final width = marker.width - marker.anchor.left;
  final height = marker.height - marker.anchor.top;

  var sw = CustomPoint(pixelPoint.x + width, pixelPoint.y - height);
  var ne = CustomPoint(pixelPoint.x - width, pixelPoint.y + height);
  return map.pixelBounds.containsPartialBounds(Bounds(sw, ne));
}

It seems like it places pixelPoint halfway along the width/height, which (as you say) seems wrong. I might be completely misunderstanding this code though, so don't take my word for it.

Happy to accept PRs on this, if you think you've found the answer! At the moment I've just come out of exams and my plugin needs some attention, so I'm relatively time limited for coding on this project. Once I'm done, I can take a deeper look if necessary.

ibrierley commented 2 years ago

Could you create an anchor with fixed values as an example that exhibits the problem. I kinda get the problem, but a concrete example is always handy.

aytunch commented 2 years ago

@JaffaKetchup @ibrierley I did some debugging and printed some values to be sure. Here are the results for you to consider; Simulator Screen Shot - iPhone 11 - 2022-06-28 at 23 48 39

THREE ICON flutter: 3_Activity_Marker--------marker.anchor.left: 113.112--------marker.anchor.top: 0.0 flutter: 3_Activity_Marker--------marker.width: 149.112-------------marker.height: 81.0 TWO ICON flutter: 2_Activity_Marker--------marker.anchor.left: 74.556--------marker.anchor.top: 0.0 flutter: 2_Activity_Marker--------marker.width: 110.556------------ marker.height: 81.0

Whit these values what the current code does is, final width = marker.width - marker.anchor.left; //149.112 - 113.112 = 36.0 and it adds 36 to the left and right of the anchor. from left this is OK. But from right, when calculating East, this is short. And the disappearing happens exactly at 36px right of the anchor when I carefully investigated! Same thing is true for top/bottom. However we don't see any hiding from top and bottom because 99% of everyone anchors are at the bottom of the markers. Current code adds marker.height above and below the anchor. So even if the marker is just below the screen, we still render it.

I think a solution along these lines can solve this problem plus it would help with performance. Because before we were giving twice the height for markers which had their anchor points on the bottom.

bool _boundsContainsMarker(Marker marker) {
  var pixelPoint = map.project(marker.point);

  final leftPortion = marker.width - marker.anchor.left;
  final rigthPortion = marker.anchor.left;
  final topPortion = marker.height - marker.anchor.top;
  final bottomPortion = marker.anchor.top;

  var sw = CustomPoint(pixelPoint.x + leftPortion, pixelPoint.y - topPortion);
  var ne = CustomPoint(pixelPoint.x - rigthPortion, pixelPoint.y + bottomPortion);
  return map.pixelBounds.containsPartialBounds(Bounds(sw, ne));
}
ibrierley commented 2 years ago

It's a funny bit of code the original, the labelling, the way round it is etc :D. I feel like I'm missing something with its intention, but it doesn't look right, so you may be correct (I haven't got time now to go through it properly).

Am I being dumb, or are sw/ne the wrong way around as well (normally it doesn't really matter in bounds), sometimes my brain works in different coordinate systems.

aytunch commented 2 years ago

@ibrierley I thought the same way also. I think the coordinate space of a Marker or an Anchor is different than Flutter's.

The (0, 0) is bottom right.

I am amazed that not many people encountered this error. I guess everyone uses anchors in the middle bottom :)

ibrierley commented 2 years ago

Ah yep doh, mixing coordinate systems, as if life isn't tricky enough already :D

aytunch commented 2 years ago

Actually now you made me question the proposed solution as well 😅. I am confused with sw and ne. In the worst case scenario, we will just need to swap topPortion/bottomPortion or +/- and it should work I hope :D One thing is sure, adding two symmetric values for calculating the bounds is not enough. It is just an estimation.

aytunch commented 2 years ago

If anyone is having this issue, you can temporarily use this dependency.


flutter_map:
    git:
      url: https://github.com/aytunch/flutter_map.git
      ref: marker_symmetrical_bug