2

I'm slowly trying to switch to geojson layers with Mapbox GL JS.

I have few layers on my test map but I can't get the fitbounds to work. What I want to achieve is:

  1. Hoover over linestring highlights it - it already works
  2. Click on linestring should zoom to line string and shows popup with data from geojson.I tried to implement this example https://www.mapbox.com/mapbox-gl-js/example/zoomto-linestring/ but I can't get it to work :( What I have to do is to get coordinates of a clicked linestring and zoom to it.
  3. Click on other linestring when some other linestring is highlighted dehighlights the old one and highlights the new one and shows popup - that kinda works already
  4. Click anywhere on a map (outside linestrings) dehighlights linestring and hides popup.

Here's a link to working map:

http://mapaszlakow.eu/vector.html

code:

<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8' />
    <title></title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
    <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.33.1/mapbox-gl.js'></script>
    <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.33.1/mapbox-gl.css' rel='stylesheet' />
    <style>
        body { margin:0; padding:0; }
        #map { position:absolute; top:0; bottom:0; width:100%; }
        .mapboxgl-popup {
            max-width: 400px;
            font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif; 
        }           
    </style>
</head>
<body>
<div id='map'></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1Ijoid29qdGFzIiwiYSI6IjFlQUlCR0kifQ.UJLiteoZ1aqE-ASd9arT3g';
var map = new mapboxgl.Map({
    container: 'map',
    style: 'mapbox://styles/mapbox/outdoors-v9',
    center: [18,54],
    hash: true,
    zoom: 4
});

map.addControl(new mapboxgl.NavigationControl());


map.on("load", function() {
    map.addSource("szlaki", {
        "type": "geojson",
        'data': 'http://mapaszlakow.eu/szlakiPL.geojson'
    });
    map.addSource("szlakiFull", {
        "type": "geojson",
        'data': 'http://mapaszlakow.eu/szlakiPLFull.geojson'
    }); 
    map.addSource("ddr", {
        "type": "geojson",
        'data': 'http://mapaszlakow.eu/ddrPL.geojson'
    });

    map.addLayer({
        'id': '3d-buildings',
        'source': 'composite',
        'source-layer': 'building',
        'filter': ['==', 'extrude', 'true'],
        'type': 'fill-extrusion',
        'minzoom': 14,
        'paint': {
            'fill-extrusion-color': '#aaa',
            'fill-extrusion-height': {
                'type': 'identity',
                'property': 'height'
            },
            'fill-extrusion-base': {
                'type': 'identity',
                'property': 'min_height'
            },
            'fill-extrusion-opacity': .6
        }
    });



//instance cycle 0  

    map.addLayer({'id': 'blue0','type': 'line','source': 'szlaki',
    "filter": 
    ["all", ["==","osmc_color","blue"],["==","instance_cycle","0"]], 
        'layout': {
            "line-cap": "round",
            "line-join": "miter"
            },
        'paint': {
            'line-offset': {"stops": [[13, 0],[15, 2],[18, 12]]},   
            "line-width": {"base": 1.2,"stops": [[13,1.2],[18,7]]},
            'line-color' : "#0000ff"
        }
    });

    map.addLayer({'id': 'red0','type': 'line','source': 'szlaki',
    "filter": 
    ["all", ["==","osmc_color","red"],["==","instance_cycle","0"]], 
        'layout': {
            "line-cap": "round",
            "line-join": "miter"
            },
        'paint': {
            'line-offset': {"stops": [[13, 0],[15, 2],[18, 12]]},   
            "line-width": {"base": 1.2,"stops": [[13,1.2],[18,7]]},
            'line-color' : "#ff0000"
        }
    });

    map.addLayer({'id': 'green0','type': 'line','source': 'szlaki',
    "filter": 
    ["all", ["==","osmc_color","green"],["==","instance_cycle","0"]], 
        'layout': {
            "line-cap": "round",
            "line-join": "miter"
            },
        'paint': {
            'line-offset': {"stops": [[13, 0],[15, 2],[18, 12]]},   
            "line-width": {"base": 1.2,"stops": [[13,1.2],[18,7]]},
            'line-color' : "#7CFC00"
        }
    }); 

    map.addLayer({'id': 'yellow0','type': 'line','source': 'szlaki',
    "filter": 
    ["all", ["==","osmc_color","yellow"],["==","instance_cycle","0"]], 
        'layout': {
            "line-cap": "round",
            "line-join": "miter"
            },
        'paint': {
            'line-offset': {"stops": [[13, 0],[15, 2],[18, 12]]},   
            "line-width": {"base": 1.2,"stops": [[13,1.2],[18,7]]},
            'line-color' : "#FFCF00"
        }
    }); 

    map.addLayer({'id': 'black0','type': 'line','source': 'szlaki',
    "filter": 
    ["all", ["==","osmc_color","black"],["==","instance_cycle","0"]], 
        'layout': {
            "line-cap": "round",
            "line-join": "miter"
            },
        'paint': {
            'line-offset': {"stops": [[13, 0],[15, 2],[18, 12]]},   
            "line-width": {"base": 1.2,"stops": [[13,1.2],[18,7]]},
            'line-color' : "#000000"
        }
    }); 

    map.addLayer({'id': 'orange0','type': 'line','source': 'szlaki',
    "filter": 
    ["all", ["==","osmc_color","orange"],["==","instance_cycle","0"]], 
        'layout': {
            "line-cap": "round",
            "line-join": "miter"
            },
        'paint': {
            'line-offset': {"stops": [[13, 0],[15, 2],[18, 12]]},   
            "line-width": {"base": 1.2,"stops": [[13,1.2],[18,7]]},
            'line-color' : "#FFA500"
        }
    }); 


//instance cycle 1

    map.addLayer({'id': 'blue1`','type': 'line','source': 'szlaki',
    "filter": 
    ["all", ["==","osmc_color","blue"],["==","instance_cycle","1"]], 
        'layout': {
            "line-cap": "round",
            "line-join": "miter"
            },
        'paint': {
            'line-offset': {"stops": [[13, 0],[15, 2],[18, 12]]},   
            "line-width": {"base": 1.2,"stops": [[13,1.2],[18,7]]},
            'line-color' : "#FFA500"
        }
    }); 

    map.addLayer({'id': 'red1','type': 'line','source': 'szlaki',
    "filter": 
    ["all", ["==","osmc_color","red"],["==","instance_cycle","1"]], 
        'layout': {
            "line-cap": "round",
            "line-join": "miter"
            },
        'paint': {
            'line-offset': {"stops": [[13, 0],[15, 2],[18, 12]]},   
            "line-width": {"base": 1.2,"stops": [[13,1.2],[18,7]]},
            'line-color' : "#ff0000"
        }
    });

    map.addLayer({'id': 'green1','type': 'line','source': 'szlaki',
    "filter": 
    ["all", ["==","osmc_color","green"],["==","instance_cycle","1"]], 
        'layout': {
            "line-cap": "round",
            "line-join": "miter"
            },
        'paint': {
            'line-offset': {"stops": [[13, 0],[15, 2],[18, 12]]},   
            "line-width": {"base": 1.2,"stops": [[13,1.2],[18,7]]},
            'line-color' : "#7CFC00"
        }
    }); 

    map.addLayer({'id': 'yellow1','type': 'line','source': 'szlaki',
    "filter": 
    ["all", ["==","osmc_color","yellow"],["==","instance_cycle","1"]], 
        'layout': {
            "line-cap": "round",
            "line-join": "miter"
            },
        'paint': {
            'line-offset': {"stops": [[13, 0],[15, 2],[18, 12]]},   
            "line-width": {"base": 1.2,"stops": [[13,1.2],[18,7]]},
            'line-color' : "#FFCF00"
        }
    }); 

    map.addLayer({'id': 'black1','type': 'line','source': 'szlaki',
    "filter": 
    ["all", ["==","osmc_color","black"],["==","instance_cycle","1"]], 
        'layout': {
            "line-cap": "round",
            "line-join": "miter"
            },
        'paint': {
            'line-offset': {"stops": [[13, 0],[15, 2],[18, 12]]},   
            "line-width": {"base": 1.2,"stops": [[13,1.2],[18,7]]},
            'line-color' : "#000000"
        }
    }); 

    map.addLayer({'id': 'orange1','type': 'line','source': 'szlaki',
    "filter": 
    ["all", ["==","osmc_color","orange"],["==","instance_cycle","1"]], 
        'layout': {
            "line-cap": "round",
            "line-join": "miter"
            },
        'paint': {
            'line-offset': {"stops": [[13, 0],[15, 2],[18, 12]]},   
            "line-width": {"base": 1.2,"stops": [[13,1.2],[18,7]]},
            'line-color' : "#FFA500"
        }
    }); 

// Hoover and highlight layers


    map.addLayer({
        "id": "hoover","type": "line","source": "szlakiFull",
        "layout": {},
        "paint": {
            "line-width":10,
            'line-opacity':0
        }
    });

    map.addLayer({
        "id": "highlight","type": "line","source": "szlakiFull",
        "layout": {},
        "paint": {
            'line-offset': {
        "stops": [
            [13, 0],        
            [15, 2],
            [18, 12]
        ]
        },      
            "line-color": "orange",
            "line-width":10,
            'line-opacity':0.6
        },
        "filter": ["==", "name", ""]
    }); 
});

    map.on("mousemove", function(e) {
        var features = map.queryRenderedFeatures(e.point, { layers: ["hoover"] });
        if (features.length) {
            map.setFilter("highlight", ["==", "osm_id", features[0].properties.osm_id]);
        } else {
            map.setFilter("highlight", ["==", "osm_id", ""]);
        }
    });

    map.on("mouseout", function() {
        map.setFilter("highlight", ["==", "osm_id", ""]);
    });

    map.on('click', function (e) {

        var features = map.queryRenderedFeatures(e.point, { layers: ['highlight'] });
        if (!features.length) {
            return;
        }
        var feature = features[0];
        var popup = new mapboxgl.Popup()
            .setLngLat(map.unproject(e.point))
            .setHTML('Nazwa: ' +feature.properties.name + '<br>' + 'Numer: ' + feature.properties.ref + '<br>' + 'Długość: ' + feature.properties.distance + ' km' + '<br>' + 'Stan: ' + feature.properties.state + '<br>' + 'Opis: ' + feature.properties.description)
            .addTo(map);    
    });

    map.on('mousemove', function (e) {
        var features = map.queryRenderedFeatures(e.point, { layers: ['highlight'] });
        map.getCanvas().style.cursor = (features.length) ? 'pointer' : '';
    });


</script>

</body>
</html>

1 Answer 1

1

You've packed a few questions into one. Since you say points one and three are generally working, I'll focus on points two and four.

For zooming to a clicked feature, in your click event handler for the map, add this after you set the popup content:

// Zoom to the clicked feature.
var coordinates = feature.toJSON().geometry.coordinates;
var bounds = coordinates.reduce(function(bounds, coord) {
  return bounds.extend(coord);
}, new mapboxgl.LngLatBounds(coordinates[0], coordinates[0]));
map.fitBounds(bounds, { padding: 20 });

That's mostly copied out of the API example except for the feature.toJSON() line.

Point four should probably be an else branch in your click event handler so that when there are no features, you hide the map's popup and clear any highlighted features.

Also, you're loading about 30 MB of geojson (gzipped! ~80 MB uncompressed) which really slows down your page.

6
  • Thank you. I will try it and report. What would you suggest for geojson to make it fast? Geojson-vt?
    – Voyteck
    Mar 20, 2017 at 5:37
  • I added that code and now it works like this: Zoom to feature doesn't always work. Some clicked routes work correctly but when I click some nothing happends. It's very random. Also when zoomed in quite low it centres the line but only a portion of a line string. Another weird thing happend to popups. When 1 route is clicked, popup shows up. When you click the same route again second popup shows up.
    – Voyteck
    Mar 20, 2017 at 6:18
  • @Voyteck reducing coordinate precision (refer to gis.stackexchange.com/a/8674/124 for a break down of what each digit gets you) could save you a lot of space. Remove unused feature properties. Or don't load as much data. Mar 20, 2017 at 16:16
  • @Voyteck for the zooming and popup stuff, post code that reproduces what you're seeing. Also it's better to stick to one question per post. Threads here are cheap, please spend a minute here if you haven't yet: gis.stackexchange.com/tour Mar 20, 2017 at 16:19
  • Ok I reduced the geojson to 20 mb. It's 6 digits after comma. I guess I will try even less. I thought mapbox-gl js can handle that size quite easly as it is said in documentation that geojson-vt is included. As for zooming it's hard to paste a code here because this code already does that.(mapaszlakow.eu/vector.html#15.95/54.4928/18.4730) it doesn't fit to bounds of the whole route. Some routes don't work at all.Try clicking the blue route from the same link. If you zoom out you will see that routes are much longer.
    – Voyteck
    Mar 20, 2017 at 17:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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