-
Notifications
You must be signed in to change notification settings - Fork 3.6k
[google_maps_flutter_web] Initial support for custom overlays #3538
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
5e536d5 to
026f4e4
Compare
packages/google_maps_flutter/google_maps_flutter_web/lib/src/overlay.dart
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Original comment by @AsturaPhoenix:
Leaving a comment here because it wasn't obvious to me the second time I looked at it:
This test was removed because it became trivial once using Mockito verification; it essentially tests to make sure that Marker.infoWindow defaults to InfoWindow.noText. On the other hand, the argument could be made to keep it anyway (e.g. to construct the verification with an explicit infoWindow: InfoWindow.noText); let me know if you'd prefer that.
|
FYI @ditman, I think you were the reviewer on the original PR when it was in the plugins repo, and I see that you're the reviewer here as well. I'm also interested in seeing custom tiles work for the web side of google maps flutter, so I asked @AsturaPhoenix if I could move his PR to the new repo and he's cool with that (thanks AP!). That's the background for this one. Let me know if you have any questions and I can try to answer them or solicit AP's help if needed. Thanks! |
f71eaf0 to
b668a6f
Compare
|
Resolved a changelog conflict and rebased on main. |
|
FYI I just moved over my local repo as well, so that's one less hurdle if we do end up needing to collaborate. Thanks for taking over @elitree! |
|
Update from triage: waiting for @ditman to have review bandwidth for maps PRs. |
3435e6f to
1ba5ef7
Compare
|
Rebased on main to resolve conflicts. |
1ba5ef7 to
b7e167e
Compare
|
@ditman Is this still in your review queue? |
|
Absolutely |
ditman
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to tinker with this PR, is there any example that uses the tile overlays feature so I can see it working? Maybe the google_maps_flutter example app?
packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart
Outdated
Show resolved
Hide resolved
packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml
Outdated
Show resolved
Hide resolved
|
PS: There seems some tests breaking, it seems that the Mocks need to be regenerated (and committed): (Mocks can be (re)generated with: |
179bff4 to
0b5faf3
Compare
I updated the mocks today as well, thanks for the reminder. |
|
I did some small changes to the |
|
I had some code ready to remove |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR used to expect that img.hidden was true before load, and false afterwards. Is hidden really required? In my testing I didn't see any difference so I removed the attribute. @AsturaPhoenix / @elitree do you remember why was the attribute added in the first place, is it required?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it was to prevent the image decoding from blocking the main thread, but I can't find a version without hidden + decode so I'm not sure I ever ran a comparison. In any case we still have the bottleneck of populating the image data on the Dart/Flutter side, which has to happen on the main thread on web today.
I do think there's a difference in the case of bad image data though; if Tile.data is not a valid image, I think adding the img straight and setting the src will eventually make it display a browser-dependent broken image whereas hiding and decoding wouldn't, but I don't think that was the primary motivation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it can be added back if it becomes a problem. I think a "broken image" (maybe on windows?) is even useful for you to see that there's something fishy going on with your TileProvider!
As for rendering on the main thread, you're right. The only way to avoid that on the web, however, is to have a web-only TileProvider that knows how to delegate the getTile call to a service worker and an offscreen canvas (in that case the drawing might get more complicated, or you end up with a very big service worker that also includes flutter :P)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am very curious about this logicalTileSize. From the API it seems that both a TileOverlay and each Tile can specify their size, so this implementation can do away with this logicalTileSize const.
Why is this fixed to 256, and do we need it?
(If this is 256, how come the example is creating 100x100 tiles? They look blurry on the web as they're scaled up to fit!)
((Also: can tiles be non-square?))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logicalTileSize is used to communicate to Google Maps the size of the tile for use in coordinate conversions and scaling. This is configurable in the JS API and can be rectangular, but I don't think it's configurable in the Android API. At a logical size of 256 x 256, the web impl appears consistent with the Android impl. I haven't tried it on iOS.
JS API: https://developers.google.com/maps/documentation/javascript/maptypes#MapTypeInterface
Android:
https://developers.google.com/maps/documentation/android-sdk/reference/com/google/android/libraries/maps/model/TileOverlay#tile-coordinates
https://developers.google.com/maps/documentation/android-sdk/tileoverlay#coordinates
The physical size can be different and will be scaled on web. I used to use this to display different levels of detail on NOAA charts from a WMS server, effectively requesting higher DPIs to show more features.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AsturaPhoenix yes, I used the physical size being logicalSize * dpi to generate high DPI tiles too. Let's go with consistency for now, having a fixed logical size.
(PS: In iOS they also mention 256x256 tiles or 512x512 for "retina" displays: https://developers.google.com/maps/documentation/ios-sdk/tiles#high_dpi_tiles_for_retina_devices, I'm not sure if the iOS SDK supports sizes any other than those two (like a 3x tile))
packages/google_maps_flutter/google_maps_flutter_web/lib/src/overlay.dart
Outdated
Show resolved
Hide resolved
18003b2 to
a324854
Compare
|
When testing with the
Not so much on this side of the implementation :) ( |
|
Yeah, unfortunately the other performance changes probably won't pass muster since they involve changing the API to pass canvases as tiles instead of byte arrays. (There are also unrelated optimizations around serialization of polylines and friends, but unfortunately eventually I ran into an expensive serialization we didn't seem able to avoid within GMS core, so that was the end of that.) This LGTM too; I have one nit comment that I'll add, but it's probably not of consequence. |
Yes, it's quite painful. We can get a few ms back by using bmps instead of pngs, but we don't get jank-free until we pass canvases afaict. (flutter/flutter#116132) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm the tiniest bit concerned that this might also cause any overlays on top of the overlay being updated to reload, but I haven't exercised this case, and my concern might be premature optimization.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This little bit of code concerns me a little bit as well, but we'll see in the real world :) I simplified the original if-else a little bit and ended up with this, and I might have over-simplified. I'll tag you whenever the first bug comes about this so you can tell me: "I TOLD YOU SO!" :p
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh actually you know what, rereading this more carefully I think it does warrant another pass. For example, there actually seems to be a bug (that I almost doubt anyone would hit) where if you change the Z index of a layer that's not visible, it becomes visible. (Purely based on my reading of the code; I haven't run a test, so I might be wrong.)
It'd probably also be worthwhile to add a regression test for this case. (I can also take care of this if nobody gets around to it over the weekend.)
And, since this is in a loop, the impact of remove/insert vs. set for the stable z-index case, although probably still a premature optimization, could be compounded if it were ever actually an issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically the fix if we want to do it this way is just to remove the moved condition entirely, but you know what I'd do if it were up to me.
|
@AsturaPhoenix in this case I see two optimizations:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I don't think I have permission to push to the remote, but here's the patch (also adding some additional assertions in related tests to try to catch similar regressions):
diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/overlays_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/overlays_test.dart
index 4b95d8bbe..8b6b34694 100644
--- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/overlays_test.dart
+++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/overlays_test.dart
@@ -68,6 +68,9 @@ void main() {
tileProviders[1].getTile(any, any, any),
tileProviders[2].getTile(any, any, any),
]);
+ verifyNoMoreInteractions(tileProviders[0]);
+ verifyNoMoreInteractions(tileProviders[1]);
+ verifyNoMoreInteractions(tileProviders[2]);
});
testWidgets('changeTileOverlays', (WidgetTester tester) async {
@@ -87,6 +90,8 @@ void main() {
tileProviders[1].getTile(any, any, any),
]);
verifyZeroInteractions(tileProviders[0]);
+ verifyNoMoreInteractions(tileProviders[1]);
+ verifyNoMoreInteractions(tileProviders[2]);
// Re-enable overlay 0.
controller.changeTileOverlays(
@@ -99,6 +104,22 @@ void main() {
tileProviders[0].getTile(any, any, any),
tileProviders[1].getTile(any, any, any),
]);
+ verifyNoMoreInteractions(tileProviders[0]);
+ verifyNoMoreInteractions(tileProviders[1]);
+ verifyNoMoreInteractions(tileProviders[2]);
+ });
+
+ testWidgets(
+ 'updating the z index of a hidden layer does not make it visible',
+ (WidgetTester tester) async {
+ controller.addTileOverlays(<TileOverlay>{...tileOverlays});
+
+ controller.changeTileOverlays(<TileOverlay>{
+ tileOverlays[0].copyWith(zIndexParam: -1, visibleParam: false),
+ });
+
+ probeTiles();
+ verifyZeroInteractions(tileProviders[0]);
});
testWidgets('removeTileOverlays', (WidgetTester tester) async {
diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/overlays.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/overlays.dart
index 464fb319a..aa6c19173 100644
--- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/overlays.dart
+++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/overlays.dart
@@ -63,14 +63,13 @@ class TileOverlaysController extends GeometryController {
final bool wasVisible = controller.tileOverlay.visible;
final bool isVisible = tileOverlay.visible;
- final bool moved = tileOverlay.zIndex != controller.tileOverlay.zIndex;
controller.update(tileOverlay);
- if (wasVisible || moved) {
+ if (wasVisible) {
_remove(controller);
}
- if (isVisible || moved) {
+ if (isVisible) {
_insertZSorted(controller);
}
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically the fix if we want to do it this way is just to remove the moved condition entirely, but you know what I'd do if it were up to me.
a324854 to
bae3ab7
Compare
|
Hi @AsturaPhoenix, I sent an invite to collaborate, so maybe that will allow you to upload. I did just update the branch to resolve some conflicts, but didn't add your changes yet ( Please feel free to update as you see fit! |
Remove/add based on visibility only.
|
@AsturaPhoenix, @elitree thanks for the fix over the weekend! |
stuartmorgan-g
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
flutter/packages@60e9a54...3dc00c1 2023-08-01 [email protected] Manual roll Flutter from 1d44fbd to 1d59196 (18 revisions) (flutter/packages#4621) 2023-07-31 [email protected] Update the cirrus key jul-31-2023 (flutter/packages#4618) 2023-07-31 [email protected] [path_provider_platform_interface] Add getApplicationCachePath() (flutter/packages#4614) 2023-07-31 [email protected] [google_maps_flutter_web] Initial support for custom overlays (flutter/packages#3538) 2023-07-31 [email protected] [camera] Removed the microphone permission request from availableCameras on Web (flutter/packages#4263) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC [email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
flutter/packages@60e9a54...3dc00c1 2023-08-01 [email protected] Manual roll Flutter from 1d44fbd to 1d59196 (18 revisions) (flutter/packages#4621) 2023-07-31 [email protected] Update the cirrus key jul-31-2023 (flutter/packages#4618) 2023-07-31 [email protected] [path_provider_platform_interface] Add getApplicationCachePath() (flutter/packages#4614) 2023-07-31 [email protected] [google_maps_flutter_web] Initial support for custom overlays (flutter/packages#3538) 2023-07-31 [email protected] [camera] Removed the microphone permission request from availableCameras on Web (flutter/packages#4263) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC [email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
This is a resubmission of flutter/plugins#6982 from the now archived flutter plugins repo. I'm submitting the changes from the original author, @AsturaPhoenix. The original description is below.
Saves tile bytes to blobs and uses img elements to decode and render. Does not implement opacity, perform caching, or serve placeholder images.
Issue: Fixes flutter/flutter#98596
Known issues:
Pre-launch Checklist
dart format.)[shared_preferences]pubspec.yamlwith an appropriate new version according to the pub versioning philosophy, or this PR is exempt from version changes.CHANGELOG.mdto add a description of the change, following repository CHANGELOG style.///).If you need help, consider asking for advice on the #hackers-new channel on Discord.