Macejkou
Macejkou

Reputation: 686

Draw ring (not circle) in Google Maps API

I would like to draw a ring 20km thick with empty 5km circle inside. I dont how how to do it. I believe it is possible.

One simple solution could be to substract one 5km circle from 25km circle. Is it possible? Thank you for any tips.

Upvotes: 3

Views: 3378

Answers (4)

Cutetare
Cutetare

Reputation: 909

For anyone who landed here while trying to draw a donut on Google My Maps, for me the following worked:

  1. Draw the outer polygon with the "Add line or shape" tool

  2. Draw the inner polygon with the "Add line or shape" tool (just put it on top of the first one, don't care about the hole yet)

  3. On the layer, click the three dots menu, then "Export data" > "CSV". Save the file on your computer

  4. Open the CSV file you just exported, and edit it with a text editor, so that it has the format:

    WKT,name,description "POLYGON ((Outer_polygon_coordinates),(inner_polygon_coordinates))",Polygon Name,

  5. Save the csv in the format above.

  6. Import the csv back into google my maps. It now has the correct format :)

Upvotes: 0

Matth
Matth

Reputation: 159

Ok, so based on geocodezip's answer, I adapted the function to draw a donut on Google Maps that caters for the distortion of the map. The function calculates 360 Lat/Lon points of the circle, based on a center point and the radius. The Lat/Lon is calculated as the bearing (0 to 360 degree/points) and distance from the center.

function drawCircle(point, radius, dir) {
 
  var olat = point[0] * Math.PI / 180;
  var olon = point[1] * Math.PI / 180;
  var ERadius = 6371;  // Radius of the earth
  var points = 360;    // Calculate number of points
  
  var circle = new Array();
  
  if (dir == 1) {
    var start = 0;
    var end = points + 1;
  } else {
    var start = points + 1;
    var end = 0;
  }
  for (var i = start; (dir==1 ? i < end : i > end); i = i + dir) {

     var Bearing = i * Math.PI / 180;
     var cLat = Math.asin(Math.sin(olat)*Math.cos(radius/ERadius)+Math.cos(olat)*Math.sin(radius/ERadius)*Math.cos(Bearing)) * 180 / Math.PI;
     var cLon = (olon + Math.atan2(Math.sin(Bearing)*Math.sin(radius/ERadius)*Math.cos(olat), Math.cos(radius/ERadius)-Math.sin(olat)*Math.sin(Math.asin(Math.sin(olat)*Math.cos(radius/ERadius)+Math.cos(olat)*Math.sin(radius/ERadius)*Math.cos(Bearing))))) * 180 / Math.PI;
     circle.push(new google.maps.LatLng(cLat, cLon));
     bounds.extend(circle[circle.length-1]);  
  }
  return circle;
}

Based on that, you can use the following function to draw the donut.

      var donut  = new google.maps.Polygon({ paths: [drawCircle([22.3089, 113.9150], 5000, 1), drawCircle([22.3089, 113.9150], 9000, -1)], strokeColor: "#AA0000",strokeWeight: 0,fillColor: "#AA0000",fillOpacity: 0.25 });
      donut.setMap(map);

The example above is centered in Hong Kong and has in inner circle with a radius of 5,000km, and an outer circle with a radius of 9,000km. This should produce a donut like this: enter image description here

Upvotes: 0

geocodezip
geocodezip

Reputation: 161334

Create a drawCircle function:

function drawCircle(point, radius, dir) { 
var d2r = Math.PI / 180;   // degrees to radians 
var r2d = 180 / Math.PI;   // radians to degrees 
var earthsradius = 3963; // 3963 is the radius of the earth in miles

   var points = 32; 

   // find the raidus in lat/lon 
   var rlat = (radius / earthsradius) * r2d; 
   var rlng = rlat / Math.cos(point.lat() * d2r); 


   var extp = new Array(); 
   if (dir==1)  {var start=0;var end=points+1} // one extra here makes sure we connect the
   else     {var start=points+1;var end=0}
   for (var i=start; (dir==1 ? i < end : i > end); i=i+dir)  
   { 
      var theta = Math.PI * (i / (points/2)); 
      ey = point.lng() + (rlng * Math.cos(theta)); // center a + radius x * cos(theta) 
      ex = point.lat() + (rlat * Math.sin(theta)); // center b + radius y * sin(theta) 
      extp.push(new google.maps.LatLng(ex, ey)); 
      bounds.extend(extp[extp.length-1]);
   } 
   // alert(extp.length);
   return extp;
   }

Then you can use it like this:

  var donut = new google.maps.Polygon({
                 paths: [drawCircle(new google.maps.LatLng(-33.9,151.2), 100, 1),
                         drawCircle(new google.maps.LatLng(-33.9,151.2), 50, -1)],
                 strokeColor: "#0000FF",
                 strokeOpacity: 0.8,
                 strokeWeight: 2,
                 fillColor: "#FF0000",
                 fillOpacity: 0.35
     });
     donut.setMap(map);

Note that the inner circle needs to "wind" opposite the outer circle.

Example (as posted by Dr Molle)

code snippet:

function drawCircle(point, radius, dir) {
  var d2r = Math.PI / 180; // degrees to radians 
  var r2d = 180 / Math.PI; // radians to degrees 
  var earthsradius = 3963; // 3963 is the radius of the earth in miles

  var points = 32;

  // find the raidus in lat/lon 
  var rlat = (radius / earthsradius) * r2d;
  var rlng = rlat / Math.cos(point.lat() * d2r);


  var extp = new Array();
  if (dir == 1) {
    var start = 0;
    var end = points + 1
  } // one extra here makes sure we connect the
  else {
    var start = points + 1;
    var end = 0
  }
  for (var i = start;
    (dir == 1 ? i < end : i > end); i = i + dir) {
    var theta = Math.PI * (i / (points / 2));
    ey = point.lng() + (rlng * Math.cos(theta)); // center a + radius x * cos(theta) 
    ex = point.lat() + (rlat * Math.sin(theta)); // center b + radius y * sin(theta) 
    extp.push(new google.maps.LatLng(ex, ey));
    bounds.extend(extp[extp.length - 1]);
  }
  // alert(extp.length);
  return extp;
}

var map = null;
var bounds = null;

function initialize() {
  var myOptions = {
    zoom: 10,
    center: new google.maps.LatLng(-33.9, 151.2),
    mapTypeControl: true,
    mapTypeControlOptions: {
      style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
    },
    navigationControl: true,
    mapTypeId: google.maps.MapTypeId.ROADMAP
  }
  map = new google.maps.Map(document.getElementById("map_canvas"),
    myOptions);

  bounds = new google.maps.LatLngBounds();

  var donut = new google.maps.Polygon({
    paths: [drawCircle(new google.maps.LatLng(-33.9, 151.2), 100, 1),
      drawCircle(new google.maps.LatLng(-33.9, 151.2), 50, -1)
    ],
    strokeColor: "#0000FF",
    strokeOpacity: 0.8,
    strokeWeight: 2,
    fillColor: "#FF0000",
    fillOpacity: 0.35
  });
  donut.setMap(map);

  map.fitBounds(bounds);

}
google.maps.event.addDomListener(window, "load", initialize);
html,
body,
#map_canvas {
  height: 100%;
  width: 100%;
  margin: 0px;
  padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
<div id="map_canvas"></div>

Upvotes: 6

Gerrit-K
Gerrit-K

Reputation: 1308

Here's a slightly modified version of geocodezip's answer using the geometry library:

function getCirclePoints(center, radius, numPoints, clockwise) {
    var points = [];
    for (var i = 0; i < numPoints; ++i) {
        var angle = i * 360 / numPoints;
        if (!clockwise) {
            angle = 360 - angle;
        }

        // the maps API provides geometrical computations
        // just make sure you load the required library (libraries=geometry)
        var p = google.maps.geometry.spherical.computeOffset(center, radius, angle);
        points.push(p);
    }

    // 'close' the polygon
    points.push(points[0]);
    return points;
}

You can use it like this:

new google.maps.Polygon({
    paths: [
        getCirclePoints(yourCenter, outerRadius, numPoints, true),
        getCirclePoints(yourCenter, innerRadius, numPoints, false)
    ],
    /* other polygon options */
 });

Edit:

The geometry API can be added in Node like this (thanks to Gil Epshtain):

require('google-maps-api')(GOOGLE_API_KEY, ['geometry'])

By the time I was writing this, I used plain old JavaScript inclusion in HTML:

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

For more information, please refer to the API page of the geometry library.

Upvotes: 1

Related Questions