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

Map panning/zooming is slow/jerky when unable to download map tiles #1889

Closed
baldricks-turnip opened this issue Mar 15, 2023 · 11 comments
Closed

Comments

@baldricks-turnip
Copy link

baldricks-turnip commented Mar 15, 2023

I have created a HttpMapSource that points to our MapBox tile server. This downloads and displays the maps and I can zoom and pan the map smoothly. The map source is configured to use a persistent file cache.

If I change the URL used to a server that doesn't exist, or an empty string, or disable the network connection, then the map is drawn from the cached tiles.
If I then try to zoom and pan the map, it is 'sticky' and not smooth where there are tiles that are not in the cache.

My app needs to operate from the cache when it fails to download tiles but I can't find a way to achieve this.

I have a cache and http source configured as follows (I've removed our MapBox key from the URL):

var mapControl = new Mapsui.UI.Maui.MapControl();
IPersistentCache<byte[]>? tileCache = new FileCache(documentsFolder + "tilecache", "png");

HttpTileSource httpMapSource = new HttpTileSource(new GlobalSphericalMercator(),
            @"https://api.mapbox.com/styles/v1/domotactical/",
            persistentCache: tileCache);

ILayer httpLayer = new TileLayer(httpMapSource);
mapControl.Map.Layers.Add(httpLayer);
mapControl.UnSnapRotationDegrees = 20;
Content = mapControl;

This is all ok until I cut the internet connection and then the map is (almost unusably) slow.

I'd expect the performance of the map rendering to be unaffected by a drop in network availability, or a URL server that is not available.

The app is using MAUi and the Mapsui.Maui 4.0.0-beta.8 package. I see the problem on a Windows build (release and debug). I've not yet tested on a mobile platform.
I'm using Windows 10 22H2 and Visual Studio Professional 2022 version 17.5.1.

@baldricks-turnip
Copy link
Author

I've added a test that shows the problem.
https://github.com/baldricks-turnip/MauiMapsuiTest

Compile the project, then disable internet access so no tiles can be downloaded from Openstreetmap (they will only be accessed from map tiles in cache, which are included in the repository).
Build for Windows target and start the app. Zoom into say North America. You will see blurry maps, which is as expected as there are missing tiles. Now pan the map. The panning is very jerky and should be smooth.

@pauldendulk
Copy link
Member

I cloned the sample but can not see a big difference (though perhaps some difference).

Here is an animated gif I made (It looks worse than it actually was because of a lower framerate).

mapsui

I can imagine that something goes wrong with retrying to fetch files that are not there, but I would like to see a clear difference so I know what needs to be fixed.

@pauldendulk
Copy link
Member

btw, I turned off all wifi with the switch. It might be that different things happen with different kind of connection problems. I simply have no internet, so perhaps HttpClient does not even try to fetch anything.

@baldricks-turnip
Copy link
Author

baldricks-turnip commented Mar 15, 2023

If I pan the map slowly it seems better. It's when panning quickly it becomes a problem. Could it be there is a cache in memory that when panned too far away causes the stickiness? It can be seen in the video the mouse moves (the yellow blob shows when the LMB is clicked) but the map does not follow it, and then a fraction later it snaps to where the mouse is.

PanningMap3

The following video is with the network connection restored. It is much smoother.
PanningMap4

@pauldendulk
Copy link
Member

I could reproduce it a bit at some point. Things that could make a difference:

  • Perhaps you have a bigger cache, grown over more hours of usage.
  • Perhaps panning over a longer period causes more requests to be fired.

I should investigate this with logging of fetch requests.

@baldricks-turnip
Copy link
Author

A bit more info.
If I publish the app and run it outside the VS debugger using the .msix, I can't reproduce the problem.
I once created a WPF canvas-based map tile renderer and that had a similar problem, which was caused by many download exceptions generated when the download timed out on each tile when there was not network connection. The exceptions were slowing the app within the debugger only.

I have also deployed to an Android device (Pixel 2) and this does not show the problem.

@baldricks-turnip
Copy link
Author

Is there a way to tell the source to not download and use the cache only?

@pauldendulk
Copy link
Member

I did not have time for this yet, and will be busy the coming weeks but I will look into this before the v4 release.

@pauldendulk
Copy link
Member

I tested this with WPF with some added logging. When I turn the internet off and moves the map I would see four requests go out that would hang for a long time (too long, the timeout should be shorter) but this did not seem to affect performance. If the map is moved again after the initial fails the requests fail immediately with a 'host not found' error. When zoomed to detail level there will be many failed tile requests. In that case I saw a decrease in performance, but only during the period that these tile requests went out and failed, which was a few second. In my test setup this could be resolved by turning off the logging and by not synchronizing the callback method on the UI thread. I will now make a MR to remove the synchronization on the UI thread (if needed the uses can do this in their own code). This may not be a full solution but this is what came out of my current test setup. My question to you is to test with the next release. If your problem persists I will test I will continue testing with the MAUI project you provided.

@pauldendulk
Copy link
Member

I tested with the sample below:

using BruTile.Cache;
using BruTile.Predefined;
using BruTile.Web;
using Mapsui.Tiling.Layers;
using System;
using System.IO;
using System.Threading.Tasks;

namespace Mapsui.Samples.Common.Maps.Performance;
public class TileLayerWithFileCaching : ISample
{     
    public string Name => "TileLayer File Caching";
    public string Category => "Performance";

    public Task<Map> CreateMapAsync() => Task.FromResult(CreateMap());

    [System.Diagnostics.CodeAnalysis.SuppressMessage("IDisposableAnalyzers.Correctness", "IDISP001:Dispose created", Justification = "<Pending>")]
    public static Map CreateMap()
    {
        var map = new Map();

        var folder = (Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData));
        IPersistentCache<byte[]> tileCache = new FileCache(Path.Combine(folder, "tilecache"), "png");
        var httpLayer = new TileLayer(CreateTileSource("my-user-agent", tileCache));
        map.Layers.Add(httpLayer);
        return map;
    }

    private static HttpTileSource CreateTileSource(string userAgent, IPersistentCache<byte[]> tileCache)
    {
        return new HttpTileSource(new GlobalSphericalMercator(),
            "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
            new[] { "a", "b", "c" }, name: "OpenStreetMap",
            attribution: OpenStreetMapAttribution, userAgent: userAgent, persistentCache: tileCache);
    }

    private static readonly BruTile.Attribution OpenStreetMapAttribution = new(
    "© OpenStreetMap contributors", "https://www.openstreetmap.org/copyright");

}

I am interested in any feedback on this.

@pauldendulk
Copy link
Member

I am closing this.

Summary: I was able to reproduce some sluggishness. This could be fixed by not synchronizing all the exception on the UI thread. I could not find any more specific problems. I was afraid that there was a loop of retries but this is not the case. When panning again there are retries but I expect this to be faster in case of no connection than when a tile is actually requested. I can investigate this further if there are still performance problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants