8

I have a leaflet app which displays a GeoJSON file as a layer. It works fine in the web browser. On the mobile browser it starts up, but quits after panning around on the map. I think the reason for that is that the GeoJSON file is too big (806kb). What kind of options do I have to get this to work on mobile?

<!DOCTYPE html>
<html>
    <head>
        <script src='http://api.tiles.mapbox.com/mapbox.js/v1.3.1/mapbox.js'></script>
        <link href='http://api.tiles.mapbox.com/mapbox.js/v1.3.1/mapbox.css' rel='stylesheet' />

        <script src="http://cdn.leafletjs.com/leaflet-0.6.4/leaflet.js"></script>
        <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.6.4/leaflet.css" />


        <link rel="stylesheet" href="dist/MarkerCluster.css" />
        <link rel="stylesheet" href="dist/MarkerCluster.Default.css" />
        <script src="dist/leaflet.markercluster.js"></script>
        <link rel="stylesheet" href="dist/L.Control.Locate.css" />
        <script src="dist/L.Control.Locate.js"></script>

        <script src="bikeParking.geojson" type="text/javascript"></script>

        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
        <style>
        body {padding: 0;margin: 0}
        #map { position:absolute; top:0; bottom:0; width:100%; }

        .mycluster {
            width: 30px;
            height: 30px;
            border: 5px solid #3887BE;
            border-radius: 20px;
            background-color: #3887BE;
            text-align: center;
            color: #FFF;
            font: 16px "Helvetica Neue", Arial, Helvetica, sans-serif;
        }

        </style>    

        <title>Bike Garage</title>

    </head>
    <body>
        <div id="map"></div>
        <script type='text/javascript'>


        var map = L.map('map').setView([45.50093,-122.65274], 12);
        var ui = document.getElementById('map-ui');

        L.tileLayer('https://a.tiles.mapbox.com/v3/blabla.blabla/{z}/{x}/{y}.png', {
                    attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
                    }).addTo(map);

        var markers = new L.markerClusterGroup({ disableClusteringAtZoom: 17,
            iconCreateFunction: function (cluster) {
                            return L.divIcon({ 
                                html: cluster.getChildCount(), className: 'mycluster',iconSize:null });
                        }, });
        var bikeParking = L.geoJson(bikeParking)        
        markers.addLayer(bikeParking).addTo(map);

        L.control.locate().addTo(map);
        </script>
    </body>
</html>
4

You may have already done these, but I have found they help a lot from my experience.

  1. Doing away with trailing (extraneous) decimals could also trim quite a bit of fat off of your json. Depending on your needs, you could go down to 2 or 3 decimal places. This all depends on scale of your map and the level of accuracy you are needing.
  2. Removing white space and line breaks can also decrease your file size. If you are storing the json in a .js include, compress it.
  3. OP brought up a great third point in a comment below, delete unnecessary attributes - this can potentially get rid of a lot of bloat as well.
| improve this answer | |
  • Yeah I already delete all the attributes, since I don't need them. How do I compress the .js? – ustroetz Nov 10 '13 at 22:56
  • 1
    @ustroetz To compress, trying something like jscompress.com. Tons of other options out there as well. – Chad Cooper Nov 10 '13 at 22:57
3

It turned out, that clustering actually helps a lot. I set the disableClusteringAtZoom to 19. This way it doesn't break anymore. The many individual points are clustered in one point until zoom level 19. The mobile browser seams to handle this better than having many individual points.

| improve this answer | |
  • 1
    Can you add a bit more detail here, please? – Alex Leith Nov 11 '13 at 0:42
2

My suggestion would be to split up the dataset into different geojson layers of co-located points, possibly through slicing by a fishnet.

I'm not sure how leaflet actually manages vector layers for display but my suspicion is that it only checks features to display if the extent of the layer is within the current map view. This means that at any given time there should be a much smaller number of points to check for rendering.

| improve this answer | |
  • Sound's like a good idea. I am just not sure how to display the layer in the default view, since I want to display all points in that view. But I think the clustering supports that, since I only display a few cluster points. My experience was, once I zoom in, where you see all the individual points, the app crashes. I'll give the slicing a try. – ustroetz Nov 10 '13 at 22:28
1

I think that you can simplify your dataset a bit. On examination, there are a bunch of bike garages that are duplicates. Perhaps you could group them together and represent them by one point, with an attribute that represents the number of spaces there? One of the stations had six points at it, and there doesn't seem to be any additional information there.

On inspection of your geojson file, there is about 5700 records in there. Combining stations might make that much smaller, maybe down to 2000 or so, which might be just enough!

Failing that, you could use MapBox.com, which does amazing things with speed and interactivity with massive datasets. Or look into TileJSON if you're into implementing yourself.

| improve this answer | |
  • I checked the file in QGIS. Only two points were duplicates. I don't really want to make my on tiles. But what exactly would you recommend from map box? Isn't leaflet.js and mapbox.js basically the same? – ustroetz Nov 10 '13 at 23:15
  • 1
    Have a read onTileJSON, it's just another vector format, but it's a bit more complex as it is tiled... Mapbox.com will host the data and do the fancy stuff for you... What about generalising the points? Look at your clustering, and note how there are many that end up at the same point. – Alex Leith Nov 11 '13 at 0:37
  • Yeah I will definitely generalize the points, like everybody here suggests. I will look into TileJSON. – ustroetz Nov 11 '13 at 1:37
0

If it was a polygon/line geometry, you could simplify them to make the GeoJSON file smaller in size. However, as you are serving a point geometry, I don't see many options.

How about serving only those points that are visible in the current viewport? Did you try switching the clustering off (I know it should get even slower afterwards, but anyway)?

| improve this answer | |
  • No, I haven't tried turning the clustering off, since I definitely want to the clustering be in there, otherwise one can't see anything. – ustroetz Nov 10 '13 at 22:12
  • Do you have an recommendations/documentations/examples on how to serve only those points that are visible in the current viewport? – ustroetz Nov 10 '13 at 22:12
  • Basically you should listen to map moves or map tilesloaded event and trigger a function everytime. The implementation is up to you, it would probably be a for loop with check against current bounding box. – Michal Zimmermann Nov 11 '13 at 12:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.