1
votes

After searching the whole day, I didn't find the answer.

So the problem is:
I have a Google Map on which the user can draw. After this, the user can save it on the server. It works fine. Here is the drawing code:

var drawingManager;
var selectedShape;
var colors = ['#1E90FF', '#FF1493', '#32CD32', '#FF8C00', '#4B0082'];
var selectedColor;
var colorButtons = {};
var all_overlays = [];
var coordinates;
var polygon;
var globalGoogleSelectedColor;
var globalGooglePinWidth;
var map;
coordObj = new Object();

function clearSelection() 
{
  if (selectedShape) 
  {
    deleteAllLastShape(); 
    selectedShape.setEditable(false);
    selectedShape = null;
    deleteObjectContent(coordObj);
  }
}

function setSelection(shape) 
{
  clearSelection();
  selectedShape = shape;
  shape.setEditable(true);
  selectColor(shape.get('fillColor') || shape.get('strokeColor'));
}

function deleteAllShape() 
{
  console.log("deleteAllShape");
  deleteObjectContent(coordObj);

  for (var i=0; i < all_overlays.length; i++)
  {
    all_overlays[i].overlay.setMap(null);
  }

  all_overlays = [];
}

function deleteAllLastShape() 
{
  var myLenth = all_overlays.length;

  if(myLenth > 1)
  {
    all_overlays[0].overlay.setMap(null);
    all_overlays = _.rest(all_overlays);
  }
}

function deleteSelectedShape() 
{
  if (selectedShape) 
  {
    selectedShape.setMap(null);
    deleteObjectContent(coordObj);
  }
}

function selectColor(color)
{
  selectedColor = color;
  globalGoogleSelectedColor = selectedColor;
  globalGooglePinWidth = 2; //only for Database

  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 initializeAreas() 
{
    map = new google.maps.Map(document.getElementById('mapBaugebieteDiv'), 
    {
      zoom: 15,
      center: new google.maps.LatLng(48.758961357888516,8.240861892700195),
      mapTypeControlOptions: {
      style: google.maps.MapTypeControlStyle.DEFAULT,
      mapTypeIds: [
        google.maps.MapTypeId.ROADMAP,
        google.maps.MapTypeId.TERRAIN,
        google.maps.MapTypeId.SATELLITE,
        google.maps.MapTypeId.HYBRID
      ]},
      disableDefaultUI: false,
      zoomControl: true,
      scaleControl: true,
      mapTypeControl: true,
      streetViewControl: true,
      rotateControl: true
    });

    var polyOptions = 
    {
      strokeWeight: 0,
      fillOpacity: 0.45,
      editable: 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,
      drawingControl: true,
      drawingControlOptions: {
        position: google.maps.ControlPosition.TOP_CENTER,
        drawingModes: [
            // google.maps.drawing.OverlayType.MARKER,
            // google.maps.drawing.OverlayType.CIRCLE,
            google.maps.drawing.OverlayType.POLYLINE,
            // google.maps.drawing.OverlayType.RECTANGLE,
            google.maps.drawing.OverlayType.POLYGON
          ]
      },
      markerOptions: 
      {
        draggable: true
      },
      polylineOptions: 
      {
        editable: true
      },
      rectangleOptions: polyOptions,
      circleOptions: polyOptions,
      polygonOptions: polyOptions,
      map: map
    });

    google.maps.event.addListener(drawingManager, 'overlaycomplete', function(e) 
    {
      // Push the overlay onto an array (all_overlays):
      all_overlays.push(e);
      deleteAllLastShape();

      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() 
        {
          setSelection(newShape);
        });
        setSelection(newShape);
      }
    });

    // 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);
    google.maps.event.addDomListener(document.getElementById('delete-all-button'), 'click', deleteAllShape);

    ///////////////////////////////////////
    // Polylgon
    ///////////////////////////////////////
    google.maps.event.addListener(drawingManager, 'polygoncomplete', function (polygon) 
    {
      var shapeType = 'polygon';
      google.maps.event.addListener(polygon.getPath(), 'insert_at', function()
      {
        // New point
        coordinates = (polygon.getPath().getArray());
        showObjectContent(coordinates);
        coordObj = getCoordinatesOfPolygon(polygon,shapeType);
      });

      google.maps.event.addListener(polygon.getPath(), 'remove_at', function()
      {
        // Point was removed
        coordinates = (polygon.getPath().getArray());
        coordObj = getCoordinatesOfPolygon(polygon,shapeType);
      });

      google.maps.event.addListener(polygon.getPath(), 'set_at', function()
      {
          // Point was moved
          coordinates = (polygon.getPath().getArray());
          coordObj = getCoordinatesOfPolygon(polygon,shapeType);
      });

      google.maps.event.addListener(polygon, 'dragend', function()
      {
        // Polygon was dragged
        coordinates = (polygon.getPath().getArray());
        coordObj = getCoordinatesOfPolygon(polygon,shapeType);
      });

      coordinates = (polygon.getPath().getArray());
      coordObj = getCoordinatesOfPolygon(polygon,shapeType);
    });

    ///////////////////////////////////////
    // Polyline
    ///////////////////////////////////////
    google.maps.event.addListener(drawingManager, 'polylinecomplete', function (polygon) 
    {
      var shapeType = 'polyline';
      google.maps.event.addListener(polygon.getPath(), 'insert_at', function()
      {
        // New point
        coordinates = (polygon.getPath().getArray());
        coordObj = getCoordinatesOfPolygon(polygon,shapeType);
      });

      google.maps.event.addListener(polygon.getPath(), 'remove_at', function()
      {
        // Point was removed
        coordinates = (polygon.getPath().getArray());
        coordObj = getCoordinatesOfPolygon(polygon,shapeType);
      });

      google.maps.event.addListener(polygon.getPath(), 'set_at', function()
      {
        // Point was moved
        coordinates = (polygon.getPath().getArray());
        coordObj = getCoordinatesOfPolygon(polygon,shapeType);
      });

      google.maps.event.addListener(polygon, 'dragend', function()
      {
        // Polygon was dragged
        coordinates = (polygon.getPath().getArray());
        coordObj = getCoordinatesOfPolygon(polygon,shapeType);
      });
      coordinates = (polygon.getPath().getArray());
      coordObj = getCoordinatesOfPolygon(polygon,shapeType);
    });

    buildColorPalette();
} 

google.maps.event.addDomListener(window, 'load', initializeAreas);

But the big problem is, after reloading the lat/lng from the server and drawing it on the map, the event listener does not know about the new polygon:

function fillBuildingForm(getData)
{
  var coord = getData['buildings']; // coordinates from the server

  if(typeof coord[0] !== 'undefined')
  {
    var shapeType = coord[0]['shapeType'];
    var color = coord[0]['color'];
    var strokeOpacity = coord[0]['opacity'];
    var strokeWeight = coord[0]['linewidth'];
    var numberOfCoord = getObjectSize(coord);
    var flightPlanCoordinates = new Array();

    for (var i = 0; i < numberOfCoord; i++) 
    {
      thisCoord = new Object();
      thisCoord['lat']=parseFloat(coord[i]['lat']);
      thisCoord['lng']=parseFloat(coord[i]['lng']);
      flightPlanCoordinates.push(thisCoord);
    };

    var bermudaTriangle = new google.maps.Polygon(
    {
      paths: flightPlanCoordinates,
      strokeColor: color,
      strokeOpacity: strokeOpacity,
      strokeWeight: strokeWeight,
      fillColor: color,
      fillOpacity: 0.35,
      // bounds: flightPlanCoordinates,
      editable: true,
      draggable: true
    });

    bermudaTriangle.setMap(map); //now its drawing at the map
  }
}

You can see, until now, it works perfectly: enter image description here

But the user can change the polygon and want to save the new changed polygon on the server. The listener:

google.maps.event.addListener(drawingManager, 'polygoncomplete', function (polygon) 

Does not recognize that the polygon has been drawn. And therefore the listener doesn't recognize when the user changes the polygon. So the coordinates are not present in all_overlays[i]. The listener only recognizes when a polygon is drawn manually, but not in the way like the above, when it is drawn automatically.

The question: How can I send the automatically drawn polygon coordinates to the "map" object? Alternatively, how can I fire an event to "polygoncomplete", so it will recognize the new polygon?

The other idea I had: Trigger a mouse click event at the map with the coordinates, so the listener must recognize that the map has changed. But unfortunately this didn't work.

Has anybody any idea how to solve this issue?

2
How you can affiirm that a polygon is complete? .. which conditions define this situation..? - ScaisEdge
In the first code above you see: drawingModes: [ // google.maps.drawing.OverlayType.MARKER, // google.maps.drawing.OverlayType.CIRCLE, google.maps.drawing.OverlayType.POLYLINE, // google.maps.drawing.OverlayType.RECTANGLE, google.maps.drawing.OverlayType.POLYGON ] ----> So here are given 2 possibilities to user: draw a polyline or a polygon, when he at first time comes to the empty map. The problem is after loading from the server and drawing it again, that the listeners don't know about the new poly. - Andy Steen
Please provide a Minimal, Complete, Tested and Readable example that demonstrates the issue. You should be able to add listeners to the polygon added to the map from the server. - geocodezip
Downvoting is not fair. I could not show the complete issue or application, because it is embedded in a backend-system of a customer, where you need a login. It would be a really great effort to write this application new for demonstrating the functionality to you. - Andy Steen

2 Answers

0
votes

There are not many possibilities as an event "polygon_load _complete" is not available. One suggestion is to exploit the fact that to operate on a polygon you must click it. If you need to manage the situation when a polygon is loaded from server and the user change the shape/coordinates. you can add listener on click to every polygon during the loading phase ..

for each polygon in loading phase..

var aPoly  = new google.maps.Polygon({
    paths:myPaths,
    .......
});


google.maps.event.addListener(aPoly, 'click', function (event) {
     console.log('This polygon contain : ' + this.paths + ' coords point ');
  });  

In this way you can intecept the click on polygon for manage your need

0
votes

your idea was a good intention, but not the end of the solution. But thank you for your hint. Because of your answer I was able finding a way.

Generally we should think, the object bermudaTriangle should have the property "paths". But it doesn't work like this way.

For getting the coordinates of the loaded Poly (loaded from server) there is a google-map function like "getPath()" or"getPaths()". It seems, that both methods are working.

Please note, I've changed the name from 'bermudaTriangle' to 'globalLoadedPoly'.

So the solution is in combination with the above code now additional:

  1. Creating a global var:

    var globalLoadedPoly;
    

    (global is not necessary, but I did it this way for further actions)

  2. Getting the path by function for the listeners:

    var thisPolyPath = globalLoadedPoly.getPath();
    
  3. Listening to events, when the loaded poly has changed:

    google.maps.event.addListener(thisPolyPath, 'set_at', thisPolyHasChanged);
    google.maps.event.addListener(thisPolyPath, 'insert_at', thisPolyHasChanged);
    

4.In the function, thisPolyHasChanged(), setting the loaded poly as the actual selection, by using the function setSelection(shape). And getting the coordinates by calling the function getCoordinatesOfLoadedPolygon

function thisPolyHasChanged()
{
   // Setting the loaded poly as the new selection
   // Yes, it's global, so therefore not necessary to be sent
   // but like this way, it's more readable
   setSelection(globalLoadedPoly);

   // If you want to get the coordinates for saving
   // Calling the function getCoordinatesOfLoadedPolygon
   // For being more readable I send the global Object - yes, it's not necessary
   coordObj = getCoordinatesOfLoadedPolygon(globalLoadedPoly,'polygon');
   // do something with coordObj
   // ...
}

  function setSelection(shape) 
  {
    // clearSelection is in the code I postet as the question 
    clearSelection();
    selectedShape = shape; // setting the loaded poly as the actual poly
    shape.setEditable(true); // making the loaded poly editable
    selectColor(shape.get('fillColor') || shape.get('strokeColor')); //setting the color
  }

function getCoordinatesOfLoadedPolygon(getPolygon,shapeType)
{
  // getLength is also a google-maps function / method
  var objSize = getPolygon.getPath().getLength();
  for (var i = 0; i < objSize; i++) 
  {
    // getArray is a google-maps function / method too
    var thisLat = getPolygon.getPath().getArray()[i].lat();
    var thisLng = getPolygon.getPath().getArray()[i].lng();
    coordObj[i]=new Object();
    coordObj[i]['lat']=thisLat;
    coordObj[i]['lng']=thisLng;
    coordObj[i]['shapeType']=shapeType;
  };
  return coordObj; 
}

At last, if you iterate the object "coordObj" and make a console.log in firebug, it looks like this way:

 0 Object { lat=51.25572693191116, lng=9.136230200529099, shapeType="polygon"}

 1 Object { lat=51.80250070611026, lng=13.069335669279099, shapeType="polygon"}

 2 Object { lat=49.958995050387585, lng=10.476562231779099, shapeType="polygon"}

Conclusion:

If you want to get the coordinates or other properties of a google-maps object, use the proprietary google-maps functions / methods:

// For getting the coordinates you are generally working with:
yourMapObject.getPath();
//or
yourMapObject.getPaths();

// Getting especially the latitude:
var latitude = yourMapObject.getPath().getArray()[i].lat();
// Getting especially the longitude:
var longitude = yourMapObject.getPath().getArray()[i].lng();

// Getting the number of coordinates
yourMapObject.getPath().getLength();

Don't forget to iterate over the whole object, to get all coordinates.

The solution-code could be really optimized. For being more readable, I wrote it in small steps.

I hope, I'm able helping anybody with this solution.