Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Saving and restoring drawn objects #253

Closed
grg9999 opened this issue Dec 26, 2013 · 35 comments
Closed

Saving and restoring drawn objects #253

grg9999 opened this issue Dec 26, 2013 · 35 comments

Comments

@grg9999
Copy link

grg9999 commented Dec 26, 2013

Leaflet.draw is awesome, but I need to save and restore the drawn objects.

I can get JSON for the layer by a somewhat cumbersome iteration in draw:created.

But I don't see an obvious way to go from JSON to objects on the map.

So two questions:

Is there a built-in way to get JSON representation of the objects?

Is there a way to go from JSON to objects on the may?

Thanks.

@Zverik
Copy link
Contributor

Zverik commented Dec 27, 2013

var drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
....
// get json
var json = drawnItems.toGeoJSON();

geojson → objects can be done by adding L.GeoJson layer and pointing Leaflet.draw at it.

Also you can iterate over drawn objects with drawnItems.eachLayer() method and add any objects to the layer.

@AndriusGeo
Copy link

I really like leaflet and draw plugin, but i'm stuck with saving and restoring drawn data. When I save drawn data to geojson, this geojson has no color and other properties, so when I restoring data with L.GeoJson I get only geometry with basic style. How can I describe style of drawn objects in geojson to load them later correctly?

Thank you.

@jacobtoye
Copy link
Member

Leaflet.draw handles drawing and editing Leaflet vector and marker objects.

Leaflet allows you to convert GeoJSON to a Leaflet vector objects. Check out the documentation on L.GeoJson, this should help you find out how to style your vectors.

@AndriusGeo
Copy link

Thank you for the quick response but L.GeoJson not solve my problem. In L.Control.Draw I use shapeOptions (color, weight) for lines and polygons, also marker icons.

var drawControl = new L.Control.Draw({
                draw: {
                polyline: {
                    shapeOptions: {
                        color: $userPolylineColor,
                        weight: 10
                    }
                },
                polygon: {
                    allowIntersection: false,
                    drawError: {
                        color: '#e1e100'
                    },
                    shapeOptions: {
                        color: $userPolygonColor
                    }
                },
                circle: false,
                rectangle: {
                    shapeOptions: {
                        clickable: false
                    }
                },
                marker: {
                    icon: markerIcon
                }
            },
            edit: {
                featureGroup: drawnItems
            }
        });
        map.addControl(drawControl);

User can change these options, so user can draw lines, polygons in different colors, choose different marker icons etc. and for that I use drawControl.setDrawingOptions();.

Everything works, but when I put all these drawn objects in json like that var json = drawnItems.toGeoJSON();, this json doesn't have information about each drawn object style. So when I convert saved GeoJSON to Leaflet vector objects again with L.GeoJson I doesn't have color, marker and other properties. So the question is how to put all color, icons etc information of drawn objects in geojson.

@jacobtoye
Copy link
Member

Ah I see what you mean. If you check out the Leaflet code for L.LayerGroup.toGeoJSON() https://github.com/Leaflet/Leaflet/blob/master/src/layer/GeoJSON.js#L241 it doesn't look like it saves the style. I imagine this is because a geometry's style is not part of the GeoJSOn spec.

You could open an issue on the Leaflet github or check out mapbox.js (this wraps the LEaflet.js library) to see how they achieve serializing the style in GeoJSON (https://github.com/mapbox/mapbox.js/blob/master/src/feature_layer.js).

@AndriusGeo
Copy link

Thank you for response. Unfortunately as you said geometry style really is not part of the geoJson spec.

But I found a solution. For collecting geometry style I create geoJson of drawn objects var usersObjectsJson = drawnItems.toGeoJSON();, then I use eachLayer(); and add manually geometry style properties to geoJson. Drawn objects style properties I can access just like that layer.options.color;. So now it works, but I think it will be much, much easier if toGeoJSON(); function could add geometry style to geojson.

@iBrian71
Copy link

If you could post an example of that it would be appreciated. I am looking at doing the same thing..
Came to the same conclusion but not sure exactly how to do it.

@che-wf
Copy link

che-wf commented Jun 22, 2015

@AndriusGeo I am running into a similar issue on a project I'm working on. Perhaps you may be able to point me in the right direction. Currently, I'm using the toGeoJSON() function to save my drawn objects. However, GeoJSON doesn't seem to accommodate circles. What did you end up doing for those? Also, how did saving the styles end up going for you? Did you end up going with eachLayer() as you alluded to? Thanks!

@nmccready
Copy link

Having this same problem; does anyone have an example?

@nmccready
Copy link

Looking around I found this stackoverflow and this example.

Kinda sucks that circle properties are not saved off by default. So extra work needs to be done to save of shape properties besides just doing toGeoJSON.

@iBrian71
Copy link

I am back to working on this again. I can get the style attributes out but I am yet to get that and the geoJSON together where multiple items are drawn with different styles.

            var ditemsOut = '';
            var ditems = drawnItems.getLayers();
            var iIndex = 0;
            console.log(ditems);
            //for (itemsIndex = 0; itemsIndex < ditems.length; ++itemsIndex) {
            //    ditemsOut = ditemsOut + ditems[itemsIndex].options.clickable + '\n';
            //}
            for (iIndex = 0; iIndex < ditems.length; ++iIndex) {
                if (ditems[iIndex]._leaflet_id) { console.log('Item ID: ' + ditems[iIndex]._leaflet_id) };
                if ('clickable' in ditems[iIndex].options) { console.log('Clickable: ' + ditems[iIndex].options.clickable) };
                if ('color' in ditems[iIndex].options) { console.log('Color: ' + ditems[iIndex].options.color) };
                if ('fill' in ditems[iIndex].options) { console.log('Fill: ' + ditems[iIndex].options.fill) };
                if ('opacity' in ditems[iIndex].options) { console.log('Opacity: ' + ditems[iIndex].options.opacity) };
                if ('stroke' in ditems[iIndex].options) { console.log('Stroke: ' + ditems[iIndex].options.stroke) };
                if ('weight' in ditems[iIndex].options) { console.log('Weight: ' + ditems[iIndex].options.weight) };
                if ('fillColor' in ditems[iIndex].options) { console.log('FillColor: ' + ditems[iIndex].options.fillColor) };
                if ('fillOpacity' in ditems[iIndex].options) { console.log('FillOpacity: ' + ditems[iIndex].options.fillOpacity) };
                if ('icon' in ditems[iIndex].options) {
                    if ('options' in ditems[iIndex].options.icon) {
                        if ('iconSize' in ditems[iIndex].options.icon.options) { console.log('IconSize0: ' + ditems[iIndex].options.icon.options.iconSize[0]) };
                        if ('iconSize' in ditems[iIndex].options.icon.options) { console.log('IconSize1: ' + ditems[iIndex].options.icon.options.iconSize[1]) };
                        if ('iconurl' in ditems[iIndex].options.icon.options) { console.log('IconUrl: ' + ditems[iIndex].options.icon.options.iconUrl) };
                    };
                };
                if ('_icon' in ditems[iIndex].options) { console.log('_Icon: ' + ditems[iIndex].options._icon) };
                if ('_shadow' in ditems[iIndex].options) { console.log('_Shadow: ' + ditems[iIndex].option._shadow) };
            };

@iBrian71
Copy link

iBrian71 commented Apr 28, 2017

And there it is. This will get all the information you require. Just decide if you save the style components in a separate field or as a style attribute of the geoJSON.
From this I will just build a generator for the geoJSON using theses options.

            var ditemsOut = '';
            var ditems = drawnItems.getLayers();
            var iIndex = 0;
            console.log(ditems);
            for (iIndex = 0; iIndex < ditems.length; ++iIndex) {
                if (ditems[iIndex]._leaflet_id) { console.log('Item ID: ' + ditems[iIndex]._leaflet_id) };
                if ('clickable' in ditems[iIndex].options) { console.log('Clickable: ' + ditems[iIndex].options.clickable) };
                if ('color' in ditems[iIndex].options) { console.log('Color: ' + ditems[iIndex].options.color) };
                if ('fill' in ditems[iIndex].options) { console.log('Fill: ' + ditems[iIndex].options.fill) };
                if ('opacity' in ditems[iIndex].options) { console.log('Opacity: ' + ditems[iIndex].options.opacity) };
                if ('stroke' in ditems[iIndex].options) { console.log('Stroke: ' + ditems[iIndex].options.stroke) };
                if ('weight' in ditems[iIndex].options) { console.log('Weight: ' + ditems[iIndex].options.weight) };
                if ('fillColor' in ditems[iIndex].options) { console.log('FillColor: ' + ditems[iIndex].options.fillColor) };
                if ('fillOpacity' in ditems[iIndex].options) { console.log('FillOpacity: ' + ditems[iIndex].options.fillOpacity) };
                if ('icon' in ditems[iIndex].options) {
                    if ('options' in ditems[iIndex].options.icon) {
                        if ('iconSize' in ditems[iIndex].options.icon.options) { console.log('IconSize0: ' + ditems[iIndex].options.icon.options.iconSize[0]) };
                        if ('iconSize' in ditems[iIndex].options.icon.options) { console.log('IconSize1: ' + ditems[iIndex].options.icon.options.iconSize[1]) };
                        if ('iconurl' in ditems[iIndex].options.icon.options) { console.log('IconUrl: ' + ditems[iIndex].options.icon.options.iconUrl) };
                    };
                };
                if ('_icon' in ditems[iIndex].options) { console.log('_Icon: ' + ditems[iIndex].options._icon) };
                if ('_shadow' in ditems[iIndex].options) { console.log('_Shadow: ' + ditems[iIndex].option._shadow) };
                if (ditems[iIndex] instanceof L.Polyline) { console.log('Type: LineString') };
                if (ditems[iIndex] instanceof L.Polygon) { console.log('Type: Polygon') };
                if (ditems[iIndex] instanceof L.Point) { console.log('Type: Point') };
                if (ditems[iIndex] instanceof L.Marker) { console.log('Type: Point') };
            };

@iBrian71
Copy link

iBrian71 commented May 2, 2017

And a function to get the items as geoJSON with the style included
Just pass the layer to the function

function drawnItemsToJSON(ilayer) {

    var dOut = '';
    var dOut1 = '';
    var dOut2 = '';
    var ditems = ilayer.getLayers();
    dOut = '{"type":"FeatureCollection","features":[';
    for (iIndex = 0; iIndex < ditems.length; ++iIndex) {
        if (ditems[iIndex] instanceof L.Point || ditems[iIndex] instanceof L.Marker) {
            dOut1 = dOut1 + ',{"type":"Feature","properties":{';
            if ('icon' in ditems[iIndex].options) {
                if ('options' in ditems[iIndex].options.icon) {
                    dOut1 = dOut1 + '"markerOptions":{';
                    dOut2 = '';
                    if ('iconSize' in ditems[iIndex].options.icon.options) { dOut2 = dOut2 + ',"iconSize":[' + ditems[iIndex].options.icon.options.iconSize[0] + ',' + ditems[iIndex].options.icon.options.iconSize[0] + ']' };
                    if ('iconUrl' in ditems[iIndex].options.icon.options) { dOut2 = dOut2 + ',"iconUrl":"' + ditems[iIndex].options.icon.options.iconUrl + '"' };
                    dOut1 = dOut1 + dOut2.substring(1) + '}';
                };
            };
            dOut1 = dOut1 + '},"geometry":{"type":"Point","coordinates":['
                + ditems[iIndex]._latlng.lng
                + ',' + ditems[iIndex]._latlng.lat
                + ']},"style":{';
            dOut2 = '';
            if ('stroke' in ditems[iIndex].options) { if (!ditems[iIndex].options.stroke !== null) { dOut2 = dOut2 + ',"stroke":' + ditems[iIndex].options.stroke } };
            if ('color' in ditems[iIndex].options) { if (ditems[iIndex].options.color !== null) { dOut2 = dOut2 + ',"color":"' + ditems[iIndex].options.color + '"' } };
            if ('weight' in ditems[iIndex].options) { if (!ditems[iIndex].options.weight !== null) { dOut2 = dOut2 + ',"weight":' + ditems[iIndex].options.weight } };
            if ('opacity' in ditems[iIndex].options) { if (!ditems[iIndex].options.opacity !== null) { dOut2 = dOut2 + ',"opacity":' + ditems[iIndex].options.opacity } };
            if ('fill' in ditems[iIndex].options) { if (!ditems[iIndex].options.fill !== null) { dOut2 = dOut2 + ',"fill":' + ditems[iIndex].options.fill } };
            if ('fillColor' in ditems[iIndex].options) { if (!ditems[iIndex].options.fillColor !== null) { dOut2 = dOut2 + ',"fillColor":"' + ditems[iIndex].options.fillColor + '"' } };
            if ('fillOpacity' in ditems[iIndex].options) { if (!ditems[iIndex].options.fillOpacity !== null) { dOut2 = dOut2 + ',"fillOpacity":' + ditems[iIndex].options.fillOpacity } };
            if ('fillRule' in ditems[iIndex].options) { if (!ditems[iIndex].options.fillRule !== null) { dOut2 = dOut2 + ',"fillRule":"' + ditems[iIndex].options.fillRule + '"' } };
            if ('dashArray' in ditems[iIndex].options) { if (!ditems[iIndex].options.dashArray !== null) { dOut2 = dOut2 + ',"dashArray":"' + ditems[iIndex].options.dashArray + '"' } };
            if ('lineCap' in ditems[iIndex].options) { if (!ditems[iIndex].options.lineCap !== null) { dOut2 = dOut2 + ',"lineCap":"' + ditems[iIndex].options.lineCap + '"' } };
            if ('lineJoin' in ditems[iIndex].options) { if (!ditems[iIndex].options.lineJoin !== null) { dOut2 = dOut2 + ',"lineJoin":"' + ditems[iIndex].options.lineJoin + '"' } };
            if ('clickable' in ditems[iIndex].options) { if (!ditems[iIndex].options.clickable !== null) { dOut2 = dOut2 + ',"clickable":' + ditems[iIndex].options.clickable } };
            if ('pointerEvents' in ditems[iIndex].options) { if (!ditems[iIndex].options.pointerEvents !== null) { dOut2 = dOut2 + ',"pointerEvents":"' + ditems[iIndex].options.pointerEvents + '"' } };
            if ('className' in ditems[iIndex].options) { if (!ditems[iIndex].options.className !== null) { dOut2 = dOut2 + ',"className":"' + ditems[iIndex].options.className + '"' } };

            if (dOut2.length > 1) {
                dOut1 = dOut1 + dOut2.substring(1) + '}';
            };
            dOut2 = '';
            dOut1 = dOut1 + '}';
        } else if (ditems[iIndex] instanceof L.Polygon) {
            dOut1 = dOut1 + ',{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[['
            dOut2 = '';
            for (ll = 0; ll < ditems[iIndex]._latlngs[0].length; ll++) {
                dOut2 = dOut2 + ',[' + ditems[iIndex]._latlngs[0][ll].lng + ',' + ditems[iIndex]._latlngs[0][ll].lat + ']';
            };
            dOut2 = dOut2 + ',[' + ditems[iIndex]._latlngs[0][0].lng + ',' + ditems[iIndex]._latlngs[0][0].lat + ']';
            dOut1 = dOut1 + dOut2.substring(1) + ']]},"style":{';
            dOut2 = '';
            if ('stroke' in ditems[iIndex].options) { if (!ditems[iIndex].options.stroke !== null) { dOut2 = dOut2 + ',"stroke":' + ditems[iIndex].options.stroke } };
            if ('color' in ditems[iIndex].options) { if (ditems[iIndex].options.color !== null) { dOut2 = dOut2 + ',"color":"' + ditems[iIndex].options.color + '"' } };
            if ('weight' in ditems[iIndex].options) { if (!ditems[iIndex].options.weight !== null) { dOut2 = dOut2 + ',"weight":' + ditems[iIndex].options.weight } };
            if ('opacity' in ditems[iIndex].options) { if (!ditems[iIndex].options.opacity !== null) { dOut2 = dOut2 + ',"opacity":' + ditems[iIndex].options.opacity } };
            if ('fill' in ditems[iIndex].options) { if (!ditems[iIndex].options.fill !== null) { dOut2 = dOut2 + ',"fill":' + ditems[iIndex].options.fill } };
            if ('fillColor' in ditems[iIndex].options) { if (!ditems[iIndex].options.fillColor !== null) { dOut2 = dOut2 + ',"fillColor":"' + ditems[iIndex].options.fillColor + '"' } };
            if ('fillOpacity' in ditems[iIndex].options) { if (!ditems[iIndex].options.fillOpacity !== null) { dOut2 = dOut2 + ',"fillOpacity":' + ditems[iIndex].options.fillOpacity } };
            if ('fillRule' in ditems[iIndex].options) { if (!ditems[iIndex].options.fillRule !== null) { dOut2 = dOut2 + ',"fillRule":"' + ditems[iIndex].options.fillRule + '"' } };
            if ('dashArray' in ditems[iIndex].options) { if (!ditems[iIndex].options.dashArray !== null) { dOut2 = dOut2 + ',"dashArray":"' + ditems[iIndex].options.dashArray + '"' } };
            if ('lineCap' in ditems[iIndex].options) { if (!ditems[iIndex].options.lineCap !== null) { dOut2 = dOut2 + ',"lineCap":"' + ditems[iIndex].options.lineCap + '"' } };
            if ('lineJoin' in ditems[iIndex].options) { if (!ditems[iIndex].options.lineJoin !== null) { dOut2 = dOut2 + ',"lineJoin":"' + ditems[iIndex].options.lineJoin + '"' } };
            if ('clickable' in ditems[iIndex].options) { if (!ditems[iIndex].options.clickable !== null) { dOut2 = dOut2 + ',"clickable":' + ditems[iIndex].options.clickable } };
            if ('pointerEvents' in ditems[iIndex].options) { if (!ditems[iIndex].options.pointerEvents !== null) { dOut2 = dOut2 + ',"pointerEvents":"' + ditems[iIndex].options.pointerEvents + '"' } };
            if ('className' in ditems[iIndex].options) { if (!ditems[iIndex].options.className !== null) { dOut2 = dOut2 + ',"className":"' + ditems[iIndex].options.className + '"' } };
            if ('icon' in ditems[iIndex].options) {
                if ('options' in ditems[iIndex].options.icon) {
                    if ('iconSize' in ditems[iIndex].options.icon.options) { dOut2 = dOut2 + ',"iconSize":[' + ditems[iIndex].options.icon.options.iconSize[0] + ',' + ditems[iIndex].options.icon.options.iconSize[0] + ']"' };
                    if ('iconurl' in ditems[iIndex].options.icon.options) { dOut2 = dOut2 + ',"iconUrl":"' + ditems[iIndex].options.icon.options.iconUrl + '"' };
                };
            };
            if (dOut2.length > 1) {
                dOut1 = dOut1 + dOut2.substring(1) + '}';
            };
            dOut2 = '';
            dOut1 = dOut1 + '}';
        } else if (ditems[iIndex] instanceof L.Polyline) {
            dOut1 = dOut1 + ',{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[['
            dOut2 = '';
            for (ll = 0; ll < ditems[iIndex]._latlngs[0].length; ll++) {
                dOut2 = dOut2 + ',[' + ditems[iIndex]._latlngs[0][ll].lng + ',' + ditems[iIndex]._latlngs[0][ll].lat + ']';
            };
            dOut1 = dOut1 + dOut2.substring(1) + ']]},"style":{';
            dOut2 = '';
            if ('stroke' in ditems[iIndex].options) { if (!ditems[iIndex].options.stroke !== null) { dOut2 = dOut2 + ',"stroke":' + ditems[iIndex].options.stroke } };
            if ('color' in ditems[iIndex].options) { if (ditems[iIndex].options.color !== null) { dOut2 = dOut2 + ',"color":"' + ditems[iIndex].options.color + '"' } };
            if ('weight' in ditems[iIndex].options) { if (!ditems[iIndex].options.weight !== null) { dOut2 = dOut2 + ',"weight":' + ditems[iIndex].options.weight } };
            if ('opacity' in ditems[iIndex].options) { if (!ditems[iIndex].options.opacity !== null) { dOut2 = dOut2 + ',"opacity":' + ditems[iIndex].options.opacity } };
            if ('fill' in ditems[iIndex].options) { if (!ditems[iIndex].options.fill !== null) { dOut2 = dOut2 + ',"fill":' + ditems[iIndex].options.fill } };
            if ('fillColor' in ditems[iIndex].options) { if (!ditems[iIndex].options.fillColor !== null) { dOut2 = dOut2 + ',"fillColor":"' + ditems[iIndex].options.fillColor + '"' } };
            if ('fillOpacity' in ditems[iIndex].options) { if (!ditems[iIndex].options.fillOpacity !== null) { dOut2 = dOut2 + ',"fillOpacity":' + ditems[iIndex].options.fillOpacity } };
            if ('fillRule' in ditems[iIndex].options) { if (!ditems[iIndex].options.fillRule !== null) { dOut2 = dOut2 + ',"fillRule":"' + ditems[iIndex].options.fillRule + '"' } };
            if ('dashArray' in ditems[iIndex].options) { if (!ditems[iIndex].options.dashArray !== null) { dOut2 = dOut2 + ',"dashArray":"' + ditems[iIndex].options.dashArray + '"' } };
            if ('lineCap' in ditems[iIndex].options) { if (!ditems[iIndex].options.lineCap !== null) { dOut2 = dOut2 + ',"lineCap":"' + ditems[iIndex].options.lineCap + '"' } };
            if ('lineJoin' in ditems[iIndex].options) { if (!ditems[iIndex].options.lineJoin !== null) { dOut2 = dOut2 + ',"lineJoin":"' + ditems[iIndex].options.lineJoin + '"' } };
            if ('clickable' in ditems[iIndex].options) { if (!ditems[iIndex].options.clickable !== null) { dOut2 = dOut2 + ',"clickable":' + ditems[iIndex].options.clickable } };
            if ('pointerEvents' in ditems[iIndex].options) { if (!ditems[iIndex].options.pointerEvents !== null) { dOut2 = dOut2 + ',"pointerEvents":"' + ditems[iIndex].options.pointerEvents + '"' } };
            if ('className' in ditems[iIndex].options) { if (!ditems[iIndex].options.className !== null) { dOut2 = dOut2 + ',"className":"' + ditems[iIndex].options.className + '"' } };
            if ('icon' in ditems[iIndex].options) {
                if ('options' in ditems[iIndex].options.icon) {
                    if ('iconSize' in ditems[iIndex].options.icon.options) { dOut2 = dOut2 + ',"iconSize":[' + ditems[iIndex].options.icon.options.iconSize[0] + ',' + ditems[iIndex].options.icon.options.iconSize[0] + ']"' };
                    if ('iconurl' in ditems[iIndex].options.icon.options) { dOut2 = dOut2 + ',"iconUrl":"' + ditems[iIndex].options.icon.options.iconUrl + '"' };
                };
            };
            if (dOut2.length > 1) {
                dOut1 = dOut1 + dOut2.substring(1) + '}';
            };
            dOut2 = '';
            dOut1 = dOut1 + '}';
        };
    };
    //console.log(dOut + dOut1.substring(1) + ']}');
    return dOut + dOut1.substring(1) + ']}';
};

@andi-nieves
Copy link

andi-nieves commented Jun 6, 2017

I formulated this function for getting the layer options and convert it into geojson layer properties, but I still have an error, I cant edit the polygons when I put it again on drawnItems (L.featureGroup). What seems the problem?

function layerToJSON(layer){
	var j = layer.toGeoJSON();
	var feature = "";
	j.properties = layer.options;
	feature += JSON.stringify(j)
	return JSON.parse(feature);
}
function drawnItemsToJSON(ilayer) {
	var json = '{"type": "FeatureCollection","features": [';
	var features = "";
	ilayer.eachLayer(function(layer) {
		 features += JSON.stringify(layerToJSON(layer)) + ",";
	});
  return  JSON.parse(json + features.slice(0,-1) + ']}');
};

@iBrian71
Copy link

iBrian71 commented Jun 6, 2017

If you have specified your editable layers when you declare the edit component, you can only edit the objects added to that editable layer

@ddproxy
Copy link
Member

ddproxy commented Jun 6, 2017

This is correct... Here's a method I wrote to move a polygon from one layer to another that may help (hopefully)? There are calls to methods outside of this one, but those should not change how the method is read.

        loadPolygon: function(polygon, returnLayer) {
            if(!returnLayer) {
                returnLayer = false;
            }
            var layer = null;
            try {
                var geoJson = $.parseJSON(polygon);
                if(geoJson.type == "Polygon") {
                    layer = L.geoJson(geoJson, {
                        color: '#FF6633',
                        dashArray: '5',
                        clickable: false,
                        pointerEvents: 'none',
                        analysisTool: true
                    });
                } else {
                    return false;
                }
            } catch (e) {
                polygonPoints = _.map(polygon.rings[0], function(value) {
                    latitude = value[1];
                    longitude = value[0];
                    return [latitude, longitude];
                });
                layer = L.polygon(polygonPoints, {
                    color: '#FF6633',
                    dashArray: '5',
                    clickable: false,
                    pointerEvents: 'none',
                    analysisTool: true
                });
            }
            if(layer && returnLayer == false) {
                this.$el.find('input[value="drawn"]').click();
                this.$el.find('input[value="polygon"]').click();

                if (this.currentDrawer != null) {
                    this.currentDrawer.disable();
                    this.currentDrawer = null;
                }
                this.setUpCancel();
                this.enableMap();
                this.applyPolygonSelection();
                this.polygonSelection.addLayer(layer);
                this.updateMapParams();
                this.centerOnGeometry();
            } else if(returnLayer) {
                return layer;
            }
        }

@ddproxy
Copy link
Member

ddproxy commented Jun 6, 2017

I'm guessing here that your ilayer is the editable layer? you should be able to get GeoJSON directly off the layer by using toGeoJSON from L.FeatureGroup()s inherited method

Should reduce the complexity of your code just a bit. Then it get's a bit fuzzy where you need to start unwrapping the response to a get to a feature collection - or, particularly, adding the properties to the features. But I don't think you need to string parse the geojson since it's already an object and does not need to be stringified to edit the properties.

In the even that the response is not a feature collection and you need to create a new object - try not to stringify if you don't have to ;) Bit fuzzy at the moment on that process.

@andi-nieves
Copy link

Hi ddproxy,

I already tried the toGeoJSON() function, but it can't get the options as geojson property, that's why I created that function. By the way thanks for the suggestion about the stringify thing, I already optimized the function:

function layerToJSON(layer){
var j = layer.toGeoJSON();
var feature = "";
j.properties = layer.options;
return j;
}
function drawnItemsToJSON(ilayer) {
var json = new Object();
json.type = "FeatureCollection";
json.features = [];
ilayer.eachLayer(function(xlayer) {
xlayer.eachLayer(function(layer) {
json.features.push(layerToJSON(layer));
})
});
return json;
};

But it can't help me with my main problem, which is editing the layers once the geojson loaded in drawnItems (L.featureGroup).

@andi-nieves
Copy link

This is my function for getting the previous drawnItems stored in sqlserver.
function getDrawnItems(){
$.getJSON(url,function(e){
var zonesDrawn = L.geoJson(e,{
style: function(f) {
return f.properties;
}
}).addTo(drawnItems);
drawnItems.eachLayer(function(layers) {
layers.eachLayer(function(l){
bindPopup(l);
})
})
});
}

@iBrian71
Copy link

iBrian71 commented Jun 8, 2017

Can you copy up your declaration for the drawnItems plugin - or set up a jsfiddle

@andi-nieves
Copy link

andi-nieves commented Jun 8, 2017

Hi IBrian71
I create my code simulation in Fiddle, please refer to this link. That is exactly my main problem. If you click the edit and delete function of Leaflet.Draw, It won't do anything

https://jsfiddle.net/fx2nnrvu/9/#&togetherjs=FJC9jzLh2v

@iBrian71
Copy link

iBrian71 commented Jun 8, 2017

The problem does not lie with the geojson layer.
If I remove the geojson layer from the fiddle, it still errors as soon as you click the edit button - after drawing an item

VM1391 Edit.SimpleShape.js:107 Uncaught TypeError: L.Marker.Touch is not a constructor
at e._createMarker (VM1391 Edit.SimpleShape.js:107)
at e._createMoveMarker (VM1393 Edit.Rectangle.js:12)
at e._initMarkers (VM1391 Edit.SimpleShape.js:91)
at e.addHooks (VM1391 Edit.SimpleShape.js:49)
at enable (VM1321 leaflet.js:8)
at e._enableLayerEdit (VM1375 EditToolbar.Edit.js:225)
at eachLayer (VM1321 leaflet.js:7)
at e.addHooks (VM1375 EditToolbar.Edit.js:71)
at enable (VM1321 leaflet.js:8)
at enable (VM1375 EditToolbar.Edit.js:43)

@iBrian71
Copy link

iBrian71 commented Jun 9, 2017

I dropped your code into a page with my sources and the same result. The editing does however work if your code not loaded

@iBrian71
Copy link

iBrian71 commented Jun 9, 2017

I have narrowed it down to your get drawn items function - i have it working in mine but cannot get it to run in your fiddle.
My working code following - style apply omitted

@iBrian71
Copy link

iBrian71 commented Jun 9, 2017

    var jsonDrawn = '{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"pane":"overlayPane","nonBubblingEvents":[],"fill":"true","smoothFactor":1,"noClip":false,"stroke":"true","color":"#3388ff","weight":"3","opacity":"1","lineCap":"round","lineJoin":"round","dashArray":null,"dashOffset":null,"fillColor":"#000000","fillOpacity":"0.2","fillRule":"evenodd","interactive":true,"name":"zone1"},"geometry":{"type":"Polygon","coordinates":[[[-123.14017295837404,49.308784358032355],[-123.14017295837404,49.31594672729814],[-123.1245517730713,49.31594672729814],[-123.1245517730713,49.308784358032355],[-123.14017295837404,49.308784358032355]]]}},{"type":"Feature","properties":{"pane":"overlayPane","nonBubblingEvents":[],"fill":true,"smoothFactor":1,"noClip":false,"stroke":true,"color":"#3388ff","weight":3,"opacity":1,"lineCap":"round","lineJoin":"round","dashArray":null,"dashOffset":null,"fillColor":null,"fillOpacity":0.2,"fillRule":"evenodd","interactive":true},"geometry":{"type":"Polygon","coordinates":[[[-123.1589698791504,49.31270140775414],[-123.1589698791504,49.320086996978475],[-123.15150260925294,49.320086996978475],[-123.15150260925294,49.31270140775414],[-123.1589698791504,49.31270140775414]]]}},{"type":"Feature","properties":{"pane":"overlayPane","nonBubblingEvents":[],"fill":true,"smoothFactor":1,"noClip":false,"stroke":true,"color":"#3388ff","weight":3,"opacity":1,"lineCap":"round","lineJoin":"round","dashArray":null,"dashOffset":null,"fillColor":null,"fillOpacity":0.2,"fillRule":"evenodd","interactive":true},"geometry":{"type":"Polygon","coordinates":[[[-123.10644149780275,49.30044560084641],[-123.10644149780275,49.30598627468646],[-123.0886745452881,49.30598627468646],[-123.0886745452881,49.30044560084641],[-123.10644149780275,49.30044560084641]]]}}]}';


    var osmUrl = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
        osmAttrib = '&copy; <a href="http://openstreetmap.org/copyright">OpenStreetMap</a> contributors',
        osm = L.tileLayer(osmUrl, {
            maxZoom: 18,
            attribution: osmAttrib
        }),
        map = new L.Map('map', {
            center: new L.LatLng(49.3112433333333, -123.088858333333),
            zoom: 13
        }),
        drawnItems = L.featureGroup().addTo(map);
    L.control.layers({
        'osm': osm.addTo(map),
        "google": L.tileLayer('http://www.google.cn/maps/vt?lyrs=s@189&gl=cn&x={x}&y={y}&z={z}', {
            attribution: 'google'
        })
    }, {
        'drawlayer': drawnItems
    }, {
        position: 'topleft',
        collapsed: false
    }).addTo(map);

    function getDrawnItems() {
        //var json = JSON.parse(jsonDrawn);
        //var zonesDrawn = L.geoJson(json, {
        //    style: function (f) {
        //        return f.properties;
        //    }
        //}).addTo(drawnItems);

        
        var json = new L.GeoJSON(JSON.parse(jsonDrawn), {
            pointToLayer: function (feature, latlng) {
                switch (feature.geometry.type) {
                    case 'Polygon':
                        //var ii = new L.Polygon(latlng)
                        //ii.addTo(drawnItems);
                        return L.polygon(latlng);
                    case 'LineString':
                        return L.polyline(latlng);
                    case 'Point':
                        return L.marker(latlng);
                    default:
                        return;
                }
            },
            onEachFeature: function (feature, layer) {
                layer.addTo(drawnItems);
            }
        });
        //drawnItems.addLayer(json);
    };

   getDrawnItems();

    map.addControl(new L.Control.Draw({
        edit: {
            featureGroup: drawnItems,
            poly: {
                allowIntersection: false
            }
        },
        draw: {
            polygon: {
                allowIntersection: false,
                showArea: true
            }
        }
    }));
    map.on(L.Draw.Event.CREATED, function (event) {
        var layer = event.layer;
        drawnItems.addLayer(layer);
    });

@iBrian71
Copy link

iBrian71 commented Jun 9, 2017

I think the main issue was you were adding a featuregroup to the edit layer instead of individual polygons

@andi-nieves
Copy link

I didnt think of that, I thought geojson automatically adds the feature as a their respective geometric type. You're a genius iBrian71, thanks a lot! Problem solved!

@mcastre
Copy link

mcastre commented Sep 5, 2018

@nmccready I have the same problem around repopulating circle shapes. Did you find a way to get around this issue?

@iBrian71
Copy link

iBrian71 commented Sep 6, 2018

Circle shapes are not explicitly supported by geojson, so to maintain compat across systems, when a circle is created i convert it to a polygon.. Therefore repopulating works fine. I could dig up a sample of the code if you need

@mcastre
Copy link

mcastre commented Sep 6, 2018

@iBrian71 That would be fantastic, thank you! I will try converting to polygon in the meantime.

@iBrian71
Copy link

iBrian71 commented Sep 6, 2018

For your

map.on(L.Draw.Event.CREATED, function specify how circles are handled
I am using 120 points for the polygon

        if (type === 'circle') {

            var origin = layer.getLatLng(); //center of drawn circle
            var radius = layer.getRadius(); //radius of drawn circle
            var projection = L.CRS.EPSG4326;
            var polys = createGeodesicPolygon(origin, radius, 120, 0, projection); 
            //these are the points that make up the circle ^^
            var polygon = []; // store the geometry
            for (var i = 0; i < polys.length; i++) {
                var geometry = [polys[i].lat, polys[i].lng]; 
                polygon.push(geometry);
            }

            var cpolygon = L.polygon(polygon);
            drawnItems.addLayer(cpolygon, {
                stroke: true,
                color: '#f06eaa',
                weight: 4,
                opacity: 0.5,
                fill: true,
                fillColor: '#f06eaa', //same as color by default
                fillOpacity: 0.2,
                clickable: true
            });
            layerJson = cpolygon.toGeoJSON();
            var pup = 'Popup Message';
            cpolygon.bindPopup(pup);
        } 

@mcastre
Copy link

mcastre commented Sep 11, 2018

@iBrian71 so what happens when I want to edit the circle again? Once it's converted to geojson, it'll have 120 points in a circle, which isn't very user-friendly haha. Would I need to tap into the editstart event and re-convert it back to a circle shape?

@iBrian71
Copy link

Looks like you might be able to use a circle 👍
See these reference
https://gist.github.com/virtualandy/1233401

@mcastre
Copy link

mcastre commented Sep 12, 2018

@Zverik what is the reason for var json = drawnItems.toGeoJSON(); this code when trying to repopulate polygon shapes to the map? do you then add the json var as a map layer? this.map.addLayer(json)? Because I tried repopulating L.geoJson() shapes to the map, but the map doesnt display the shapes. But i believe the shapes are present in this.drawnItems because the Edit and Delete toolbar options are enabled.

This is the specific code block I'm using to try and repopulate shapes from a db back onto the map. Sorry its ugly, just trying to get it to work

this.queryState.selectedPolygons.forEach(shape => {
        const coordinates = shape.shape.geo_polygon.location.points;
        const convertToPolygonShape = L.polygon(coordinates, layerStyles);
        const convertToGeoJsonLayer = convertToPolygonShape.toGeoJSON();
        const finalLayer = L.geoJSON(convertToGeoJsonLayer).getLayers()[0];
        finalLayer.addTo(this.drawnShapes);
 });
this.map.addLayer(this.drawnShapes);

@mcastre
Copy link

mcastre commented Sep 13, 2018

Actually, I figured out why my shapes weren't populating. I had the coordinates reversed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants