coordstoLatLng function not returning array [duplicate] - javascript

I have my geoJson format like this:
statesData.features.push({
"type":"Feature",
"id":"AFG",
"properties":{
"name":"Afghanistan"
},
"geometry":{
"type":"Polygon",
"coordinates":[
[
[
61.210817,
35.650072
],
[
62.230651,
35.270664
],
[
62.984662,
35.404041
],
I am trying to read those coordinates and set them as
var coord = statesData.features[0].geometry.coordinates;
lalo = L.GeoJSON.coordsToLatLng(coord);
map.setView(lalo, 18);
The documentation says:
coordsToLatLng( coords ) Function that will be used for
converting GeoJSON coordinates to LatLng points (if not specified,
coords will be assumed to be WGS84 — standard [longitude, latitude]
values in degrees).
But I am getting this error in console
Uncaught Error: Invalid LatLng object: (undefined,
61.210817,35.650072,62.230651,35.270664,62.984662,35.404041...
UPDATE
The first answer is correct as it solves the issue above, however, it zooms the map to the first set of coordinates while what I am really trying to achieve is to be able to load the page with the map auto zoomed to a polygon (I only load one polygon).
This example is the closest i could find

Thanks to the answer I got from here the solution is to use leaflet layerGroup.
Following leaflet example as that is what I am using, based on their code and the other answer i got, this is what worked for me. The php bit is what I use to get the country name I need as per my project. The following gets a name, compares it if there is a name in the geoJson like that and if so, centers and zooms the map to that polygon:
geojson = L.geoJson(statesData, {
style: style,
onEachFeature: onEachFeature
}).addTo(map);
<?php
$myCountry = usp_get_meta(false, 'usp-custom-3');
$fixedname = ucfirst($myCountry);
?>
geojson.eachLayer(function (layer) {
if (layer.feature.properties.name === "<?php echo $fixedname; ?>") {
// Zoom to that layer.
map.fitBounds(layer.getBounds());
}
});

You are passing an array of arrays of arrays as a parameter. coordsToLatLng doesn't expect that. It only expects one array, being it the coordinates: https://www.dartdocs.org/documentation/leaflet/0.0.1-beta.1/leaflet.layer/GeoJSON/coordsToLatLng.html
So your code has to be actually:
var coord = statesData.features[0].geometry.coordinates[0][0];
lalo = L.GeoJSON.coordsToLatLng(coord);
map.setView(lalo, 18);
This will get the coordinates of your first point inside your double-array. Btw, I'm pretty sure that double-array is not what you really want.

Related

Input geometry is not a valid Polygon in turf.js

I try to use turf.js and its function intersect in my Leaflet project. My original question can be found here. The problem is I cannot get a proper polygon in order to call it. The idea is to get the waypoints of the calculated route make a polgyon out of them and check where they intersect with a given buffered area.
var testpoint = turf.point([9.9354, 49.799]);
var buffered = turf.buffer(testpoint, 50, {units: 'meters'});
var array = []
control._routes[0]['coordinates'].forEach(function(e){
array.push([e['lat'],e['lng']])
});
var test = turf.polygon(L.polygon([[array]]))
var intersection = turf.lineIntersect(buffered, test)
I am getting the following error message:
Uncaught Error: Input geometry is not a valid Polygon or MultiPolygon
Here I have to point out that, when using line.intersect(buffered,buffered) it is working correctly, therefore I am assuming that the buffered variable is correct.
When it comes down to the test variable, I have tried with no [], one pair and double pair. But they all result in the same problem. I also tried to pass the array to turf.polygon but it couldn`t be done.

saving and retrieving leaflet.js based non geographical map

I have a SVG based non geographical layout with image overlay.
var map = L.map('map', {
crs: L.CRS.Simple
});
var bounds = [[0,0], [1000,1000]];
var image = L.imageOverlay('uqm_map_full.png', bounds).addTo(map);
map.fitBounds(bounds);
I traced out different shapes on top of this image.
Now i want to retrieve all the shapes drawn, as a json object array and save it to database. Requirement is to replicate the same shapes later some point by fetching the json object array from database. Is it possible in leaflet.js? I want some thing like below
L.getObjectsArray(map) will give me
var leafletAllShapesConfig = [Object1,Object2,Object3,Object4,Object5]
Now reading the object array i can be able to draw the same shapes like L.draw(leafletAllShapesConfig).
Is this possible and any in built method available to achieve the same? If not please give some idea how can i achieve that.
Yes Leaflet has a built in method: L.GeoJson()
Put your shapes into a featuregroup instead to the map.
var fg = L.featureGroup().addTo(map);
L.marker(latlng,options).addTo(fg);
Then you can get the geojson from the featuregroup:
var gjson = fg.toGeoJSON()
Now you can save this geojson as string with: var str = JSON.stringify(gjson)
To add the shapes back to the map use:
var json = JSON.parse(str);
fg.clearLayers() //To clean the map from the shapes
L.geoJSON(json, {
onEachFeature: function(feature, layer) {
//Code
}
}).addTo(fg);
Now you have your shapes back on your map, but without options/properties like color. GeoJson don't convert them too. You can solve this problem by looping through the layers in the featuregroup and add them manually to the gjson and add the layer.options to the gjson.properties.options and later by adding to the map, read the options from gjson out.
After some research over leaflet.js, i figured out an event "pm:drawend" from "geoman-io/leaflet-geoman-free" plugin Github link https://github.com/geoman-io/leaflet-geoman
map.on('pm:drawend', e => {
console.log(e); //Gives array of all shapes including background image and SVG
});
Above snippet gives me an array of all shapes available(including background image and SVG container), the moment i finish adding any active shape. For reference including the output snippet here which served my purpose.
By default leaflet includes background image as first item. Then follows the SVG container(where my map resides), then all shapes.Hope this will be use to some one else.

Add circle to map with carto.js and leaflet libraries

I have to show a circle on feature click on my layer.
When I try to create the circle I have this error: Error: Invalid LatLng object: (41.961124103390674, NaN).
If I print the object before this error I can read: Array [ 41.84664960937685, 12.008056640625 ].
I tried to write values separated but it doesn't work.
How is it possible?
Someone can help me? Thanks and sorry for my english
EDIT
I tried this solution:
layer.getSubLayer(1).on('featureClick', function (event, latlon, pos, data, index) {
var coord = {lat:data.lat, lng:data.lon};
console.log(coord)
L.circle(coord, {radius: data.distance}).addTo(map);
Error and log are the same...
EDIT 2
With this code
var coord = L.latLng(42,21);
var cerchio = L.circle(coord,{radius: data.distance});
console.log(cerchio);
cerchio.addTo(map);
I noticed that circle Object is correctly created, so the problem is on addTo(map) method.
According to the Carto Docs, the latlon argument in your featureClick callback contains:
Array with the LatLng ([lat,lng]) where the layer was clicked.
Is that where you want the circle to be placed? If so, use this line:
L.circle(latlon, {radius: data.distance}).addTo(map);
SOLVED
The correct way is
L.circle([data.lat, data.lon], data.distance, {}).addTo(map);
where data.distance is the radius of circle. Official doc's example L.circle([50.5, 30.5], {radius: 200}).addTo(map); seems to be wrong.
Add 1609*3
var coord = L.latLng(42,21,1609*3);

Can I change the fillColor of a GeoJSON LineString with LeafLet

I have a GeoJSON full of LineStrings (elevation contours), which I'd like to plot on a MapBox/LeafLet map.
When plotted, all LineStrings seem to form polygons (i.e. first and last coordinates in the array are equivalent).
Is it possible to change the fillColor of the LineStrings, given they look like polygons anyway?
EDIT
Below is the code I currently have:
var elevation950Style = {
color : "yellow",
fillColor : "yellow",
opacity : 0.4,
weight : 2,
};
$.getJSON('950.geo.json', function(file) {
L.geoJson( file , { style: elevation950Style } ).addTo(map);
});
It is certainly possible.
A good approach would probably be first to make sure your Line String is really a loop (as you say, if first and last coordinates are equal). Then simply convert it into a Polygon (create a new Polygon based on the same coordinates, remove the Line String), and it will be filled by Leaflet according to your fillColor option.
EDIT:
You could detect looped line strings after they are created by the L.geoJson() factory, create an equivalent GeoJSON feature with polygon geometry, and replace the looped line string by the newly created polygon within your GeoJSON layer group:
var myGeoJsonGroup = L.geoJson(myGeoJsonData), // build your GeoJSON layer group.
geo, coords, first, last;
myGeoJsonGroup.eachLayer(function (layer) {
geo = layer.feature.geometry;
coords = geo.coordinates;
first = coords[0];
last = coords[coords.length - 1];
if (geo.type === "LineString" && first[0] === last[0] && first[1] === last[1]) {
myGeoJsonGroup.removeLayer(layer);
myGeoJsonGroup.addData({
type: "Feature",
properties: layer.feature.properties,
geometry: {
type: "Polygon",
coordinates: [
coords // exterior linear ring
]
}
});
}
});
myGeoJsonGroup.addTo(map);
Disclaimer: written as-is, not tested.
Note: in your case, you will certainly have elevation contours one within another. You may wish to build polygons with holes for the embedded contours. Otherwise, the fillings will stack, and you may not get your desired result if they are transparent.
If plotting line is the only criteria as SVG please check geojson2svg. You can just use CSS class in SVG path element or basic SVG's style. Check detailed examples here for understanding of this small module.
Disclaimer: I am author of geojson2svg

mapbox fit bounds to country

i just want fit my map to my country. I saw some example from https://www.mapbox.com/mapbox-gl-js/example/fitbounds/ and it's fit to whole Kenya. It's a simple code but i don't know why this function takes two lat and longs. I just google it for what is Keyna lat and long? it's 1.2667° S, 36.8000° E. Why this is different than google's result.
function fit() {
map.fitBounds([[
32.958984,
-5.353521
], [
43.50585,
5.615985
]]);
}
How to fit to my specific area just like this.
If i search for the bounding box of Kenya, i find the following:
http://isithackday.com/geoplanet-explorer/index.php?woeid=23424863
Using those coordinates, it's looks ok:
map.fitBounds([
[-4.71712, 33.90884], // Northeast
[4.62933, 41.899059] // Southwest
]);
Example using Leaflet on Plunker: http://plnkr.co/edit/yRuTxjmQxcoqkVyFbE4q?p=preview
.fitBounds takes two latlng arguments, one for the upper-left corner of the mapview and one for the lower-right corner.
If you would like to just center the map on Kenya, you could use:
map.flyTo({center: [Lat, Lng]})
I also was looking for the answer on this question. Leaflet, for example, has a property of a layer to get its bounds (e.g.,map.fitBounds(layer.getBounds());). Mapbox GL doesn't have anything like that. At least not that I know. To handle this you may access the first and the last coordinates of the currently selected feature: map.fitBounds([feature.geometry.coordinates[0], feature.geometry.coordinates[feature.geometry.coordinates.length-1]]).
Here is the whole piece of code in case you want to have a popup with a Zoom button on it:
map.on('click', function (e) {
map.featuresAt(e.point, {layer: 'route-lines', radius: 10, includeGeometry: true}, function (err, features) {
if (err || !features.length)
return;
var feature=features[0];
new mapboxgl.Popup()
.setLngLat(e.lngLat)
.setHTML(popupTemplate)
.addTo(map);
var buttonZoomFeature = document.getElementById('button-zoom');
buttonZoomFeature.addEventListener('click', function (e) {
map.fitBounds([feature.geometry.coordinates[0], feature.geometry.coordinates[feature.geometry.coordinates.length-1]]);
});
});
});
var popupTemplate = '<div id="popup-div">\
<button id="button-zoom" class="button-zoom" type="button">Zoom to</button>\
</br>\
</div>';
PS. This approach works fine when the layer is a number of lines (roads, for example). If you want to fit the bounds to a country, which is a polygon, you may try taking the first longitude-latitude point as the one that has min latitude and for the second point the one that has max longitude. Or something like that. Just try to play around with this approach. I am sure it will work out.

Categories