Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Catch Events when drawing a polygon on Google Maps Data Layer

When drawing a polygon on a google maps Data Layer, I want to handle the events when a user draws the first point, second and subsequent points so that the UI can give different user guidance such as:

  • no points drawn : "click to draw the first point"
  • first point drawn: "click to draw the next point"
  • second point drawn: "click to add another point or click on the first point to end"

When the closing point is drawn on a data layer using the Data Library there is an 'addfeature' event. When the final point is drawn using the Drawing Library there are different events such as polygoncomplete.

To see if any events are emitted for the first, second and subsequent points, I used google sample code to display all the events and modified it to handle Drawing events on a Data layer. The new events are:

'addfeature': 'data layer event',
      'click': 'data layer event',
      'dblclick': 'data layer event',
      'mousedown': 'data layer event',
      'mouseout': 'data layer event',
      'mouseover': 'data layer event',
      'mouseup': 'data layer event',
      'removefeature': 'data layer event',
      'removeproperty': 'data layer event',
      'rightclick': 'data layer event',
      'setgeometry': 'data layer event',
      'setproperty': 'data layer event',
      'circlecomplete': 'This event is fired when the user has finished drawing a circle',
      'markercomplete': 'This event is fired when the user has finished drawig a marker',
      'overlaycomplete': 'This event is fired when the user has finished drawing an overlay of any type',
      'polygoncomplete': 'This event is fired when the user has finished drawing a polygon',
      'polylinecomplete': 'This event is fired when the user has finished drawing a polyline',
      'rectanglecomplete': 'This event is fired when the user has finished drawing a rectangle'
}

http://jsfiddle.net/bunjil/gfp9qntx/9/

The event listener was also enhanced to also listen for data layer events - not just map events.

Looking at the events that are fired, and checking the documentation it appears there is no event for adding points while drawing a new polygon, just the mouseup event on the data layer.

While it would be possible to count the mouseup events, this might not be a robust solution.

I can see there are some events on polygons and polylines when adding or moving vertices but these only seem to exist once the polygon is created.

Can anyone confirm if this understanding is correct or if there are events I am missing something.

There is a related question that seems to confirm there are no events on the data layer or the map but you can listen for mouse events on the canvas. How can I listen for the start of a user drawing a polygon in Google Maps v3?

like image 291
intotecho Avatar asked Jan 06 '16 07:01

intotecho


People also ask

How do I capture data from Google Maps?

To download your data, head to Google Maps on your computer and sign in. Next, click the three-line menu icon in the top-left corner next to the Search box. Near the bottom, select “Your Data in Maps.” On the next screen, scroll down to and select “Download Your Maps Data.”

How do I extract a polygon from Google Maps?

In Google Earth, create the polygon that you wish to bring into RockWorks. Or, locate the polygon that currently exists in your Saved Places listing. Right-click on the item, and choose Copy from the pop-up menu. Or, right-click on the item, and choose Save Place As to save the locations in a KMZ file.

How do I calculate the area of a polygon in Google Maps?

Right-click on the map at your starting point and choose the Measure distance option. Add points around the location's boundary. Once you close the shape by clicking on the starting point, the Google Maps area calculator will automatically process the area of your shape.


1 Answers

Well, it looks like people have been asking for this since 2011. It's the end of April 2018 as I write this and it still hasn't been added, so... that's unfortunate.

While not a fantastic solution, I did come up with a workaround that worked for my purposes. My map is inside of a container div tag that is the same size as the map. I added an onclick handler to this.

If you keep track of the map drawing manager's mode in your code, you should be able to count the number of times the click occurs, and use this info as needed. Then on the overlaycomplete event, you could reset the count to zero.

If you need to get at the position of the event, as I did, you can use the event to get the pixel coordinates of the location clicked on the map:

const onClickHandler = (event) => {
  const offset = event.target.getClientRects()[0];
  console.log("x", event.clientX - offset.left);
  console.log("y", event.clientY - offset.top); 
}

With the x and y pixel coordinate, you can get a lat and lng with (this deserves a credit, but I forget where I got it):

const point2LatLng = (point, map) => {
  let topRight = map
    .getProjection()
    .fromLatLngToPoint(map.getBounds().getNorthEast());
  let bottomLeft = map
    .getProjection()
    .fromLatLngToPoint(map.getBounds().getSouthWest());
  let scale = Math.pow(2, map.getZoom());
  let worldPoint = new google.maps.Point(
    point.x / scale + bottomLeft.x,
    point.y / scale + topRight.y
  );
  return map.getProjection().fromPointToLatLng(worldPoint);
};

Update: May 2, 2018

Using mousedown and mouseup event handlers instead of just onclick

I just encountered a nuance with this I figured would be helpful to share. It looks like the Google maps drawing manager doesn't register a vertex when you are drawing a polygon if the position of your cursor changes by more than a pixel when clicking. So, if you click to drop a vertex, then while holding the mouse down, move the cursor by more than a pixel before letting the mouse up, a vertex does not get dropped.

To deal with this, instead of using onclick, I needed to keep track of the position of the mousedown event and compare it to the position of the mouseup event in order to ensure it was within an acceptable tolerance.

In my code, I store the mousedown position (I'm using React, so I store it in my component's state). Then in my mouseup event handler I have this guard clause before I carry out any vertex-was-just-added functionality:

if (
  Math.abs(eventPosition.x - mouseDownPosition.x) > 1 ||
  Math.abs(eventPosition.y - mouseDownPosition.y) > 1
) {
  return;
}

I extracted eventPosition to a method so it could be shared between event handlers:

eventPosition(event) {
  const offset = event.target.getClientRects()[0];
  const x = event.clientX - offset.left;
  const y = event.clientY - offset.top;
  return { x, y };
}

// const eventPosition = this.eventPosition(event);
like image 123
Elliot Larson Avatar answered Sep 23 '22 01:09

Elliot Larson