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];
});
});
Related
I am trying to request a static image of a map from Mapbox that has a polygon overlay.
I keep getting a 422 Unknown response.
Below is the url encoded geojson:
https://api.mapbox.com/styles/v1/mapbox/streets-v11/static/geojson(%7B%22type%22%3A%22FeatureCollection%22%2C%22features%22%3A%5B%7B%22id%22%3A%224c97769717bde5d3ece6aa37ad153a26%22%2C%22type%22%3A%22Feature%22%2C%22geometry%22%3A%7B%22type%22%3A%22Polygon%22%2C%22coordinates%22%3A%5B%5B%5B-97.35498290052888%2C47.07901887872825%5D%2C%5B-97.34567101592366%2C47.07901887872825%5D%2C%5B-97.34553174426712%2C47.06840297785641%5D%2C%5B-97.35539079875348%2C47.06965221312885%5D%2C%5B-97.36672817535712%2C47.069627161422176%5D%2C%5B-97.36668040297414%2C47.07906677293954%5D%2C%5B-97.35498290052888%2C47.07901887872825%5D%5D%5D%7D%2C%22properties%22%3A%7B%22title%22%3A%22%22%7D%7D%5D%7D)/auto,13/500x300?access_token=MY_MAPBOX_ACCESS_TOKEN
Below is the geojson structure I have stored in my database field that gets url encoded:
{
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[-98.38294, 47.06659],
[-98.38322, 47.05229],
[-98.36687, 47.05221],
[-98.36675, 47.06654],
[-98.38294, 47.06659]
]
]
},
"properties": {
"title": ""
}
}]
}
Any help would be greatly appreciated.
The error you receive back with this request is a descriptive one:
{"message":"The auto parameter cannot be used with additional location parameters, bearing, or pitch."}
The problem with this request is not your overlay data, but rather the fact that you are attempting to include additional position arguments after auto (e.g. /auto,13/) which is not supported.
If you remove ,13 from the request, then the image renders as expected:
I am closely following the example at this link at Mapbox documentation to add a pattern to a polygon. I have simply taken their code and added it to my map using an onClick event. It is very simple and basic. I am unable to figure out how to use my own data, though. They use manually entered coordinates. I wish to use my own local JSON file. How do I do this? Here is my code that works : (it is literally copied/pasted from the Mapbox tutorial, but this is my actual code that is working)
function test() {
// Add GeoJSON data
map.addSource('source', {
"type": "geojson",
"data": {
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [[
[-30, -25],
[-30, 35],
[30, 35],
[30, -25],
[-30, -25]
]]
}
}
});
// Load an image to use as the pattern
map.loadImage('https://upload.wikimedia.org/wikipedia/commons/thumb/6/60/Cat_silhouette.svg/64px-Cat_silhouette.svg.png', function(err, image) {
// Throw an error if something went wrong
if (err) throw err;
// Declare the image
map.addImage('pattern', image);
// Use it
map.addLayer({
"id": "pattern-layer",
"type": "fill",
"source": "source",
"paint": {
"fill-pattern": "pattern"
}
});
});
}
So, how do I use my own data? I have tried the following below and many (10+) variations and I can't get this to work. Below is just an example of what I am trying to do.
map.addSource('source', {
"type": "geojson",
"data": {
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"data": "folder/sample.json"
},
}
}
});
map.addSource('source', {
"type": "geojson",
"data": "folder/sample.json"
});
See https://docs.mapbox.com/mapbox-gl-js/style-spec/#sources-geojson
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":{...},
});
});
I have a GEOJSON which I added to the featuregroup in my Mapbox map like this:
var featureCollection = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {
"id": 1
},
"geometry": {
"type": "Point",
"coordinates": [0, 0]
}
},{
"type": "Feature",
"properties": {
"id": 2
},
"geometry": {
"type": "Point",
"coordinates": [30, 30]
}
},{
"type": "Feature",
"properties": {
"id": 3
},
"geometry": {
"type": "Point",
"coordinates": [-30, -30]
}
}]
};
var geojson = L.geoJson(featureCollection);
var featureGroup = L.featureGroup().addTo(map);
featureGroup.addLayer(geojson);
Now, I wish to access the id property of each layer while looping through the featuregroup, so that I can pass it as an argument to another function. In the case of a featurelayer, I can easily access it using something like this:
var featureLayer = L.mapbox.featureLayer(featureCollection).addTo(map);
featureLayer.eachLayer(function (layer) {
layer.on('click', function (e) {
console.log('Clicked feature ID: ' + e.target.feature.properties.id);
});
});
But I want to be able to access it while looping inside a featuregroup, and also I want to be able to do it without a 'click' or any such event. For example, ideally I would use something like this:
featureGroup.eachLayer(function (layer) {
var id = layer.feature.properties.id;
testfunction(id);
});
I haven't been able to figure out how to do that. I've tried searching online, but because I'm new to this, I probably haven't been using the right keywords in my search.
geojson is nested within featureGroup, so when your eachLayer function runs, it is not operating on the individual features within geojson, but instead on geojson itself. To extract each feature's id property, you will need to go one level deeper and iterate over the features within geojson.
Fortunately, the L.GeoJson class also supports the eachLayer method (because it is an extension of L.FeatureGroup, which is itself an extension of L.LayerGroup). To print the id of each feature, you could just use the eachLayer method directly on geojson:
geojson.eachLayer(function (layer) {
var id = layer.feature.properties.id;
testfunction(id);
});
Or, if you have a bunch of L.GeoJson objects nested within featureGroup, you can use:
featureGroup.eachLayer(function (layer) {
layer.eachLayer(function (layer) {
var id = layer.feature.properties.id;
testfunction(id);
});
});
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.