-
-
Notifications
You must be signed in to change notification settings - Fork 866
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
Improve tile management #572
Conversation
…n tileZoom is within limits
Good job man, this is very close to what I was thinking to achieve. |
If someone wants to observe tile fetching / pruning / aborting then revert remove diagnostic prints commit. Maybe fade in can be improved (Tile has an animationController), but user is able to increase default 100ms. |
If maintainer plans to merge this PR then pls wait a bit because I am going to add some documentation and making some performance refactors (ie. making local function call from setState instead of creating closure-s). |
Good job! I hope this gets merged some time soon! |
@maRci002 Thanks for this PR, I hope it gets merged very soon |
Not much difference that I could observe. It possibly takes slightly less time for the old tiles to disappear, but there's still a crossover where both the old and new tiles are visible at the same time. |
Woohoo! I'm taking a look now, but this is looking great so far! |
// It was a zoom lvl change | ||
_setView(map.center, tileZoom); | ||
} else { | ||
if (null == _throttleUpdate) { |
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.
@maRci002 do you always put null on the left hand side of an equality check? :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.
Sometimes I like using yoda style 😄
It has it own advantage; forinstance in JS this is a valid expression statement (but user wanted to check if i
equals to 7
, like i == 7
or i === 7
)
var i = 0;
if (i=7){
// this block will be executed
}
console.log(i); // prints 7
Or in java:
String i = null;
if (i.equals("CONSTANT")) {} // NullPointerException
It has it's own benefits but not in Dart 😅
@johnpryan you are welcome. |
@pento so you are using multiple I think this will help your problem just change this:
To this:
Or maybe to this:
|
@obiwanzenobi tiles which are on the same zoom level are retained based on margin.
|
this.retain = false, | ||
this.loadError = false, | ||
}) { | ||
try { |
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.
@maRci002 - I think this constructor body introduced error reported in #608. The reason why PR #609 works is that it replaces the state in the widget-tree, forcing a fresh _TileLayerState to be constructed.
In it self, the code is not wrong, the problem occurs in _addTile
, where assignment to array _tiles[tileCoordsToKey]
is done after the body is executed.
_tiles[tileCoordsToKey] = Tile(
coords: coords,
coordsKey: tileCoordsToKey,
tilePos: _getTilePos(coords),
current: true,
level: _levels[coords.z],
imageProvider: options.tileProvider.getImage(_wrapCoords(coords), options),
tileReady: _tileReady,
);
The callback method tileReady
is called indirectly from the method _tileOnLoad
when the image has been loaded. If the tile is already cached, the method will return immediately, invoking tileReady
before the assignment to _tiles[tileCoordsToKey]
is completed. In the actual callback method _tileReady
, the assignment is evaluated.
var key = _tileCoordsToKey(coords);
tile = _tiles[key];
if (null == tile) {
return;
}
and as you can see, the method will return before it is rendered to the canvas.
Working solution
- Removing the code from constructor body
- using the new method in
loadTileImage
in PR https://github.com/johnpryan/flutter_map/pull/584/files#diff-d0fc1fe821e34169c8068a76a40415f3R1007 to load image expliclity in_addTile
I've done this change in https://github.com/DISCOOS/flutter_map/blob/track_change_and_evict_errors/lib/src/layer/tile_layer.dart#L887 and it solves the problem:
void _addTile(Coords<double> coords) {
var tileCoordsToKey = _tileCoordsToKey(coords);
_tiles[tileCoordsToKey] = Tile(
coords: coords,
coordsKey: tileCoordsToKey,
tilePos: _getTilePos(coords),
current: true,
level: _levels[coords.z],
imageProvider: options.tileProvider.getImage(_wrapCoords(coords), options),
tileReady: _tileReady,
);
_tiles[tileCoordsToKey].loadTileImage();
}
I could make an PR with the change to #584 if you're interested?
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'll checkout your suggestions soon. However #609 works because if drawer detects if user wants to navigate to the same menu then it just closes drawer instead of reopen same menu. You can test it if you pan away then if you try to reopen same menu then map current location stays the same as before.
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.
Yes, of course. My bad.
Hi @maRci002 thanks for this. I am using flutter_map 0.10.1+1 and I can see the map is retaining the previous tiles when zooming if the network connection is slow. However, I am testing the case where I manually set the device to flight mode and switch off all internet connections. In this case when trying to zoom the map shows a grey tile instead of keep displaying the previous zoom tiles. |
@velval Leaflet does the same thing so this is the intended behaviour if a Tile loads with error then we show empty Tile on screen because it's loaded so we can throw away old level Tiles. https://leafletjs.com/ on PC I turned off my internet and gray Tiles appear when zooming in or out. You can use And 582 will allow to do anything with Tiles including error Tiles. |
@maRci002 I'm working on refactoring the tile layer code again and I've noticed that the z coordinate of tiles (the zoom level of tiles) is always a whole number but the minNativeZoom and maxNativeZoom are doubles. I wondered if there is a use case for this? If it is possible to change them to ints instead that would allow me to simplify some of the tile related code and cache some values for various zoom levels. |
If I read the doc it suggest me this should be integer. /// Maximum zoom number the tile source has available. If it is specified, the
/// tiles on all zoom levels higher than maxNativeZoom will be loaded from
/// maxNativeZoom level and auto-scaled.
final double? maxNativeZoom; I am not fully aware of the project at the moment but here you should test what happens for instance when flutter_map/lib/src/layer/tile_layer/tile_layer.dart Lines 616 to 621 in 3e8368d
|
Thanks for the response @maRci002! I think your right that in practice it is used like an integer anyway 👍 . |
@maRci002 I just noticed that the tile provider rounds the tile numbers anyway so it looks like an int is fine 🎉 flutter_map/lib/src/layer/tile_layer/tile_provider/base_tile_provider.dart Lines 29 to 31 in 3e8368d
|
@rorystephenson I think
flutter_map/lib/src/layer/tile_layer/tile_layer.dart Lines 518 to 522 in 3e8368d
|
Hello, I made some changes mainly in tile_layer.dart in order to keep the old tiles on the screen when zooming if new ones not avaible. These changes based on current Leaflet's tile fetching /retaining strategy see TileLayer.js / GridLayer.js.
I also added some missing features like minZoom / minNativeZoom / maxNativeZoom / zoomReverse / zoomOffset / errorImage and fixed / tracked down some other problems which I will mention in closes section.
Normal use case (fast internet connection)
Simulating slow internet connection
Add support for Error tiles
Add support for minNativeZoom / maxNativeZoom (this demo shows locked minNativeZoom: 16 while real zoom is about 12/10 <- it will be a real trial for mobile phones bandwidth / render time)
Support for remove tiles if we are out of zoom limits (we don't call any setState if we are out of bounds, however we pay attention for zoom lvl changes) -- this can happen if forinstance MapOptions has maxZoom: 18, but TileLayerOptions has maxZoom: 16; works with minZoom too, and fixed #59 overscale problems (helps if MapOptions / TileLayerOptions has same maxZoom, however without this fix overscale could go beyond limits which could have caused remove all tiles).
closes #59
closes #79
closes #125
closes #227 (we don't need remove maxZoom because we may have multiple layers and if current tilelayer is more than maxZoom then _removeAllTiles called also applies to minZoom; we stop fetching new tiles when not inside min /maxZoom moreover we skip setState calls for performance reasons)
closes #339 (performance -- maybe this PR resolves this because build() method was designed to run as fast as possible (_update is throttled and _pruneTiles / _setView called only when necessary))
closes #386
closes #429
closes #444
closes #457
closes #463
closes #492 (performance -- maybe this PR resolves this because build() method was designed to run as fast as possible (_update is throttled and _pruneTiles / _setView called only when necessary))
closes #517
closes #523
closes #536
closes #538
PR will be closed also:
closes #525
closes #570
PR also gives opportunity to finish these issues easily (we can add some callbacks to TileLayerOptions - when a Tile is downloaded / become active (when loaded + and fade ends) / Tile loads with an error / or when all tiles loaded (_noTilesToLoad internal function can fire callback when the grid layer loaded all visible tiles)):
see #345
see #377