mapbox-gl-draw data driven style on LineString - mapbox

I use Mapbox GL Draw and I want to customize the fill color of my LineString Feature using data driven.
I have a set userProperties: true and I have a property prefixed with user_ .
here is my style configuration :
{
id: "gl-draw-linestring-fill-inactive",
type: "fill",
filter: ["all", ["==", "active", "false"], ["==", "$type", "LineString"],["!=", "mode", "static"],],
paint: {
"fill-color": [
"case",
["==", ["get", "user_type"], "meetingRoom"],
"#00ff00",
["==", ["get", "user_type"], "notUsed"],
"#00ff00",
"#ff0000",
],
"fill-outline-color": "#3bb2d0",
"fill-opacity": 0.4,
},
}
and my feature :
{
"type": "Feature",
"id": "ROOM-floor-1-1",
"properties": {
"parentId": "floor-1",
"user_type": "notUsed"
},
"geometry": {
"coordinates": [
[2.334699793548168, 48.85506145052912],
[2.3334337908935083, 48.85340956808176],
[2.3360301692199243, 48.85314130852265],
[2.3368884761040363, 48.85547088304844],
[2.3368884761040363, 48.85547088304844],
[2.334699793548168, 48.85506145052912]
],
"type": "LineString"
}
}
Feature is always paint with default value (#ff0000). It should be #00ff00 in this example.
In the same application I use the same property (user_type) to set Line color on Polygon and it works fine !
Any Idea ?

I just figured out how to do it, I'm putting the answer here in case other people make the same mistake as me.
I misunderstood the mapbox documentation for using my own properties in data driven styles.
If you want to use a property named myProp from your feature, you have to prefix it with user_ but only in the style rule.
For example:
{
"type": "Feature",
"id": "1",
"properties": {
"myProp": "myValue"
},
"geometry": {
"coordinates": [...],
"type": "LineString"
}
}
And:
{
id: 'my-rule',
type: 'line',
filter: ['all', ['==', 'active', 'false'], ['==', '$type', 'LineString'],['!=', 'mode', 'static']],
paint: {
'line-color': [
'match', ['get', 'user_myProp'], // get the property
'myValue', '#00ff00',
'#ff0000']
},
}
My mistake was to add prefix user_ in the style rule AND the feature properties.

I dont really understand, why you are using "type: fill" in your style configuration for a linestring. You shoud be using the line-specific style properties as shown in this mapbox example https://docs.mapbox.com/mapbox-gl-js/example/data-driven-lines/
Also, since you are refering to a property in your data driven styling, there is no need to use the "case". you can simply use "match"
So it would rather be:
{
id: 'gl-draw-linestring-fill-inactive',
type: 'line',
filter: ['all', ['==', 'active', 'false'], ['==', '$type', 'LineString'],['!=', 'mode', 'static']],
paint: {
'line-color': [
'match', ['get', 'user_type'], // get the property
'meetingRoom', '#00ff00',
'notUsed', '#00ff00',
'#ff0000'],
'line-width': 3,
},
}
By the way: ids on feature level should be integers or strings, that can be cast in as integers:
https://github.com/mapbox/mapbox-gl-js/issues/7632

Related

Mapbox GL style line color based on property text value

I'm trying to style a single GeoJSON source with different line colors based on a feature property using react-map-gl, and I can't find a way to get set the color of lines in a smart way.
Most of all, I would love to apply a function on the dataset to return the color of my own choosing based on a feature property value, but so far I haven't fount anything about it. If you know about it, please point in my direction:)
If I have the following GeoJSON:
{
"type": "FeatureCollection",
"name": "lineData",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "properties": { "Need": "Urgent" }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ 10.653823175868171, 59.676506860589157 ], [ 10.652881996887283, 59.675443989456632 ] ] ] } },
{ "type": "Feature", "properties": { "Need": "Starting" }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ 10.658536710768077, 59.680279341285896 ], [ 10.65787427600862, 59.680222775937636 ] ] ] } },
{ "type": "Feature", "properties": { "Need": "Medium" }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ 10.653224904719789, 59.67859470385492 ], [ 10.653201052045171, 59.678557551379008 ] ] ] } },
]
}
I would like to be able to style this source data with different line colors based on the property "Need". Say, urgent becomes red, medium becomes yellow, and starting becomes green.
I've read about styling expressions at mapbox, and I believe the "feature-state" is key to solving this, but I cant wrap my head around how to get the color converted from a feature.
If this in the rendering:
<Source id="my-data" type="geojson" data={TheDataFileWithSomeData}>
<Layer {...layerStyleTheLines } />
</Source>
Then I want a layer styling something like this (not working):
const layerStyleTheLines = {
id: 'style_it_to_red',
type: 'line',
paint: {
'line-color': [
[["==", ["feature-state", "Need"], "Urgent"],"red"],
[["==", ["feature-state", "Need"], "Medium"],"yellow"],
[["==", ["feature-state", "Need"], "Starting"],"green"]
],
'line-width': 3,
}
};
Thanks for all your help!
I've read about styling expressions at mapbox, and I believe the "feature-state" is key to solving this, but I cant wrap my head around how to get the color converted from a feature.
You only want feature-state if you're intending to manipulate the feature attributes dynamically, which I don't think you are.
You probably just want regular data-driven styling:
const layerStyleTheLines = {
id: 'style_it_to_red',
type: 'line',
paint: {
'line-color': [
'match', ['get','Need'],
'Urgent', 'red',
'Medium', 'yellow',
'Starting','green',
'black'
],
'line-width': 3,
}
};

with Mapbox gl draw, after overriding polygon features' circle-radius, how to enlarge the selected vertex's circle-radius?

in the official demo, after creating a polygon in the "draw_polygon" mode, as you direct_select a vertex on the polygon, that vertex will be enlarged. https://docs.mapbox.com/mapbox-gl-js/example/mapbox-gl-draw/
In this js fiddle: https://jsfiddle.net/frankzhang2046/y49mhtjx/16/
after overriding the styling rules for the vertices from line 258-271, the selected vertex under "direct_select" doesn't get enlarged anymore.
Was wondering what API/selector can I use to target the selected vertex to restore the "enlarged when selected" behavior. Thanks.
{
id: "i-guess-id-doesnt-matter",
type: "circle",
filter: [
"all",
["==", "meta", "vertex"],
["==", "$type", "Point"],
["!=", "mode", "static"],
],
paint: {
"circle-radius": 3,
"circle-color": "green"
},
},
update: discovered the ruleset used to target the selected vertex in the unminified MapboxDraw library. Changing the circle-radius bigging solved the problem
{
'id': 'gl-draw-point-active',
'type': 'circle',
'filter': ['all',
['==', '$type', 'Point'],
['!=', 'meta', 'midpoint'],
['==', 'active', 'true']],
'paint': {
'circle-radius': 5,
'circle-color': colorHexVal
}
},

How filter features by status

I want to show in my map in a cluster layer filtering by if is opened or not. How can do it? Should I create two layers?
One with filter: filter["has", "opened"] and other with filter: filter["!", ["has", "opened"]]?
export const clusterLayerOpened = {
id: "clusters",
type: "circle",
source: "earthquakes",
filter: ["has", "opened"],
paint: {
"circle-color": [ "step", ["get", "opened"], "#51bbd6",100,"#f1f075",750,"#f28cb1", ],
"circle-radius": ["step", ["get", "opened"], 20, 100, 30, 750, 40],
},
};
export const clusterLayerNoOpened = {
id: "clusters",
type: "circle",
source: "earthquakes",
filter: ["!", ["has", "opened"]],
paint: {
"circle-color": [ "step", ["get", "opened"], "#51bbd6",100,"#f1f075",750,"#f28cb1", ],
"circle-radius": ["step", ["get", "opened"], 20, 100, 30, 750, 40],
},
};
This is my geojson:
{
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {
"id": "ak16994521",
"mag": 2.3,
"time": 1507425650893,
"felt": null,
"tsunami": 0,
"opened": true
},
"geometry": {
"type": "Point",
"coordinates": [-151.5129, 63.1016, 0.0]
}
},
{
"type": "Feature",
"properties": {
"id": "ak16994519",
"mag": 1.7,
"time": 1507425289659,
"felt": null,
"tsunami": 0,
"opened": false
},
"geometry": {
"type": "Point",
"coordinates": [-150.4048, 63.1224, 105.5]
}
}
]
}
It's not necessary to create two separate layers to filter by whether the a point has been opened or not. Here is some code showing how to add a layer which displays all points with the property "opened": true, and hides all points with "opened": false:
map.addLayer({
'id': 'opened',
'type': 'circle',
'source': 'points',
'paint': {
'circle-radius': 10,
'circle-opacity': ["match", ["to-string", ["get", "opened"]], 'true', 1 , 'false', 0, 0]
}
});
To instead show all points with the property "opened": false, you can switch the 'circle-opacity' expression to read:
["match", ["to-string", ["get", "opened"]], 'true', 0 , 'false', 1, 0]
This code makes use of a few Mapbox expressions. I've linked the documentation to each relevant expression here: match, to-string, and get.
Here is a JSFiddle where two layers are added to the map: https://jsfiddle.net/hpkzrm4n/. The points with "opened": true are shown in red and the points with "opened": false are shown in blue. Note that you will need to add your own Mapbox access token where indicated in order to view the results. Here is a screenshot, as a preview:

How to remove specific feature in feature collection under geojson source in a places layer?

I got this:
map.addLayer({
"id": "places",
"type": "symbol",
"source": {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": features
}
},
"layout": {
"icon-image": "{icon}-15",
"text-field": "{title}",
"text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"],
"text-offset": [0, 0.6],
"text-anchor": "top"
}
});
Where features is array of objects like this:
{
"id": SOME_ID,
"type": "Feature",
"properties": {
"title": SOME_TITLE,
"icon": "monument"
},
"geometry": {
"type": "Point",
"coordinates": SOME_COORDINATES
}
}
I want to delete this specific feature, NOT THE WHOLE places LAYER, how can it be done?
I have tried to create for each feature, a designated layer with predefined ID, but
when tried to remove it using map.removeLayer(SOME_ID) this told me that the
layer id does not exist.
How to delete specific geojson feature from feature collection in mapbox, without delete the wole
layer, just the json data?
If you want to hide the feature on the map, then you don't have to remove it from the source. You can filter this feature out using filter, so it wouldn't be rendered on the map.
Consider example:
map.addLayer({
id: 'points',
type: 'circle',
source: {
type: 'geojson',
data: {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
id: 1,
properties: {},
geometry: {
type: 'Point',
coordinates: [127.61718749999999, 66.51326044311185]
}
},
{
type: 'Feature',
id: 2,
properties: {},
geometry: {
type: 'Point',
coordinates: [79.1015625, 72.50172235139388]
}
},
{
type: 'Feature',
id: 3,
properties: {},
geometry: {
type: 'Point',
coordinates: [61.17187499999999, 31.952162238024975]
}
}
]
}
},
filter: ['!=', '$id', 3]
});
This will render all features except feature with id=3.
You can also set this kind of filters using map.setFilter method.
map.setFilter('my-layer', ['==', 'name', 'USA']);
Edit:
If you really want to remove a specific feature from the source, you can filter this feature from the features array and update the source using setData:
map.getSource('places').setData({
"type": "FeatureCollection",
features
});

Color only the edge of a circle mapbox gl js

I want to show the outline of a circle on an interactive map (no fill) however, the paint options in mapbox-gl-js seem limited to fill only.
https://www.mapbox.com/mapbox-gl-style-spec/#layers-circle
var styles = [{
"id": 'points',
"interactive": true,
"type": "circle",
"source": "geojson",
"paint": {
"circle-radius": 5,
"circle-color": "#000
},
"filter": ["in", "$type", "Point"]
}, {
"type": "line",
"source": "geojson",
"layout": {
"line-cap": "round",
"line-join": "round"
},
"paint": {
"line-color": "#000",
"line-width": 2.5
},
"filter": ["in", "$type", "LineString"]
}];
Am i missing something or is this just not possible?
This is now possible, with circle-opacity.
E.g.:
"paint": {
"circle-opacity": 0,
"circle-stroke-width": 1,
"circle-stroke-color": #000
}
Not currently possible. Current top workaround appears to be layering two circles of slightly different sizes.
https://github.com/mapbox/mapbox-gl-js/issues/1713
https://github.com/mapbox/mapbox-gl-style-spec/issues/379
I'm having trouble running custom color 'match' and having opacity controls running simultaneously.
I can get both working, but not at the same time. See code below.
var coorAddresses = [ [ -75.7040473, 45.418067,"Medium" ], [-75.7040473, 45.418067, "Medium"], [-79.32930440000001, 43.7730495, "Unknown"]]
$.getJSON(coodAddresses, function(data) {
for(var itemIndex in data) {
// push new feature to the collection
featureCollection.push({
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [data[itemIndex][0], data[itemIndex][1]]
},
"properties": {
"size_by": data[itemIndex][2],
"color_by": data[itemIndex][2]
},
});
}
});
map.on('load', function () {
map.addLayer({
"id": "points",
"type": "circle",
"source": {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": featureCollection
}
},
"paint": {
"circle-color": [
'match',
['get', 'size_by'],
'Easy',
'#e4f400',
'Medium',
'#f48a00',
'Unknown',
'#6af400',
/* other */ '#00e4f4'
],
"circle-radius": [
'match',
['get', 'size_by'],
'Easy',
4,
'Medium',
7,
'Unknown',
2,
/* other */ 1000
],
// "circle-opacity": 0, // color does not show if i uncomment these lines
// "circle-stroke-width": 1, // do not get desired 'hollow' circle unless these lines run
}});
Trying to troubleshoot.