Joshua Terrill
Joshua Terrill

Reputation: 2017

Getting coordinates of rectangle/polygon when drawn on google maps with drawing manager

I found a gist that enables drawing tools and gives the ability to choose from a few colors to draw on a google map: https://gist.github.com/Hagith/5765919

I'm trying to utilize this with socket.io so that multiple people can be viewing a map, and when one person draws something onto the map, all of the people can see what is drawn.

I've got the basic idea down with markers by doing

socket.emit("marker", e.overlay.position);

When a marker is placed, however, with rectangles, polygons, and circles, it seems a bit harder. When I log out the click event on the map with any of those shapes, the data that it gives back seems way more complicated than what it gave back with marker and I can't find the coordinates for the points that I need to be able to broadcast to the other users. Does anyone know where to find these in the context of the gist above?

Edit: I've been able to find the center with e.overlay.j.center

Upvotes: 1

Views: 17394

Answers (3)

Gabriel Petersson
Gabriel Petersson

Reputation: 10432

getCoords(someShape){
    const paths = someShape.getPath().getArray();
    const coords = paths.map((a) => [a.lat(), a.lng()]);
}

Gives a list of [lat, lng]

Upvotes: 1

Vadim Gremyachev
Vadim Gremyachev

Reputation: 59328

It is not recommended to utilize those kind of properties (e.overlay.j) since they are not intended for public access and there is no guarantee that they will not change in the next version of Google Maps JavaScript API.

For google.maps.drawing.OverlayType.RECTANGLE and google.maps.drawing.OverlayType.CIRCLE types you could utilize getBounds() function to determine the lat/lng bounds of the current shape as demonstrated below:

//get lat/lng bounds of the current shape
var bounds = e.overlay.getBounds();
var start = bounds.getNorthEast();
var end = bounds.getSouthWest();
var center = bounds.getCenter();

For google.maps.drawing.OverlayType.POLYLINE and google.maps.drawing.OverlayType.POLYGON types you could utilize getPath() function:

//get lat/lng array of the current shape
var locations = e.overlay.getPath().getArray()

Modified example

var drawingManager;
var selectedShape;
var colors = ['#1E90FF', '#FF1493', '#32CD32', '#FF8C00', '#4B0082'];
var selectedColor;
var colorButtons = {};
function clearSelection() {
    if (selectedShape) {
        selectedShape.setEditable(false);
        selectedShape = null;
    }
}
function setSelection(shape) {
    clearSelection();
    selectedShape = shape;
    shape.setEditable(true);
    selectColor(shape.get('fillColor') || shape.get('strokeColor'));
}
function deleteSelectedShape() {
    if (selectedShape) {
        selectedShape.setMap(null);
    }
}
function selectColor(color) {
    selectedColor = color;
    for (var i = 0; i < colors.length; ++i) {
        var currColor = colors[i];
        colorButtons[currColor].style.border = currColor == color ? '2px solid #789' : '2px solid #fff';
    }
    // Retrieves the current options from the drawing manager and replaces the
    // stroke or fill color as appropriate.
    var polylineOptions = drawingManager.get('polylineOptions');
    polylineOptions.strokeColor = color;
    drawingManager.set('polylineOptions', polylineOptions);
    var rectangleOptions = drawingManager.get('rectangleOptions');
    rectangleOptions.fillColor = color;
    drawingManager.set('rectangleOptions', rectangleOptions);
    var circleOptions = drawingManager.get('circleOptions');
    circleOptions.fillColor = color;
    drawingManager.set('circleOptions', circleOptions);
    var polygonOptions = drawingManager.get('polygonOptions');
    polygonOptions.fillColor = color;
    drawingManager.set('polygonOptions', polygonOptions);
}
function setSelectedShapeColor(color) {
    if (selectedShape) {
        if (selectedShape.type == google.maps.drawing.OverlayType.POLYLINE) {
            selectedShape.set('strokeColor', color);
        } else {
            selectedShape.set('fillColor', color);
        }
    }
}
function makeColorButton(color) {
    var button = document.createElement('span');
    button.className = 'color-button';
    button.style.backgroundColor = color;
    google.maps.event.addDomListener(button, 'click', function () {
        selectColor(color);
        setSelectedShapeColor(color);
    });
    return button;
}
function buildColorPalette() {
    var colorPalette = document.getElementById('color-palette');
    for (var i = 0; i < colors.length; ++i) {
        var currColor = colors[i];
        var colorButton = makeColorButton(currColor);
        colorPalette.appendChild(colorButton);
        colorButtons[currColor] = colorButton;
    }
    selectColor(colors[0]);
}
function initialize() {
    var map = new google.maps.Map(document.getElementById('map'), {
        zoom: 16,
        center: new google.maps.LatLng(52.25097, 20.97114),
        mapTypeId: google.maps.MapTypeId.SATELLITE,
        disableDefaultUI: true,
        zoomControl: true
    });
    var polyOptions = {
        strokeWeight: 0,
        fillOpacity: 0.45,
        editable: true,
        draggable: true
    };
    // Creates a drawing manager attached to the map that allows the user to draw
    // markers, lines, and shapes.
    drawingManager = new google.maps.drawing.DrawingManager({
        drawingMode: google.maps.drawing.OverlayType.POLYGON,
        markerOptions: {
            draggable: true
        },
        polylineOptions: {
            editable: true,
            draggable: true
        },
        rectangleOptions: polyOptions,
        circleOptions: polyOptions,
        polygonOptions: polyOptions,
        map: map
    });
    google.maps.event.addListener(drawingManager, 'overlaycomplete', function (e) {
        if (e.type !== google.maps.drawing.OverlayType.MARKER) {
            // Switch back to non-drawing mode after drawing a shape.
            drawingManager.setDrawingMode(null);
            // Add an event listener that selects the newly-drawn shape when the user
            // mouses down on it.
            var newShape = e.overlay;
            newShape.type = e.type;
            google.maps.event.addListener(newShape, 'click', function (e) {
                if (e.vertex !== undefined) {
                    if (newShape.type === google.maps.drawing.OverlayType.POLYGON) {
                        var path = newShape.getPaths().getAt(e.path);
                        path.removeAt(e.vertex);
                        if (path.length < 3) {
                            newShape.setMap(null);
                        }
                    }
                    if (newShape.type === google.maps.drawing.OverlayType.POLYLINE) {
                        var path = newShape.getPath();
                        path.removeAt(e.vertex);
                        if (path.length < 2) {
                            newShape.setMap(null);
                        }
                    }
                }
                setSelection(newShape);
            });
            setSelection(newShape);

            if (e.type == google.maps.drawing.OverlayType.POLYLINE || google.maps.drawing.OverlayType.POLYGON) {
                var locations = e.overlay.getPath().getArray()
                //console.log(bounds.toString());    
                document.getElementById('output').innerHTML = locations.toString();
            }
            else {
                //get lat/lng bounds of the current shape
                var bounds = e.overlay.getBounds();
                var start = bounds.getNorthEast();
                var end = bounds.getSouthWest();
                var center = bounds.getCenter();
                //console.log(bounds.toString());    
                document.getElementById('output').innerHTML = bounds.toString();
            }


        }
    });
    // Clear the current selection when the drawing mode is changed, or when the
    // map is clicked.
    google.maps.event.addListener(drawingManager, 'drawingmode_changed', clearSelection);
    google.maps.event.addListener(map, 'click', clearSelection);
    google.maps.event.addDomListener(document.getElementById('delete-button'), 'click', deleteSelectedShape);
    buildColorPalette();
}
google.maps.event.addDomListener(window, 'load', initialize);
#map, html, body {
            padding: 0;
            margin: 0;
            width: 960px;
            height: 300px;
        }

        #panel {
            width: 200px;
            font-family: Arial, sans-serif;
            font-size: 13px;
            float: right;
            margin: 10px;
        }

        #color-palette {
            clear: both;
        }

        .color-button {
            width: 14px;
            height: 14px;
            font-size: 0;
            margin: 2px;
            float: left;
            cursor: pointer;
        }

        #delete-button {
            margin-top: 5px;
        }
<script type="text/javascript"
            src="http://maps.google.com/maps/api/js?sensor=false&libraries=drawing"></script> 
<div id="panel">
        <div id="color-palette"></div>
        <div>
            <button id="delete-button">Delete Selected Shape</button>
        </div>
 </div>
 <div id="map"></div>
 <div id="output"></div>

Upvotes: 9

Juffy
Juffy

Reputation: 1220

Edit: I've been able to find the center with e.overlay.j.center

You want to be VERY careful using the single-letter properties you can see in the browser debug tools. They are not documented, or static, and will change without warning.


To answer the actual question - the type of e.overlay depends on what you've initialised the DrawingManager with, see the docs here. So if you're drawing polygons, e.overlay will be of type Polygon. You can then get the points that make up that Polygon using e.overlay.getPath(0).getArray(), which gives you an array of LatLng objects. (obviously loop over all the available paths, not just 0).

There's a good example here which shows switching behaviour based on what type of geometry the overlay is returned as.

Upvotes: 3

Related Questions