MapBox GL custom markers with symbol layer - mapbox-gl-js

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.

Related

Mapbox - draw lines for each property

I use mapbox-gl to draw a map. In one of the routes (it's a single line) I have 2 attached properties:
{
id: 17,
pcs_mode: 'AtRisk'
},
id: 18,
pcs_mode: 'Excellent'
}
I want to draw 2 lines (each line for a property) and fill using a proper color, depending on pcs_mode.
I've tried to draw these like this:
const layerId = `segment-condition`;
map.current.addLayer({
id: layerId,
type: 'line',
source: SOURCE_NAME,
'source-layer': SOURCE_LAYER_NAME,
layout: {
'line-join': 'round',
'line-cap': 'butt'
},
paint: {
'line-color': [
'case',
['==', ConditionStates.Excellent, ['get', 'pcs_mode']],
CONDITION_COLORS[ConditionStates.Excellent],
['==', ConditionStates.AtRisk, ['get', 'pcs_mode']],
CONDITION_COLORS[ConditionStates.AtRisk],
['==', ConditionStates.Distressed, ['get', 'pcs_mode']],
CONDITION_COLORS[ConditionStates.Distressed],
['==', ConditionStates.NoMsl, ['get', 'pcs_mode']],
CONDITION_COLORS[ConditionStates.NoMsl],
'#000'
],
'line-width': 5,
'line-offset': 5
}
});
But it draws only one line (for the first property I suppose). How to draw lines for each property? Thanks!
In your code you have added only one line layer and the conditions are given for line-color. If you want to visualize two lines , then apply separate line-offset values for each condition state (using expression).

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'
],
}
});

Issue when using ticks option on h-axis: google charts

I am using google chart's combo stacked bar. I want to display explicit values for h-axis, so I used ticks option. But, after using this option, my graph is displaying all bar values at once along the h-axis. But, I want to limit the bars to let's say 5 at a time and display the rest dynamically by sliding the charRangeFilter. The bars are almost appearing as straight lines when I use ticks option as shown in the image. Could some help me in resolving this issue? Any help is highly appreciated
Below is the code for the chart options
let hTicks = new Array<Date>(); // I already populated this array with Dates
let chart = new google.visualization.ChartWrapper({
'chartType': 'ComboChart',
'containerId': 'chartRangeFilter_chart_div',
'options': { .
// Use the same chart area width as the control for . axis alignment.
'width': '100%',
'height': '100%',
'hAxis': { 'title': 'DATES', 'gridlines': { 'color': 'transparent' }, 'ticks': hTicks, 'slantedText': true, 'slantedTextAngle': hTicks.length <= 10 ? 45 : 90 },
'legend': 'none',
'vAxis': { 'title': 'CABINS', 'viewWindow': { 'min': 0, 'max': (Number(cabinTotal) * 1.5) } },
'seriesType': 'bars',
'chartArea': { 'height': '50%', 'width': '85%' },
'bar': { 'groupWidth': '15%' },
'series': { 4: { 'type': 'line' } },
'isStacked': true,
'colors': ['#95d631', '#d7d7d7', '#f44336', '#00bcd4', '#ffc107']
}
Below are the charts
Chart with Tick option Chart Without Tick option
Solved by updating the ticks dynamically as the user slides the chartFilter

add terrain-rgb layer to MaboxGL.js?

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

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'
}
});
});