Center point to move entire polygons like rectangles #243

Open
Zverik opened this Issue Dec 11, 2013 · 9 comments

Comments

Projects
None yet
7 participants
@Zverik
Contributor

Zverik commented Dec 11, 2013

There is a point for rectangles, why not place the same marker for polygons? Finding its center is more tricky, of course, but can be done.

@peterb-2795

This comment has been minimized.

Show comment Hide comment
@peterb-2795

peterb-2795 Dec 11, 2013

+1 on this, ditto all graphical elements (point, line, polygon, circle, rect). It would seem to me that in order to move a polygon entity, finding a centre point is secondary to the action. Typically for any polygon - one would calc a para-centroid (think text placement algorithms etc).

+1 on this, ditto all graphical elements (point, line, polygon, circle, rect). It would seem to me that in order to move a polygon entity, finding a centre point is secondary to the action. Typically for any polygon - one would calc a para-centroid (think text placement algorithms etc).

@willfarrell

This comment has been minimized.

Show comment Hide comment
@willfarrell

willfarrell Apr 30, 2014

+1, I did my own hack to do it outside of leaflet.draw.

Basically what I did was get the center point of the bounds (start points) then offset all the points by the diff to where the mouse is, then redraw (likely slow for polygon with many points).

It's used in an angular directive, but you get the idea.

                var layerMoveCopy;
                $scope.layerSetCopy = function(layer) {
                    layerMoveCopy = layer;
                };
                $scope.layerStartDrag = function( e ) {
                    console.log( 'layerStartDrag', e, e.layer );
                    //layerMoveCopy = e.target;
                    $scope.editMode = 'dragstart';
                    $scope.changePointer( 'move' );

                    map.removeLayer( e.target );
                    map.addLayer( layerMoveCopy );

                    //layer._layers[ layer.c1id ].options.color = '#e94525';
                    //layer._layers[ layer.c2id ].options.fillColor = '#e94525';
                    map.on( 'mousemove', $scope.layerMoveDrag );
                    map.once( 'click', $scope.layerStopDrag );
                    //map.on( 'drag', layerMoveDrag );
                    //map.once( 'dragend', layerStopDrag );
                    $scope.$apply();
                };

                $scope.layerMoveDrag = function( e ) {
                    console.log( 'layerMoveDrag', e, layerMoveCopy );
                    $scope.editMode = 'dragmove';

                    var startCenter = $mapCore.leafletLayerToCenterObject(layerMoveCopy);
                    var moveCenter = e.latlng;
                    var latDiff = (parseFloat(moveCenter.lat) - parseFloat(startCenter.lat)),
                        lngDiff = (parseFloat(moveCenter.lng) - parseFloat(startCenter.lng));
                    //console.log( 'layerMoveDrag.diff', latDiff, lngDiff );

                    if (map.hasLayer(layerMoveCopy)) {
                        map.removeLayer( layerMoveCopy );
                    }
                    layerMoveCopy = $scope.layerMove(layerMoveCopy, lngDiff, latDiff);
                    console.log( 'layerMoveDrag.diff', layerMoveCopy );
                    map.addLayer( layerMoveCopy );
                    $scope.$apply();
                };

                $scope.layerMove = function(layer, lngDiff, latDiff) {
                    if (angular.isDefined(layer._layers)) {
                        angular.forEach(layer._layers, function(layerPart) {
                            layerPart = $scope.layerMove(layerPart, lngDiff, latDiff);
                        });
                    } else if (angular.isDefined(layer._latlng)) {
                        //console.log( 'layerMoveDrag.point', layer._latlng, moveCenter );
                        layer._latlng = L.latLng(
                            layer._latlng.lat + latDiff,
                            layer._latlng.lng + lngDiff
                        );
                    // polygons
                    } else if (angular.isDefined(layer._latlngs)) {
                        angular.forEach( layer._latlngs, function ( point, index ) {
                            layer._latlngs[index] = L.latLng(
                                layer._latlngs[index].lat + latDiff,
                                layer._latlngs[index].lng + lngDiff
                            );
                        });
                    }
                    return layer;
                };

                $scope.layerStopDrag = function( e ) {
                    console.log( 'layerStopDrag', e );
                    $scope.editMode = 'dragstop';
                    $scope.changePointer( null );

                    map.dragging.enable();

                    map.off( 'mousemove', $scope.layerMoveDrag );
                    //map.off( 'drag' );
                    map.removeLayer( layerMoveCopy ); // cb must re add new obj
                    $scope.$apply();
                };
            $scope.leafletLayerToCenterObject = function ( layer ) {
                var center = layer.getBounds().getCenter();
                return {
                    lat:center.lat,
                    lng:center.lng
                };
            };

+1, I did my own hack to do it outside of leaflet.draw.

Basically what I did was get the center point of the bounds (start points) then offset all the points by the diff to where the mouse is, then redraw (likely slow for polygon with many points).

It's used in an angular directive, but you get the idea.

                var layerMoveCopy;
                $scope.layerSetCopy = function(layer) {
                    layerMoveCopy = layer;
                };
                $scope.layerStartDrag = function( e ) {
                    console.log( 'layerStartDrag', e, e.layer );
                    //layerMoveCopy = e.target;
                    $scope.editMode = 'dragstart';
                    $scope.changePointer( 'move' );

                    map.removeLayer( e.target );
                    map.addLayer( layerMoveCopy );

                    //layer._layers[ layer.c1id ].options.color = '#e94525';
                    //layer._layers[ layer.c2id ].options.fillColor = '#e94525';
                    map.on( 'mousemove', $scope.layerMoveDrag );
                    map.once( 'click', $scope.layerStopDrag );
                    //map.on( 'drag', layerMoveDrag );
                    //map.once( 'dragend', layerStopDrag );
                    $scope.$apply();
                };

                $scope.layerMoveDrag = function( e ) {
                    console.log( 'layerMoveDrag', e, layerMoveCopy );
                    $scope.editMode = 'dragmove';

                    var startCenter = $mapCore.leafletLayerToCenterObject(layerMoveCopy);
                    var moveCenter = e.latlng;
                    var latDiff = (parseFloat(moveCenter.lat) - parseFloat(startCenter.lat)),
                        lngDiff = (parseFloat(moveCenter.lng) - parseFloat(startCenter.lng));
                    //console.log( 'layerMoveDrag.diff', latDiff, lngDiff );

                    if (map.hasLayer(layerMoveCopy)) {
                        map.removeLayer( layerMoveCopy );
                    }
                    layerMoveCopy = $scope.layerMove(layerMoveCopy, lngDiff, latDiff);
                    console.log( 'layerMoveDrag.diff', layerMoveCopy );
                    map.addLayer( layerMoveCopy );
                    $scope.$apply();
                };

                $scope.layerMove = function(layer, lngDiff, latDiff) {
                    if (angular.isDefined(layer._layers)) {
                        angular.forEach(layer._layers, function(layerPart) {
                            layerPart = $scope.layerMove(layerPart, lngDiff, latDiff);
                        });
                    } else if (angular.isDefined(layer._latlng)) {
                        //console.log( 'layerMoveDrag.point', layer._latlng, moveCenter );
                        layer._latlng = L.latLng(
                            layer._latlng.lat + latDiff,
                            layer._latlng.lng + lngDiff
                        );
                    // polygons
                    } else if (angular.isDefined(layer._latlngs)) {
                        angular.forEach( layer._latlngs, function ( point, index ) {
                            layer._latlngs[index] = L.latLng(
                                layer._latlngs[index].lat + latDiff,
                                layer._latlngs[index].lng + lngDiff
                            );
                        });
                    }
                    return layer;
                };

                $scope.layerStopDrag = function( e ) {
                    console.log( 'layerStopDrag', e );
                    $scope.editMode = 'dragstop';
                    $scope.changePointer( null );

                    map.dragging.enable();

                    map.off( 'mousemove', $scope.layerMoveDrag );
                    //map.off( 'drag' );
                    map.removeLayer( layerMoveCopy ); // cb must re add new obj
                    $scope.$apply();
                };
            $scope.leafletLayerToCenterObject = function ( layer ) {
                var center = layer.getBounds().getCenter();
                return {
                    lat:center.lat,
                    lng:center.lng
                };
            };
@w8r

This comment has been minimized.

Show comment Hide comment
@w8r

w8r Jan 28, 2015

Contributor

I would propose a slightly different approach to this. Take a look at my Leaflet.draw.drag and let me explain:

  • It uses SVG/VML matrix transforms while dragging, so no recalculations on mousemove involved. This is crucial if you have to deal with the polygons that consist of hundreds of points. Reprojection is done only once - on release.
  • It extends L.Path with _applyTransform(matrix) method, that gives way to all kinds of transformations that can be added to Lefalet.draw in the future: scale, skew, etc

@Zverik, @willfarrell, @jacobtoye, please review this plug-in, if you think it's useful, I can convert it into a pull-request

Contributor

w8r commented Jan 28, 2015

I would propose a slightly different approach to this. Take a look at my Leaflet.draw.drag and let me explain:

  • It uses SVG/VML matrix transforms while dragging, so no recalculations on mousemove involved. This is crucial if you have to deal with the polygons that consist of hundreds of points. Reprojection is done only once - on release.
  • It extends L.Path with _applyTransform(matrix) method, that gives way to all kinds of transformations that can be added to Lefalet.draw in the future: scale, skew, etc

@Zverik, @willfarrell, @jacobtoye, please review this plug-in, if you think it's useful, I can convert it into a pull-request

@dremonkey

This comment has been minimized.

Show comment Hide comment
@dremonkey

dremonkey Feb 11, 2015

@w8r thanks for the plugin. From my testing so far, works like a charm. +1 to bringing this into Leaflet.Draw and also refactoring Edit.Rectangle and Edit.Circle to work like this, rather than needing the drag marker.

@w8r thanks for the plugin. From my testing so far, works like a charm. +1 to bringing this into Leaflet.Draw and also refactoring Edit.Rectangle and Edit.Circle to work like this, rather than needing the drag marker.

@w8r

This comment has been minimized.

Show comment Hide comment
@w8r

w8r Feb 24, 2015

Contributor

Added optional support for centroid markers, next thing I have in mind is turning that into PR

Contributor

w8r commented Feb 24, 2015

Added optional support for centroid markers, next thing I have in mind is turning that into PR

@willfarrell

This comment has been minimized.

Show comment Hide comment
@willfarrell

willfarrell Mar 1, 2015

Finally had some time to take a quick look. Looks promising. I won't be able to take a closer look till I revisit my drawing code, which may be a while. Performance has been quite good in this area, but I expect it to be once users become more confident with using the tool and start creating very complex polygons.

Finally had some time to take a quick look. Looks promising. I won't be able to take a closer look till I revisit my drawing code, which may be a while. Performance has been quite good in this area, but I expect it to be once users become more confident with using the tool and start creating very complex polygons.

@raoulalwani

This comment has been minimized.

Show comment Hide comment
@raoulalwani

raoulalwani Jun 10, 2015

+1 to @w8r , thanks for the nice plugin. Leaving a comment so I am on the email notifications for this

+1 to @w8r , thanks for the nice plugin. Leaving a comment so I am on the email notifications for this

@fschutt

This comment has been minimized.

Show comment Hide comment
@fschutt

fschutt Jun 4, 2017

alright, did anything ever happen to this?

fschutt commented Jun 4, 2017

alright, did anything ever happen to this?

@willfarrell

This comment has been minimized.

Show comment Hide comment
@willfarrell

willfarrell Jun 4, 2017

Nope, There is an open PR for it though. #294
I'm no longer at the company I built this for. Perhaps someone else would like to take the lead on getting this merged in? I feel it's still a useful edit feature.

Nope, There is an open PR for it though. #294
I'm no longer at the company I built this for. Perhaps someone else would like to take the lead on getting this merged in? I feel it's still a useful edit feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment