Mapbox data driven styling for paint with boolean - mapbox

I'm trying to dynamically set the fill colour for a GeoJSON layer based on its properties.
The properties for the feature would be:
properties: {
color: 'cyan',
colorSelected: 'magenta',
selected: false,
}
For the mapbox paint attribute, I have:
paint: {
"fill-color": [
'case',
['==', ['get', 'selected'], ['get', 'colorSelected']],
['get', 'color'],
]
}
The idea being that if the "selected" property is true, get colourSelected = 'magenta', else the default of 'cyan'
This is not working, how can I do this boolean selection?

This solution ended up resolving my problem:
"fill-color": [
'case',
['==', ['get', 'selected'], true],
['get', 'fillColorSelected'],
['get', 'fillColor'],
],

Related

How can I change the ComboBox trigger to show a search icon?

The ComboBox component shows a dropdown icon for the trigger. How can I show a search icon instead? I am using ExtJS 3.X.
You can use the triggerClass config. I found a class x-form-search-trigger that seems to work. Here is a simple example:
new Ext.form.FormPanel({
items: [{
xtype: 'combo',
fieldLabel: 'Color',
mode: 'local',
triggerAction: 'all',
displayField: 'text',
valueField: 'value',
triggerClass: 'x-form-search-trigger',
store: new Ext.data.JsonStore({
data: [
{ text: 'Green', value: '1' },
{ text: 'Blue', value: '2' },
{ text: 'Red', value: '3' },
],
fields: [ 'text', 'value' ]
})
}],
renderTo: Ext.getBody()
});

Mapbox - achieving three states of paint opacity

I am trying to have 3 states of opacity for the following situation:
Clicked = Opacity: 0.8
Hover = Opacity: 0.6
Default = Opacity: 0.4
I have this code so far:
'paint': {
'fill-color': '#627BC1',
'fill-opacity': [
'case',
['boolean', ['feature-state', 'hover'], false],
0.6,
0.4
]
}
However given it's boolean, can someone help me understand how I can make this into an array with three states rather than 2?
Here is a useable example:
https://codepen.io/hiven/pen/NWwBXJj
James
You should be able to do something like the following
paint: {
"fill-color": "#627BC1",
"fill-opacity": [
"case",
["==", ["feature-state", "mystate"], 1],
0.6,
["==", ["feature-state", "mystate"], 2],
0.8,
0.4
]
}
Then you would just set "mystate" as required...
// Hover
map.setFeatureState(
{ source: "states", id: clickedStateId },
{ mystate: 1 }
);
// Clicked
map.setFeatureState(
{ source: "states", id: clickedStateId },
{ mystate: 2 }
);
With the default being 0.4
This way you can support an arbitrary number states, each with their own value - rather than a simple Boolean "true/false"

Cannot combine multiple filters (ISO country codes)

I followed this tutorial to highlight countries on my Mapbox map (using the Mapbox Countries v1 vector tileset). However, some countries seem to be highlighted twice (i.e. their shading is darker).
Here's my map right now:
As you can see, China, India, etc are a more vibrant color than the other countries in Asia. (This is also a phenomenon in the Medium post, as you can see in the third photo in the "Add a layer" section.)
Here's my code:
map.addLayer({
id: 'country-boundaries',
source: 'country-boundaries',
'source-layer': 'country_boundaries',
type: 'fill',
paint: {
'fill-color': palette.blue.flats,
'fill-opacity': 0.4,
},
filter: [
'in',
'iso_3166_1_alpha_3',
...highlightedContinents.reduce((countries, c) => {
return countries.concat(...ContinentRegionDefinitions[c].countries);
}, [] as ISOCountry[]),
],
});
and the array being returned is just a list of 3-digit ISO 3166-1 codes (['AFG', 'ARE', ...]).
I believe the problem is that I'm showing all worldviews, so countries with disputed boundaries are being shown twice.
I can change the filter from being the country codes to filtering by worldview (see bottom of docs page for sample code):
filter: [
'any',
['==', 'all', ['get', 'worldview']],
['in', 'US', ['get', 'worldview']],
],
and I get this, where almost all (except the circled) are only highlighted once:
Now, one would assume that, to get what I'm after, I could just combine these two filters like so:
[
'all',
[
'any',
['==', 'all', ['get', 'worldview']],
['in', 'US', ['get', 'worldview']],
],
[
'in',
'iso_3166_1_alpha_3',
...highlightedContinents.reduce((countries, c) => {
return countries.concat(...ContinentRegionDefinitions[c].countries);
}, [] as ISOCountry[]),
],
]
but for some reason that doesn't work:
(I've tried removing the ...highlightedCountinents.reduce(...) part and just replacing it with a short, static array, but that didn't help.)
Any thoughts? Is my filter wrong?
If anyone else stumbles across this I managed to get this to work with the following filter:
let masterFilter = [
'all',
['any',
['==', 'all', ['get', 'worldview']],
['in', 'US', ['get', 'worldview']],
],
['==', 'false', ['get', 'disputed']],
['any', ['all', ['in', ['get', 'iso_3166_1_alpha_3'], ["literal", countriesToShow.flat()]]]],
];

Mapbox GL - Prevent Layer Label Fading Based on Zoom

Using Mapbox GL JS 1.12.0 with a GeoJSON source I'm adding circles that have a numeric label based on the "name" value in the GeoJSON.
map.addLayer({
'id': 'marker',
'type': 'circle',
'source': 'geojson',
'minzoom': 0,
'maxzoom': 24,
'paint': {
'circle-radius': 10,
'circle-color': '#FFFFFF',
'circle-stroke-color': '#000000',
'circle-stroke-width': 2,
'circle-opacity': 1,
},
'filter': ['==', '$type', 'Point']
});
map.addLayer({
'id': 'marker-label',
'type': 'symbol',
'source': 'geojson',
'minzoom': 0,
'maxzoom': 24,
'layout': {
'text-field': [ 'format', ['get', 'name'], { 'font-scale': 0.8, 'text-translate': [0,-20] } ],
},
'filter': ['==', '$type', 'Point']
});
When you're zoomed in they look correct:
As you zoom out the circles start to overlap, but still look correct:
But then the "2" fades out and the "1" shows through the circle for #2 (even though the circles have a white fill and an opacity of 1) and makes it unclear which is #1 and which is #2.
Is there a better way to do this? I wish you could just add a centered label to the circle itself.
Can I disable this automatic fading / transparency?
Can I somehow bind the label to that specific circle?
Can I disable this automatic fading / transparency?
You can use "text-allow-overlap": true to disable it. You may not like the result.
Can I somehow bind the label to that specific circle?
No.

Mapbox JS Runtime Styling from collection

So I have a Mapbox Tileset I've uploaded with census-block information for the US. Each geometry in the tileset has a property called GeoID, that I am trying to apply a style to based on another collection I have.
The collection is an array objects with this format: [{geoid: string, weight: number}, {geoid: string, weight: number},...]
I want to match the GeoIDs from the array to the layer from the tileset and color it based on the corresponding weight property from that object. Weight is a number between 0 and 1. I have tried searching the documentation on runtime styling and expressions from Mapbox, but I can't find anything about extrapolating data from a collection and conditionally applying it to the right geometries from a tileset.
You can generate an expression from your list of weights and than pass it to the layer your want to style:
const weights = [
{geoid: 1, weight: 10},
{geoid: 2, weight: 5},
{geoid: 3, weight: 30},
];
const cases = weights.map(weight => {
const condition = ['==', ['get', 'geoid'], weight.geoid];
const output = getColor(weight.weight);
return [
condition,
output
];
});
const expresion = ['case',
...cases.reduce((flat, conditionAndOutput) => [...flat, ...conditionAndOutput]),
'<default-color>'
];
/*
Will result in:
[
"case",
[
"==",
[
"get",
"geoid"
],
1
],
"rgb(255, 255, 255)",
[
"==",
[
"get",
"geoid"
],
2
],
"rgb(255, 255, 255)",
[
"==",
[
"get",
"geoid"
],
3
],
"rgb(255, 255, 255)",
"<default-color>"
]
*/