add terrain-rgb layer to MaboxGL.js? - leaflet

I'd like to use Mapbox's terrain-rgb tiles as a layer in a Mapbox GL map.
The examples I've seen that manipulate terrain-rgb data use L.tileLayer to construct the tiles for the new layer:
https://www.mapbox.com/blog/terrain-rgb/
With MapboxGL.js, I've tried to add the layer this way:
map.on('load', function () {
map.addSource('terrain-rgb', {
type: 'vector',
url: 'https://api.mapbox.com/v4/mapbox.terrain-rgb/{z}/{x}/{y}.pngraw?access_token=pk.eyJ1IjoibWF0dCIsImEiOiJTUHZkajU0In0.oB-OGTMFtpkga8vC48HjIg'
});
map.addLayer({
'id': 'terrain-rgb',
'type': 'fill',
'source': 'terrain-rgb',
'layout': {
'visibility': 'visible'
},
'paint': {
'fill-color': 'rgba(15,148,179,.4)'
},
'source-layer': 'terrain-rgb'
});
});
I tried the fill, line, and circle type, but it's not working.
I get these console errors:
GET https://api.mapbox.com/v4/mapbox.terrain-rgb/%7Bz%7D/%7Bx%7D/%7By%7D.pngraw…ss_token=pk.eyJ1IjoibWF0dCIsImEiOiJTUHZkajU0In0.oB-OGTMFtpkga8vC48HjIg 404 (Not Found) ajax.js:25
Object {type: "error", target: t, isSourceLoaded: false, source: Object, sourceId: "terrain-rgb"} evented.js:104
How do I properly add a the terrain-rgb source to mapboxgl.js?

Ok, after looking through the issues on github, it seems this isn't possible yet:
https://github.com/mapbox/mapbox-gl-js/issues/3730

Related

Change state of mapbox map upon loading

I'm working on a web app with Mapbox and I want to change the state of a created polygon to be selected without clicking upon loading.
I appreciate any help!
draw.add({
'id': 'polygon',
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'Polygon',
'coordinates': [coordinates],
}
});
Current state
Desired state
You can use this to enter direct selection mode:
draw.changeMode('direct_select', { featureId: myFeatureId })
See the API docs for more info. https://github.com/mapbox/mapbox-gl-draw/blob/main/docs/API.md

How is this NYT Mapbox map rendered?

The map below is a high resolution county Mapbox map, with dynamically changing data. When trying to render the same high resolution county map with other tools, a lot of processing power is required. Why is this different?
Additionally, I believe they are using a custom tileset to render the county shapes, but then how is the data passed into the visualization? Any insight here would be appreciated. NYT Map Link
Whatever you want to know is in their main.js script
They do not use leaflet but mapbox-gl-js sdkVersion:"2.0.1"
They create a map with their own style
map$1 = new mapboxGl.Map({
container: $wrap,
style: 'mapbox://styles/nytgraphics/cjnxfd2cy57nq2rqj8o3d7sl2',
scrollZoom: false,
boxZoom: false,
maxZoom: 10
});
Then they create their fill layers based on the sources they load
function addSources() {
Object.keys(tilesets).forEach((name) => {
map$1.addSource(name, {
type: 'vector',
url: `mapbox://${tilesets[name]}`,
promoteId: 'geoid'
});
});
map$1.on('sourcedata', () => {
addLayers();
});
}
...
...
map$1.addLayer({
id: 'counties',
type: 'fill',
source: 'counties',
'source-layer': 'USA_Counties_With_RI',
paint: {
'fill-color': [
'case',
['has', ['get', 'geoid'], ['literal', colorLookup]],
['get', ['get', 'geoid'], ['literal', colorLookup]],
'#cccccc'
],
}
});

MapBox GL custom markers with symbol layer

I am trying to cluster custom markers in MapBox GL JS but I cannot figure out how to get a custom marker image from a url into the symbol layer? It either does not work or no markers show up at all. How is it done? I need to know how to use a custom image from a url with the symbol layer. Thank you very much.
map.addSource('parcelpoints', {
type: 'geojson',
data: geojson,
cluster: true,
clusterMaxZoom: 14, // Max zoom to cluster points on
clusterRadius: 50 // Radius of each cluster when clustering points (defaults to 50)
});
map.addLayer({
id: 'clusters',
type: 'circle',
source: 'parcelpoints',
filter: ['has', 'point_count'],
paint: {
// Use step expressions (https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-step)
// with three steps to implement three types of circles:
// * Blue, 20px circles when point count is less than 100
// * Yellow, 30px circles when point count is between 100 and 750
// * Pink, 40px circles when point count is greater than or equal to 750
'circle-color': [
'step',
['get', 'point_count'],
'#51bbd6',
100,
'#f1f075',
750,
'#f28cb1'
],
'circle-radius': [
'step',
['get', 'point_count'],
20,
100,
30,
750,
40
]
}
});
map.addLayer({
id: 'cluster-count',
type: 'symbol',
source: 'parcelpoints',
filter: ['has', 'point_count'],
layout: {
'text-field': '{point_count_abbreviated}',
'text-font': ['DIN Offc Pro Medium', 'Arial Unicode MS Bold'],
'text-size': 12
}
});
map.addLayer({
id: 'unclustered-point',
type: 'symbol',
source: 'parcelpoints',
filter: ['!has', 'point_count'],
'layout': {
'visibility': 'visible',
'icon-image': { url: "marker.svg" }
}
});
First you need to:
load the external image with a specific ID, via map.loadImage().
add the image with a specific ID, via map.addImage(https://docs.mapbox.com/mapbox-gl-js/api/map/#map#loadimage).
There is a worked example here: https://www.mapbox.com/mapbox-gl-js/example/add-image/
// If the style's sprite does not already contain an image with ID 'kitty',
// add the image 'cat-icon.png' to the style's sprite with the ID 'kitty'.
map.loadImage('https://upload.wikimedia.org/wikipedia/commons/thumb/6/60/Cat_silhouette.svg/400px-Cat_silhouette.svg.png', (error, image) => {
if (error) throw error;
if (!map.hasImage('kitty')) map.addImage('kitty', image);
});
To include your loaded image in a symbol layer will look something like:
map.addLayer({
'id': 'clusters',
'type': 'circle',
'source': 'parcelpoints',
'filter': ['has', 'point_count'],
'icon-image': 'kitty',
...
There is no support for directly loading symbol images from URLs.

GeoJSON layer won't load on MapBox GL JS

I'm trying to add a layer of GeoJSON data onto a MapBox base map, but it won't work. I've tried a number of their tutorials like this one and this one, but they won't work.
This is my code:
var map = new mapboxgl.Map({
container: 'themap',
center: [-73.9939914, 40.7274072],
zoom: 17,
style: 'mapbox://styles/mapbox/streets-v9'
});
map.on('load', function () {
map.addSource('plutodata', {
type: 'geojson',
url: 'http://url.geojson'
});
map.addLayer({
id: 'pluto',
type: 'fill',
source: 'plutodata',
'source-layer': 'plutodata',
layout: {
visibility: 'visible'
},
paint: {
'fill-color': 'rgba(61,153,80,0.55)'
}
});
});
The map loads, but the GeoJSON layer does not appear. Any ideas where I'm going wrong?
Full Solution:
tmcw's post below was the first step in fixing this issue. I added the COR-enabling headers to my .htaccess file. The second step was that the "url" property under map.addSource should have been "data." Now everything works.
For Mapbox GL JS to load data from this server, it needs to use Cross-origin resource sharing, and this URL doesn't support that. You'll need to enable CORS on the server or the file to permit other servers to request data.
You can upload your geojson as a tileset to Mapbox, then make a new layer in one of your styles, and enter your geojson tileset under the tab 'Layer from Data'. If, for instance, you called your new layer 'mygeojson' then you can call it in your .js, eg:
map.on('load', function() {
map.addLayer({
'id': 'mygeojson',
'source': 'composite',
'source-layer': 'mygeojson',
'type': 'fill',
'paint': {
'fill-color': '#f00'
}
});
});

Fit Mapbox map to boundaries of dynamic markers

I try to create a map with mapbox, that features dynamic markers. I want the map to automatically fit to the markers, as described here: https://www.mapbox.com/mapbox.js/example/v1.0.0/fit-map-to-markers/. Unfortunately I can't get it working.
The code also contains the feature markers as links (https://www.mapbox.com/mapbox.js/example/v1.0.0/markers-as-links/), which works great – but as JS- and Mapbox-Noob, I can't figure out how to combine both.
The code right now is this:
<div class='start-map'>
<div id='map'></div>
<script>
var map = L.mapbox.map('map', 'XXX', {zoomControl: false})
.setView([-20.1908, -67.5893], 3);
var geoJson = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [-67.5893, -20.1908]
},
properties: {
title: 'Salar de Uyuni',
'marker-size': 'small',
'marker-color': '#fff',
url: 'http://localhost'
}
},
{
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [170.2, -43.4764]
},
properties: {
title: 'Franz Josef Glacier',
'marker-size': 'small',
'marker-color': '#fff',
url: 'http://localhost'
}
}
]
};
map.featureLayer.setGeoJSON(geoJson);
map.featureLayer.on('click', function(e) {
e.layer.unbindPopup();
window.open(e.layer.feature.properties.url);
});
geoJson.on('ready', function() {
// featureLayer.getBounds() returns the corners of the furthest-out markers,
// and map.fitBounds() makes sure that the map contains these.
map.fitBounds(geoJson.getBounds());
});
</script>
</div>
Here's corrected code: https://gist.github.com/tmcw/10203442
Issues in this example:
geoJson is a simple JavaScript object, not a layer, so you can't call methods on it.
If you're adding custom data to a map, create a new L.mapbox.featureLayer rather than using map.featureLayer
If you're calling .setGeoJSON() you do not have to wait for the .on('ready' event.