Styling markers from GeoJSON based on non-string feature properties in Mapbox - mapbox

as the title suggests, I would like to style some markers stored in a GeoJSON file. In each feature, I saved a "rotate": some_integer, based on how I want to rotate the marker.
In the stylejson in Mapbox I wrote the following style for the markers:
{
"id": "markers_test",
"type": "symbol",
"source": "markers_test",
"layout": {
"symbol-placement": "point",
"icon-image": "marker_{style_id}",
"icon-rotate": "{rotate}",
"text-field": "{name}",
"text-font": ["Open Sans Semibold"],
"text-anchor": "top-left",
"text-padding": 20,
"text-size": 10,
"text-optional": true
},
"paint": {
"text-color": "#dddddd",
"text-halo-color": "#0000ff",
"text-halo-width": 1,
"text-halo-blur": 1
}
}
Setting the correct name and icon works flawlessly, but as soon as I try to set up rotate, it crashes saying the value should be a number, not a string. Only - how do i reference a property of a feature outside a string?

The {token} syntax only works for text-field and icon-image. For all other properties you must use the property function syntax.
{
"id": "markers_test",
"type": "symbol",
"source": "markers_test",
"layout": {
"symbol-placement": "point",
"icon-image": "marker_{style_id}",
"icon-rotate": {
"property": "rotate",
"stops": [[0, 0], [365, 365]]
},
"text-field": "{name}",
"text-font": ["Open Sans Semibold"],
"text-anchor": "top-left",
"text-padding": 20,
"text-size": 10,
"text-optional": true
},
"paint": {
"text-color": "#dddddd",
"text-halo-color": "#0000ff",
"text-halo-width": 1,
"text-halo-blur": 1
}
}

Related

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:

Is there a way to extrude the height of mapbox Point on the map?

Is there a way to extrude the height of mapbox Point on the map?
Having the following example:
map.addSource("markers", {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [14.422063225409431,50.08273361716846]
},
"properties": {
"height": 12,
"base_height": 10,
"title": "Mapbox DC",
"marker-symbol": "spaceti-maintenance"
}
}, {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [14.421896271941648,50.08259946060207]
},
"properties": {
"height": 12,
"base_height": 10,
"title": "Mapbox SF",
"marker-symbol": "spaceti-maintenance"
}
}]
}
});
map.addLayer({
"id": "markers",
"source": "markers",
//"type": "symbol",
"type":"fill-extrusion",
// "layout": {
// "icon-image": "{marker-symbol}",
// "text-field": "{title}",
// "text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"],
// "text-offset": [0, 0.6],
// "text-anchor": "top"
// },
"paint": {
// See the Mapbox Style Spec for details on property functions
// https://www.mapbox.com/mapbox-gl-style-spec/#types-function
"fill-extrusion-color": "#424242",
"fill-extrusion-height": {
// Get fill-extrusion-height from the source "height" property.
"property": "height",
"type": "identity"
},
"fill-extrusion-base": {
// Get fill-extrusion-base from the source "base_height" property.
"property": "base_height",
"type": "identity"
},
// Make extrusions slightly opaque for see through indoor walls.
"fill-extrusion-opacity": 0.90
}
});
am I able to use both layout and paint properties of the layer assuming that I want to have marker with custom icon + extrusion height? I am building indoor navigation with multiple floor, that is the reason.
​It's not possible at this time to extrude points, however, you can convert these to (small) circles and extrude them based on your values. Looks like some similar requests for point cloud support is here:
​https://github.com/mapbox/mapbox-gl-js/issues/3450 so you may be able to follow the progress should it makes its way into new releases.

mapbox gl data driven style: What does the "value" parameter do?

I'm modifying my icon size based on the current zoom value by using the zoom data to drive the size.
As I understand it, I'm using the property "zoom" to track the zoom value (This is required as per the spec), In the stops I setup each desired "zoom" value and then output the icon-size value for that state (shown by the 0-1 > 3 range). If I don't include the parameter "value": something the code fails. If I set it all to 1, it works fine, so it seems that this value is ignored.
Can anyone explain its actual use?
// Add layer to map populating data from Geojson
map.addLayer({
"id": "seed",
"type": "symbol",
"source": "objects",
"layout": {
"icon-rotation-alignment": "map",
"icon-keep-upright": true,
"icon-rotate": 0,
"icon-image": "{icon}",
"icon-allow-overlap": true,
"icon-size": {
"property": "zoom",
"type": "exponential",
"stops": [
[{ "zoom": 15, "value": 1}, 0.1],
[{ "zoom": 16, "value": 1}, 0.3],
[{ "zoom": 17, "value": 1}, 0.6],
[{ "zoom": 18, "value": 1}, 0.8],
[{ "zoom": 19, "value": 1}, 2],
[{ "zoom": 20, "value": 1}, 3]
]
}
}
});
});
Apologies for the confusion #stuffyjoelab!
There are three types of functions in Mapbox GL:
Zoom functions allow the appearance of a map feature to change with map’s zoom level
Property functions allow the appearance of a map feature to change with its properties.
Zoom-and-property functions allow the appearance of a map feature to change with both its properties and zoom.
(There's more info about these in our style spec docs)
I'm using the property "zoom" to track the zoom value
We define a "property" as being per-feature metadata, a la GeoJSON feature properties. By this definition, zoom is not a property (unless you have a property on your features called zoom)
If you switch to the zoom function syntax by removing "property": "zoom" and replacing the {zoom, value} objects from your stops with numeric zooms, everything should work as expected.
// Add layer to map populating data from Geojson
map.addLayer({
"id": "seed",
"type": "symbol",
"source": "objects",
"layout": {
"icon-rotation-alignment": "map",
"icon-keep-upright": true,
"icon-rotate": 0,
"icon-image": "{icon}",
"icon-allow-overlap": true,
"icon-size": {
"type": "exponential",
"stops": [
[15, 0.1],
[16, 0.3],
[17, 0.6],
[18, 0.8],
[19, 2],
[20, 3]
]
}
}
});

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.

Can't get custom markers to work in Mapbox GL JS

I've followed both the example at Mapbox site and this instruction on GitHub but can't get markers to show on my map:
http://codepen.io/znak/pen/waPPRj (using Mapbox style and sprites)
http://codepen.io/znak/pen/PqOEyV (using custom style and sprites)
var center = [51.5, -0.1];
var map = new mapboxgl.Map({
container: 'map',
center: center,
zoom: 8,
style: 'https://www.mapbox.com/mapbox-gl-styles/styles/mapbox-streets-v7.json'
});
// Markers
map.on('style.load', function() {
map.addSource("markers", {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [51.48, -0.08]
},
"properties": {
"title": "Lorem",
"marker-symbol": "default_marker"
}
}, {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [51.52, -0.12]
},
"properties": {
"title": "Ipsum",
"marker-symbol": "secondary_marker"
}
}]
}
});
map.addLayer({
"id": "markers",
"type": "symbol",
"source": "markers",
"layout": {
"icon-image": "{marker-symbol}",
"text-field": "{title}",
"text-font": "Open Sans Semibold, Arial Unicode MS Bold",
"text-offset": [0, 0.6],
"text-anchor": "top"
},
"paint": {
"text-size": 14
}
});
});
All styles, JSON and PNG files with markers seem to load properly.
Any ideas?
The GeoJSON layer type of Mapbox GL JS follows the GeoJSON specification, which requires that coordinates be in longitude, latitude order. Your examples have them reversed. Flipping them shows the markers, which have the correct icons.
"geometry": {
"type": "Point",
"coordinates": [-0.12, 51.52]
}