saving and retrieving leaflet.js based non geographical map - javascript

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.

Related

When cutting a polygon with a polyline the geometry engine will group certain peices together?? Arcgis javascript api

When preforming a cut action on a polygon with a polyline, some of the returned geometries are grouped while others are not?
I have a simple program where the user can create a polygon with a SketchViewModel. Then the user creates a polyline with a SketchViewModel. I then take the geometry from each sketch and preform a cut from the geometryEngine. I get an array of geometries from the cut and add them to the layer while removing the original polygon and polyline. I would expect to get each subdivided piece individually but for some reason some get grouped together as one geometry even if they're not connected.
//polylineLayer and polygonLayer are graphiclayers
//submit is a html button to call the execution
submit.addEventListener("click", function() {
//subDivisions is an Geometry[] for the produced geometries
//ex. one line through a circle polygon would produce
// two geometries of each half. (this works)
// anything more complicated starts having grouping issues
// (see pictures)
var subDivisions =
geometryEngine.cut(polygonLayer.graphics.getItemAt(0).geometry,
polylineLayer.graphics.getItemAt(0).geometry);
polygonLayer.removeAll();
polylineLayer.removeAll();
//show the number of subdivisions
alert("size: " + subDivisions.length);
// add created geometries to the graphiclayer
for (var i = 0; i < subDivisions.length; i++){
tempGraphic = new Graphic ({
geometry: subDivisions[i]
});
polygonLayer.graphics.add(tempGraphic,i);
}
});
(sorry for the links to photos I don't have 10 reputation to post photos and this is a very visual project/issue)
Open screen:
https://ibb.co/WDcgmSn
Draw first polygon:
https://ibb.co/wd6CDbV
Draw polyline to cut polygon:
https://ibb.co/BG32863
Expected subdivisions - 10 Actual - 7:
https://ibb.co/0VMsHGg
Some are split into individual polygons:
https://ibb.co/SKXCJR8
Others are not:
https://ibb.co/7WqNB9q
All broken up pieces:
https://ibb.co/Pr0smrw
Wish I could comment instead of just answer but hard to say with out code.
Basically you are getting multipart polygons, you need to break those up.
Use a split in your array to break up the multi-part polygons split("]],[[")
Simplify Polygons using a geometry service would be worth a shot too. (before and after cutting)
https://developers.arcgis.com/rest/services-reference/geometry-service.htm

Changing the order of long lat from geojson file in js

I'm trying to get points out of a geojson file but the coordinate of the points are in the opposite way instead of (x,y) as opposed to (y,x).
On the map I am getting a place that is not really on the map.
How can i get it right in javascript?
This is my code that takes out the points and binds a popup for each point on a map:
jQuery.getJSON("data/london_pois.geojson",function(data){
// add GeoJSON layer to the map once the file is loaded
L.geoJson(data,{
onEachFeature: function (feature, layer) {
layer.bindPopup(feature.properties.name);
}
}).addTo(map);
});
I realized that my issue was not a programming issue, but rather the data set was too large.
After removing a some entries, everything worked fine.

How to have multiple data layers in Google Maps?

Is it possible to have multiple data layers using Google Maps API? The only existing related question I could find was this.
Here's my problem.
I want to have a data layer for showcasing polygons on map that are being drawn by the user. At the same time I want to have another data layer that displays polygons that already exist in a database.
I figured I would do this by creating 2 data layers:
drawLayer = new google.maps.Data();
savedLayer = new google.maps.Data();
But when I initialize the drawing tools using drawLayer.setControls(['Polygon']), it doesn't work. If I replace the drawLayer with map.data, then the drawing tools works fine. Why is that?
JSFiddle: http://jsfiddle.net/pjaLdz6w/
In your fiddle you aren't declaring drawLayer as a google.maps.Data object. But even if you do, you still need to give it a map attribute:
drawLayer = new google.maps.Data({map:map});
JSFiddle: http://jsfiddle.net/jbyd815y/

Leaflet.js - Fit geoJSON co-ordinates on map view

I have a leaflet.js map that has points and linestrings on it that come from an external JSON file.
If I add:
map.setView(new L.LatLng(0,0), 10);
It will centre the map on the latitude and longitude 0,0. How can I set it so the map centre and zoom fit all of the points from the JSON on it?
You could add all of your layers to a FeatureGroup which has a getBounds method. So you should be able to just say myMap.fitBounds(myFeatureGroup.getBounds());
The getBounds method for L.FeatureGroup is only available in the master branch (not the latest version, 0.3.1), for now at least.
Similar case with me. I drawn all the markers from GeoJson data. So I written the function, which gets called repeatedly on button click. Just try if it suits your requirements.
function bestFitZoom()
{
// declaring the group variable
var group = new L.featureGroup;
// map._layers gives all the layers of the map including main container
// so looping in all those layers filtering those having feature
$.each(map._layers, function(ml){
// here we can be more specific to feature for point, line etc.
if(map._layers[].feature)
{
group.addLayer(this)
}
})
map.fitBounds(group.getBounds());
}
The best use of writing this function is that even state of map/markers changed, it will get latest/current state of markers/layers. Whenever this method gets called all the layers will be visible to modest zoom level.
I needed to do this when showing a user directions from his origin to a destination. I store my list of directions in an array of L.LatLng called directionLatLngs then you can simply call
map.fitBounds(directionLatLngs);
This works because map.fitBounds takes a L.LatLngBounds object which is just an array of L.LatLng
http://leafletjs.com/reference.html#latlngbounds

OpenLayers, and GeoJSON, not multiply marker on same coordinates

My code is showing markers from GeoJSON, when I'm haved zoomed into zoom-level 10,it load the GeoJSON-file, but how do I avoid to reput out the same markers?
Is there a way to check if there already exist a marker on a specific place?
The code
map.events.register("zoomend", null, function(){
if(map.zoom == 10)
{
var bounds = map.getExtent();
console.log(bounds);
var ne = new OpenLayers.LonLat(bounds.right,bounds.top).transform(map.getProjectionObject(),wgs84);
var sw = new OpenLayers.LonLat(bounds.left,bounds.bottom).transform(map.getProjectionObject(),wgs84);
var vectorLayer = new OpenLayers.Layer.Vector();
map.addLayer(vectorLayer);
$.getJSON('ajax.php?a=markers&type=json&sw=('+sw.lon+','+sw.lat+')&ne=('+ne.lon+','+ne.lat+')',function(data){
//$.getJSON('test.json',function(data){
var geojson_format = new OpenLayers.Format.GeoJSON({
'externalProjection': wgs84,
'internalProjection': baseProjection
});
vectorLayer.addFeatures(geojson_format.read(data));
});
}
});
Why not use the BBOX Strategy [1] ?
That will do what you need, and will for sure be more performant (it will delete existing features and reload new ones on zoomend). Comparing features to add new will need a lot of comparison, and you can end with too much features on your map.
Check out the js source of the example.
HTH,
1 - http://openlayers.org/dev/examples/strategy-bbox.html
EDIT: if you want to change less code, a call to vectorLayer.removeAllFeatures() before adding will solve your problem… Do you really need to keep features out of bound?
First you would need to get the layer off the map using something like map.getLayersByName. Then you can iterate over layer.features to look for the feature you are adding.
If you can modify the backend to use BBOX, then the BBOX strategy with zoom level and projection settings would take care of a lot for you.

Categories