Mmmmm Donuts

I’m working on an update to a Google Maps project and was confronted with a bit of a dilemma. As part of the UI, we wanted to “blackout” the map but leave a rectangular hole in the middle. Basically a polygon with a hole, or a donut/island polygon as they’re known in the mapping community. After a little frustration I figured out how to accomplish it with the Google Maps API.

Basically you create two polygons. With a KML file you can create and outer and inner boundary:

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document><name>KML file for a polygon with a hole</name>
<description>Just a polygon with a hole</description>
<Style id="rangecolour">
<LineStyle><color>660000FF</color><width>0.1</width></LineStyle>
<PolyStyle><color>660000FF</color></PolyStyle>
</Style>
<Style id="linecolour">
<LineStyle><color>660000FF</color><width>3</width></LineStyle>
</Style>
<Placemark><name>distribution/range</name>
<description></description>
<styleUrl>#rangecolour</styleUrl>
<Polygon>
<tessellate>1</tessellate><altitudeMode>clampToGround</altitudeMode>
<outerBoundaryIs><LinearRing><coordinates>
-16.171875,16.804541,0 
33.75,16.130262,0 
33.046875,-32.546813,0 
-16.699219,-31.802893,0 
-16.171875,16.804541,0 
</coordinates></LinearRing></outerBoundaryIs>
<innerBoundaryIs><LinearRing><coordinates>
25.839844,6.315299,0 
-8.964844,8.407168,0 
-10.371094,-26.273714,0 
24.785156,-26.115986,0 
25.839844,6.315299,0 
</coordinates></LinearRing></innerBoundaryIs>
</Polygon>
</Placemark>
</Document>
</kml>

and then import in into your Google Map:

var kml = new google.maps.KmlLayer('http://jeffreysambells.com/examples/hole.kml');
kml.setMap( map );

Or, if you’re embedding it in the Google Maps API you would create two paths in the same polygon object:

var poly = new google.maps.Polygon({
	clickable:false,
	strokeWeight: 0,
	fillColor: '#000000',
	fillOpacity: 0.4
});

// Outer path then inner path extending from a single lat/lon value
var offset = 0.8;
var paths = [[
	new google.maps.LatLng(lat + offset + 1, lon - offset - 1), //tl
	new google.maps.LatLng(lat + offset + 1, lon + offset + 1), //tr
	new google.maps.LatLng(lat - offset - 1, lon + offset + 1), //br
	new google.maps.LatLng(lat - offset - 1, lon - offset - 1)  //bl
], [
	new google.maps.LatLng(lat + offset, lon + offset), //tr
	new google.maps.LatLng(lat + offset, lon - offset), //tl
	new google.maps.LatLng(lat - offset, lon - offset), //bl
	new google.maps.LatLng(lat - offset, lon + offset)  //br
]];

poly.setPaths( paths );
poly.setMap( map );

but there’s a really big gotcha.

It only works if you draw the two polygons in the reverse directions. If you go clockwise for the first polygon, you need to go counter clockwise for the second or visa-versa. This is due to the polygon winding rules in the various technologies used to draw the map. That was my stumbling point for awhile.

Just thought I’d pass it along.

The post ‘Mmmmm Donuts’ was first published by Jeffrey Sambells on