MapboxGL JS - Shape layer type - mapbox-gl-js

I have a map with a vector tile source containing thousands of geojson points.
I can display the points on a map, showing a circle for each one of them, using a circle type layer.
I would like to do the same, but using different shapes, such as square and triangle. Isn't there a built-in way to do this ? What are my options ?

In case it is of any use, this is what I did :
I created a set of svg images in different colors, by editing the maki shape icons provided at https://www.mapbox.com/maki-icons/editor/
I converted them to a jpg sprite file and a json descriptor using https://github.com/mapbox/spritezero-cli
I created a style derived from the mapbox-provided styles, in order to use my custom sprite, and served this style using https://github.com/klokantech/tileserver-gl
In my layer configuration, I used a "symbol" type layer and selected the relevant icon by passing its name in the layout properties "icon-image" : "green-triangle-11"
I'll admit it's quite a lot of work to display a green triangle on a map !
Edit (18-07-2017) : I found out you can load any image and display it on the map, it doesn't have to be part of the style. I'm not sure if Mapbox added this recently or if I had missed it until now. Here goes :
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;
map.addImage('cat', image);
map.addLayer({
"id": "points",
"type": "symbol",
"source": {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [0, 0]
}
}]
}
},
"layout": {
"icon-image": "cat",
"icon-size": 0.25
}
});
});
Taken from https://www.mapbox.com/mapbox-gl-js/example/add-image/

Related

Map Tiling Service ignores GeoJSON styles

I uploaded GeoJSON with "simple styles" to Map Tiling Service (MTS). It seems that MTS ignores the styles. The GeoJSON was generated with geojsoncontour. I use mtsds to upload to MTS.
Any idea why MTS skips the styling?
A part of input GeoJSON is:
...
"type": "MultiPolygon"
},
"properties": {
"fill": "#471164",
"fill-opacity": 0.9,
"stroke": "#471164",
"stroke-opacity": 1,
"stroke-width": 1,
"title": "200.00-210.00 "
},
"type": "Feature"
}
But in MTS I see the following:

Drawing a line in mapbox-gl using coordinates from an array?

I am trying to draw a line on mapbox using coordinates from an api request. The api call retrieves an array of map points latitude and longitude values. I had tried using the example for creating a geojson line at this website:
https://www.mapbox.com/mapbox-gl-js/example/geojson-line/ however this example and every other example I found only showed adding layers to the map containing hardcoded coordinates rather than coordinates that will be retrieved from another source later.
What I originally thought would work is simply creating an array of lat/longs in the appropriate format then putting that array equal to the coordinates when adding a layer, like so:
var lineArray = [];
for(var i = 0; i < response.mapPoints.length; i++)
{
lineArray[i] = " [" + response.mapPoints[i].lng + ", " + response.mapPoints[i].lat + "]";
}
map.addLayer({
"id": "route",
"type": "line",
"source": {
"type": "geojson",
"data": {
"type": "Feature",
"properties": {},
"geometry": {
"type": "LineString",
"coordinates": [
lineArray
]
}
}
},
"layout": {
"line-join": "round",
"line-cap": "round"
},
"paint": {
"line-color": "#888",
"line-width": 8
}
});
The lineArray looked correct after printing it out. I was able to create a small line using a for loop and changing the add layer code to look like the following:
"coordinates": [
[ response.mapPoints[i].lng, response.mapPoints[i].lat ],
[ response.mapPoints[i+1].lng, response.mapPoints[i+1].lat ]
]
however this took way too long since I am using thousands of coordinates at a time and am having to loop through every single one in order to draw the line.
Am I on the right track at all? Any help or direction to a similar example would be greatly appreciated!
You could use Turf.js for creating a LineString feature from an array of positions (http://turfjs.org/docs/#lineString) and use this LineString as a source for a line layer:
Example (based on https://www.mapbox.com/mapbox-gl-js/example/geojson-line/):
http://jsbin.com/beziyolisu/1/edit?html,output
var positions =[
[lon_1, lat_1],
...
[lon_n, lat_n]
];
var linestring = turf.lineString(positions);
map.on('load', function () {
map.addLayer({
"id": "route",
"type": "line",
"source": {
"type": "geojson",
"data": linestring
},
"layout": {...},
"paint":{...},
});
});

Leaflet FeatureCollection: LatLong is undefined

I am looking to create a GeoJson instance from a database request with PHP.
I am using this package to create the instance:
http://jmikola.github.io/geojson/api/class-GeoJson.Feature.FeatureCollection.html
I have created the FeatureCollection but I am getting an error
"Error: Invalid LatLng object: (undefined, undefined)"
even though my coordinates are floats.
However, the coordinates are not coming through an array [,], but as a Javascript objects {,} that are inside an array and maybe this is the problem?
Secondly, I think I am having trouble setting the CRS. I can successfully create the GeoJSON in QGIS and it appears at the top of the FeatureCollection but with this package in PHP it appears towards the end.
My feature collection looks like this:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "MultiPoint",
"coordinates": [
{...},
{...}
]
},
"properties": [
{...},
{...}
],
"id": {
"type": "name",
"properties": {
"name": "urn:ogc:def:crs:OGC:1.3:CRS84"
}
}
}
]
}
I hope someone can help because I have been trawling through forums for hours!
Cheers
Yes, the coordinates and properties must be arrays, and not objects. Therefore, you can transform those before trying to create your geoJSON, like this:
//loop through all your features
featureCollection.features.forEach(function(feature) {
// first the coordinates in the geometry property
feature.geometry.coordinates.forEach(function(coord, index) {
feature.geometry.coordinates[index] = [coord.lat, coord.lng];
});
// then those in the properties
feature.properties.forEach(function(prop, index) {
feature.properties[index] = [prop.lat, prop.lng];
});
});

Mapbox GL setData to update layer with multiple markers

I have a Mapbox GL map with a single layer and multiple markers on that layer, I am trying to update a specific marker, so I am using setData in order to update only one marker but setData will reset the whole layer markers to add only that I am trying to update as the single marker on the whole layer, thus removing all old markers.
By trying to add multiple markers in GEOJson format as an array of GEOJson objects as shown below I get an error:
Uncaught Error: Input data is not a valid GeoJSON object.
code:
map.getSource('cafespots').setData([{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [31.331849098205566, 30.095422632059062]
},
"properties": {
"marker-symbol": "cafe"
}
},{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [31.39, 30.10]
},
"properties": {
"marker-symbol": "cafe"
}
}]);
Will appreciate it so much if someone can please help by telling me what I am doing wrong / missing here, thanks
setData expects a complete GeoJSON object (not just it's features) or a url pointing to a GeoJSON object.
You'll need to manage the state of the GeoJSON in your code and update the entire object via setData when a change is made.
var geojson = {
"type": "FeatureCollection",
"features": []
};
map.on('load', function() {
map.addSource('custom', {
"type": "geojson",
"data": geojson
});
// Add a marker feature to your geojson object
var marker {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [0, 0]
}
};
geojson.features.push(marker);
map.getSource('custom').setData(geojson);
});
https://www.mapbox.com/mapbox-gl-js/example/measure/ is a good example that demonstrates this behaviour.

Adding custom points to mapbox studio

In Mapbox studio classic, you just click where you want a new "marker" and it creates one. I want to do the same thing in the new mapbox studio but that feature doesn't seem to exist. Please note, I do not have a dataset to upload, I need to create a dataset through Mapbox Studio.
If anybody has any insight for me that would be super!
You can add your data to Mapbox Studio along with this custom svg marker. I styled it similar to the old Leaflet L.marker: https://github.com/Ccantey/icons/blob/master/svgs/placeMarker-Blue-Shadow.svg
Then in the layout properties you can set "marker-symbol"/"icon-image" to "myMarker-Blue-Shadow":
map.addSource("pointclick", {
"type": "geojson",
"data": {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [e.lngLat.lng, e.lngLat.lat]
},
"properties": {
"title": "mouseclick",
"marker-symbol": "myMarker-Blue-Shadow"
}
}
});
map.addLayer({
"id": "pointclick",
type: 'symbol',
source: 'pointclick',
"layout": {
"icon-image": "{marker-symbol}",
"icon-size":1,
"icon-offset": [0, -13]
},
"paint": {}
});