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).
Related
I'm using Mapbox GL to color dynamically countries. Some of the countries are red, some are green.
For this, I'm using the country-boundaries-v1 source, then I use the iso_3166-1 data from country-boundaries to set a filter on the layers that use the country-boundaries source.
This is the code where I add my layers:
addLayers (map, layers) {
layers.forEach((layer) => {
map.addLayer({
id: layer.id,
source: layer.source,
'source-layer': layer.sourceLayer,
layout: {
visibility: 'none'
},
type: 'fill',
paint: {
'fill-opacity': 0.5
}
}, 'country-label')
})
},
And there is where I make visible my layer, add the color and set my filter on a list of iso_3166-1 codes:
map.setLayoutProperty(state.id, 'visibility', 'visible')
map.setPaintProperty(state.id, 'fill-color', this.layerColor(formattedState))
map.setFilter('positive-countries', ['in', 'iso_3166_1', 'FR', 'BE', 'IN', 'CN', 'JP'])
The problem is that when I add the 'fill-color' property on my layers that have reduced opacity, countries with different worldview (like China, Japan, India) therefore have layers that overlap. The result is that some countries, instead of having a layer with an opacity of 0.6, have 3 with an opacity of 0.6, which makes them opaque.
I tried to add this :
map.setFilter('positive-countries', ['match', ['get', 'worldview'], ['all', 'US'], true, false])
Hope Mapbox only uses the US worldview, but it doesn't work.
Here is a screenshot of my map so you can see the problem:
As you can see, countries like China, India and Japan have multiple layers because there's multiple worldview for these countries, so they look different than others.
Does anyone know if what I want to do is possible?
EDIT:
I tried this:
const filters = [
'any',
['in', 'iso_3166_1', 'MA', 'BR'],
['==', 'all', ['get', 'worldview']],
['in', 'US', ['get', 'worldview']]
]
map.setFilter('positive-countries', filters)
But I got these errors:
mapbox-gl.js:31 Error: layers.positive-countries.filter[2][2]: string, number, or boolean expected, array found
mapbox-gl.js:31 Error: layers.positive-countries.filter[3][2]: string, number, or boolean expected, array found
If I remove ['in', 'iso_3166_1', 'MA', 'BR'], there are no more errors but of course I have no applied filter on my map.
So, I tried this:
const filters = [
'any',
['==', 'all', ['get', 'worldview']],
['in', 'US', ['get', 'worldview']]
]
map.setFilter(params['id'], filters)
map.setFilter(params['id'], ['in', 'iso_3166_1', 'MA', 'BR'])
but the result is the same as without filter on the worldview...
If someone else is facing the same problem, this is the solution:
const filters = [
'all',
['match', ['get', 'worldview'], ['all', 'US'], true, false],
['match', ['get', 'iso_3166_1'], ['MA', 'BR'], true, false]
]
this.map.setFilter(layerId, filters)
Only the countries as seen by the USA are then visible
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'
],
}
});
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
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.
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