Darwin Tech
Darwin Tech

Reputation: 18919

Draw a smaller Polygon inside a Polygon using Google Maps

I am trying to render shapes on Google Maps (using V3 of the API), which contain the same shape, just smaller inside. Basically a box within a box or a polygon within a polygon.

For the rectangle I have the following code, which works:

var drawEdgesRectangle = function (shape) {
  // shape is the original, parent rectangle

  var NE, SW, childNE, childSW, padding, diagonal, inner;

  // set padding constant to 1 (i.e. 1m distance all around) 
  padding = 1;

  // get diagonal distance from corner
  diagonal = Math.sqrt(2) * padding;

  // get NE of parent
  NE = shape.bounds.getNorthEast();

  // get SW of parent
  SW = shape.bounds.getSouthWest();

  // get child NE, SW
  childNE = google.maps.geometry.spherical.computeOffset(NE, diagonal, 225);
  childSW = google.maps.geometry.spherical.computeOffset(SW, diagonal, 45);

  // render inner shape
  inner = new google.maps.Rectangle({
    strokeColor: 'white',
    strokeOpacity: 0.8,
    strokeWeight: 1,
    fillColor: 'black',
    fillOpacity: 0.35,
    map: map,
    bounds: new google.maps.LatLngBounds(
      childSW,
      childNE
    )
  });
}

Of course, doing this for a polygon is a different kettle of fish. I know I can use getPaths() to get the attributes of each line, but working out how to place the inner lines, and indeed, work out where 'inside' is is proving to be conceptually quite difficult for me.

I would like to know if what I want to achieve is possible given the Google API.

Upvotes: 2

Views: 3969

Answers (1)

geocodezip
geocodezip

Reputation: 161324

One option if you polygons are "simple" (the center is "inside" the polygon and there are no concave sides), would be to do something similar to what you did with the rectangle (which is a four sided polygon that meets those criteria):

Using the geometry library:

To include it:

<script src="https://maps.googleapis.com/maps/api/js?v=3&libraries=geometry"></script>

Code (assumes global "poly" and others):

var drawEdgesPoly = function() {
  // shape is the original, parent polygon

  var shape = poly;
  // set padding constant to 1 (i.e. 1m distance all around) 
  padding = 50;

  var vertices = shape.getPath();
  var polybounds = new google.maps.LatLngBounds();
  for (var i = 0; i < vertices.getLength(); i++) {
    polybounds.extend(vertices.getAt(i));
  }
  var center = polybounds.getCenter();
  if (centerMarker && centerMarker.setMap) {
    centerMarker.setMap(null);
  }
  centerMarker = new google.maps.Marker({
    position: center,
    map: map,
    icon: {
      url: "https://maps.gstatic.com/intl/en_us/mapfiles/markers2/measle.png",
      size: new google.maps.Size(7, 7),
      anchor: new google.maps.Point(4, 4)
    }
  });
  if (polylines && (polylines.length > 0)) {
    for (var i = 0; i < polylines.length; i++) {
      polylines[i].setMap(null);
    }
  }
  polylines = [];
  var newPath = [];
  for (var i = 0; i < vertices.getLength(); i++) {
    polylines.push(new google.maps.Polyline({
      path: [center, vertices.getAt(i)],
      map: map,
      strokeWidth: 2,
      strokeColor: 'red'
    }));
    newPath[i] = google.maps.geometry.spherical.computeOffset(vertices.getAt(i),
      padding,
      google.maps.geometry.spherical.computeHeading(vertices.getAt(i), center));
  }
  if (inner && inner.setMap)
    inner.setMap(null);
  // render inner shape
  inner = new google.maps.Polygon({
    strokeColor: 'white',
    strokeOpacity: 0.8,
    strokeWeight: 1,
    fillColor: 'black',
    fillOpacity: 0.35,
    map: map,
    editable: false,
    path: newPath
  });
};

proof of concept fiddle Play with the polygon in the code snippet or the jsfiddle to see the constraints. screen shot of fiddle

var map;
var infoWindow;
var poly;
var inner;
var polylines = [];
var centerMarker;

var paths = [
  [
    new google.maps.LatLng(38.872886, -77.054720),
    new google.maps.LatLng(38.872602, -77.058046),
    new google.maps.LatLng(38.870080, -77.058604),
    new google.maps.LatLng(38.868894, -77.055664),
    new google.maps.LatLng(38.870598, -77.053346)
  ]
];

function initialize() {
  var mapOptions = {
    center: new google.maps.LatLng(38.8714, -77.0556),
    zoom: 15
  };
  map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);

  poly = new google.maps.Polygon({
    paths: paths,
    strokeWeight: 3,
    fillColor: '#55FF55',
    fillOpacity: 0.5,
    editable: true
  });

  poly.setMap(map);
  drawEdgesPoly();

  google.maps.event.addListener(poly.getPath(), 'insert_at', drawEdgesPoly);
  google.maps.event.addListener(poly.getPath(), 'remove_at', drawEdgesPoly);
  google.maps.event.addListener(poly.getPath(), 'set_at', drawEdgesPoly);

  // Define an info window on the map.
  infoWindow = new google.maps.InfoWindow();
}

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

var drawEdgesPoly = function() {
  // shape is the original, parent polygon

  var shape = poly;
  // set padding constant to 1 (i.e. 1m distance all around) 
  padding = 50;

  var vertices = shape.getPath();
  var polybounds = new google.maps.LatLngBounds();
  for (var i = 0; i < vertices.getLength(); i++) {
    polybounds.extend(vertices.getAt(i));
  }
  var center = polybounds.getCenter();
  if (centerMarker && centerMarker.setMap) {
    centerMarker.setMap(null);
  }
  centerMarker = new google.maps.Marker({
    position: center,
    map: map,
    icon: {
      url: "https://maps.gstatic.com/intl/en_us/mapfiles/markers2/measle.png",
      size: new google.maps.Size(7, 7),
      anchor: new google.maps.Point(4, 4)
    }
  });
  if (polylines && (polylines.length > 0)) {
    for (var i = 0; i < polylines.length; i++) {
      polylines[i].setMap(null);
    }
  }
  polylines = [];
  var newPath = [];
  for (var i = 0; i < vertices.getLength(); i++) {
    polylines.push(new google.maps.Polyline({
      path: [center, vertices.getAt(i)],
      map: map,
      strokeWidth: 2,
      strokeColor: 'red'
    }));
    newPath[i] = google.maps.geometry.spherical.computeOffset(vertices.getAt(i),
      padding,
      google.maps.geometry.spherical.computeHeading(vertices.getAt(i), center));
  }
  if (inner && inner.setMap)
    inner.setMap(null);
  // render inner shape
  inner = new google.maps.Polygon({
    strokeColor: 'white',
    strokeOpacity: 0.8,
    strokeWeight: 1,
    fillColor: 'black',
    fillOpacity: 0.35,
    map: map,
    editable: false,
    path: newPath
  });
};
html,
body,
#map-canvas {
  height: 100%;
  width: 100%;
}
<script src="https://maps.googleapis.com/maps/api/js?v=3&libraries=geometry"></script>
<div id="map-canvas" style="height:100%; width:100%;"></div>

Upvotes: 5

Related Questions