mapbox-gl-js icon indicating copy to clipboard operation
mapbox-gl-js copied to clipboard

Show long/lat grid lines

Open henriktorget opened this issue 4 years ago • 10 comments

Question

I am trying to add labeled latitudinal/longitudinal to my map like shown in image below. image

I can't seem to find a good way to do this from reading the documentation.

There is some implementations for this in leaflet, but the bindings for leaflet are experimental only and not suited for production. https://github.com/mapbox/mapbox-gl-leaflet

Am I missing something? Or is this possible to make in mapbox studio or programatically with mapbox-gl?

Thanks

Edit: Graticules is what I refer to by grid lines.

henriktorget avatar Nov 12 '20 12:11 henriktorget

@henriktorget you can do this programmatically with a GeoJSON source, generating a bunch of lines and then using this as a source with line and label layers. Something like this:

const graticule = {
    type: 'FeatureCollection',
    features: []
};
for (let lng = -170; lng <= 180; lng += 10) {
    graticule.features.push({
        type: 'Feature',
        geometry: {type: 'LineString', coordinates: [[lng, -90], [lng, 90]]},
        properties: {value: lng}
    });
}
for (let lat = -80; lat <= 80; lat += 10) {
    graticule.features.push({
        type: 'Feature',
        geometry: {type: 'LineString', coordinates: [[-180, lat], [180, lat]]},
        properties: {value: lat}
    });
}

map.on('load', () => {
    map.addSource('graticule', {
        type: 'geojson',
        data: graticule
    });
    map.addLayer({
        id: 'graticule',
        type: 'line',
        source: 'graticule'
    });
    ...

It might be a good idea to create a plugin for this to make it easier though.

mourner avatar Nov 12 '20 16:11 mourner

@mourner Thanks a lot for this!

I have been trying to do something similar. But I recently found a dataset for different "resolution" graticule grids that i could upload to mapbox studio and toggle on zoom level. Which works well enough for now.

If I feel that the datasets are limiting, I will adopt your idea.

henriktorget avatar Nov 13 '20 11:11 henriktorget

@henriktorget I am also trying to solve this. Could you please let me know what dataset you are using. I would also like to try that solution of uploading that dataset to mapbox.

Thanks for sharing this.

prafeb avatar Apr 02 '21 15:04 prafeb

@henriktorget I'm also interested by the dataset solution you mentioned but I did not find any graticule grids on the web. Could you please provide me a link ?

Thanks !

letelliercle avatar Sep 08 '21 13:09 letelliercle

Hey @letelliercle @prafeb!

What we are doing now is creating tiles from premade graticules. So i found these files with different resolutions:

https://www.naturalearthdata.com/downloads/10m-physical-vectors/10m-graticules/

These files can be dragged and dropped into mapbox studio as sources, and toggled on/of programatically. You can also set the max min zoom for the layers, so you get the prefered zoom level for each grid.

image

But going forward, i think we will try to do what @mourner is demonstrating. At least if you want to interact with the boxes, you might want to create them on the fly.

Edit:

So if i want to make boxed i can interact with, i would modify @mourner's code to create the grid that is within the viewport. (you have the top left and bottom right coordinates from events when the map is moved), and then create lines or boxes incrementally between these. Then you can add mouse over events to the boxes that highlights them.

henriktorget avatar Oct 28 '21 12:10 henriktorget

const graticule = {
    type: 'FeatureCollection',
    features: []
};
for (let lng = -170; lng <= 180; lng += 10) {
    graticule.features.push({
        type: 'Feature',
        geometry: {type: 'LineString', coordinates: [[lng, -90], [lng, 90]]},
        properties: {value: lng}
    });
}
for (let lat = -80; lat <= 80; lat += 10) {
    graticule.features.push({
        type: 'Feature',
        geometry: {type: 'LineString', coordinates: [[-180, lat], [180, lat]]},
        properties: {value: lat}
    });
}

map.on('load', () => {
    map.addSource('graticule', {
        type: 'geojson',
        data: graticule
    });
    map.addLayer({
        id: 'graticule',
        type: 'line',
        source: 'graticule'
    });
    ...

Apologies for re-opening but how could this be modidied to show minutes as well as degrees?

PaparazzoKid avatar Dec 16 '22 02:12 PaparazzoKid

I guess you could try something like this, where sixty minutes is one degree:


one_minute = 1 / 60

for (let lng = -170; lng <= 180; lng += one_minute) {
    graticule.features.push({
        type: 'Feature',
        geometry: {type: 'LineString', coordinates: [[lng, -90], [lng, 90]]},
        properties: {value: lng}
    });
}
for (let lat = -80; lat <= 80; lat +=one_minute) {
    graticule.features.push({
        type: 'Feature',
        geometry: {type: 'LineString', coordinates: [[-180, lat], [180, lat]]},
        properties: {value: lat}
    });
}`

henriktorget avatar Dec 16 '22 08:12 henriktorget

Splendid, thanks!!

PaparazzoKid avatar Dec 16 '22 13:12 PaparazzoKid

This is so awesome. Thanks for sharing this code. I want to use it with this example, but each time I toggle to a new style, the graticules are no longer visible. Any ideas?

https://docs.mapbox.com/mapbox-gl-js/example/setstyle/

kevando avatar Dec 17 '23 05:12 kevando

TLDR; you need to re add everything when you set a new style.

@kevando When you set a style you are setting a new style sheet (style.json) so the items you added to the existing stylesheet are gone (as they are set to the previous stylesheet).

paulsUsername avatar Mar 13 '24 22:03 paulsUsername