Skip to content
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

Fix #629 | Reload map if options changed for overrideTilesWhenUrlChanges #740

Merged
merged 1 commit into from Jan 29, 2021
Merged

Fix #629 | Reload map if options changed for overrideTilesWhenUrlChanges #740

merged 1 commit into from Jan 29, 2021

Conversation

Xennis
Copy link
Contributor

@Xennis Xennis commented Sep 5, 2020

The option overrideTilesWhenUrlChanges currently only works if the URL
template changes but not if the options change.

For example:

TileLayerOptions(
  urlTemplate: 'https://api.mapbox.com/styles/v1/mapbox/{id}/tiles/{z}/{x}/{y}',
  additionalOptions: <String, String>{
    'id': mapboxStyle,
  },

If the value of id (here the Mapbox layer style, e.g. streets, satellite, etc.)
changes the option overrideTilesWhenUrlChanges should override the tiles as well.

@Xennis Xennis mentioned this pull request Sep 5, 2020
@maRci002
Copy link
Contributor

maRci002 commented Sep 5, 2020

This isn't perfect:

      final oldOptions = oldWidget.options.additionalOptions;
      final newOptions = options.additionalOptions;

      if (oldUrl != newUrl || oldOptions != newOptions) {

When you decalre every time a new HashMap they won't be equal, see

  additionalOptions: <String, String>{
    'id': mapboxStyle,
  },

Just see this: print({'x': 1} != {'x': 1} ); you would think this will print false because they are equals, however it will print true, so in this case oldOptions != newOptions will always evaluate to true which will reload tiles unnecessarily.

On the other hand if you cache additionalOptions in a Stateful widget and later you put / change a parameter in it then I would assume TileLayer would detects changes and map will reload tiles, however this won't happen, see:

class _HomePageState extends State<HomePage> {
  final params = <String, String>{
    'id': 'myStyle',
  };

  void onEvent() {
    setState(() {
      params['id'] = 'myStyle2';
    });
  }

  Widget build(BuildContext context) {
...
                  TileLayerOptions(
                    urlTemplate: 'https://api.mapbox.com/styles/v1/mapbox/{id}/tiles/{z}/{x}/{y}',
                    additionalOptions: params,
                  )
...

If an event calls onEvent() method, then it will change param, however TileLayer has the same instance so replace will affect that HashMap too, so they will be always equals, see:

  var a = {'x': 1};
  a['x'] = 2;
  
  print(a != a);

It will print false, however I wanted to reload tiles because one param changed.

@Xennis
Copy link
Contributor Author

Xennis commented Sep 5, 2020

Dear @maRci002 thanks for your detailed feedback. What do you recommend to fix this issue? Would using MapEquality help here?

@maRci002
Copy link
Contributor

maRci002 commented Sep 6, 2020

Yes you can use it, however there are still problems if programmer using explicit null value for additionalOptions.

  print((const MapEquality()).equals({'x': 1}, {'x': 1})); // true
  print((const MapEquality()).equals(null, {'x': 1})); // false !

So in TileLayerOptions change this line this.additionalOptions = const <String, String>{}, to Map<String, String> additionalOptions, and add this line to initializer list: additionalOptions = additionalOptions ?? const <String, String>{}, so now you make sure there isn't any null values and MapEquality will be fine. Note, this won't handle if you cache HashMap and change value inside it.

You have to handle updates on Map, so this case:
In initializer list you should use this line:

additionalOptions = additionalOptions == null
    ? const <String, String>{}
    : Map.from(additionalOptions), // copy Map, so we can safely compare old and new Map inside didUpdateWidget with MapEquality

…henUrlChanges

The option `overrideTilesWhenUrlChanges` currently only works if the URL
template changes but not if the options change.

For example:

```dart
TileLayerOptions(
  urlTemplate: 'https://api.mapbox.com/styles/v1/mapbox/{id}/tiles/{z}/{x}/{y}',
  additionalOptions: <String, String>{
    'id': mapboxStyle,
  },
```

If the value of `id` (here the Mapbox layer style, e.g. streets, satellite, etc.)
changes the option `overrideTilesWhenUrlChanges` should override the tiles as well.
@Xennis
Copy link
Contributor Author

Xennis commented Sep 6, 2020

Hey @maRci002 great thanks for your help. I adopted the MR accordingly.

Copy link
Contributor

@maRci002 maRci002 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@johnpryan johnpryan merged commit 965cfed into fleaflet:master Jan 29, 2021
@Xennis Xennis deleted the fix-629-reload branch February 3, 2021 00:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants