You might want to solve this problem by adding extra circles at x intervals with increasing radii between each waypoint. This would be very easy to implement and would work for any direction of the cyclone. Obviously, Matti proposed a solution to create a polygon, connecting all the tangents would be more accurate, but you can consider this as a possible alternative. The main disadvantage is that it may take some effort to make it look beautiful, and it will obviously use more resources on the client side than if you were displaying one polygon.
Let's start by re-creating your map:
<!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> <title>Google Maps Cyclones</title> <script src="http://maps.google.com/maps/api/js?sensor=false" type="text/javascript"></script> </head> <body> <div id="map" style="width: 600px; height: 400px"></div> <script type="text/javascript"> var i; var mapOptions = { mapTypeId: google.maps.MapTypeId.TERRAIN, center: new google.maps.LatLng(28.50, -81.50), zoom: 5 }; var map = new google.maps.Map(document.getElementById("map"), mapOptions); var pathPoints = [ new google.maps.LatLng(25.48, -71.26), new google.maps.LatLng(25.38, -73.70), new google.maps.LatLng(25.28, -77.00), new google.maps.LatLng(25.24, -80.11), new google.maps.LatLng(25.94, -82.71), new google.maps.LatLng(27.70, -87.14) ]; pathPoints[0].radius = 80; pathPoints[1].radius = 100; pathPoints[2].radius = 200; pathPoints[3].radius = 300; pathPoints[4].radius = 350; pathPoints[5].radius = 550; new google.maps.Polyline({ path: pathPoints, strokeColor: '#00FF00', strokeOpacity: 1.0, strokeWeight: 3, map: map }); for (i = 0; i < pathPoints.length; i++) { new google.maps.Circle({ center: pathPoints[i], radius: pathPoints[i].radius * 1000, fillColor: '#FF0000', fillOpacity: 0.2, strokeOpacity: 0.5, strokeWeight: 1, map: map }); } </script> </body> </html>
Google Maps Cyclones - Figure 1 http://img186.imageshack.us/img186/1197/mp1h.png
I assume that you have already reached this point, and therefore the above example is self-explanatory. In fact, we just identified 6 points along with 6 radii, and we drew circles on the map along with the green track.
Before continuing, we need to define several methods so that we can calculate the distance and direction from one point to another. We will also need a method that will return the destination if there is a bearing and the distance traveled from the starting point. Fortunately, Chris Veness offers a very good JavaScript implementation for these methods in the section Calculating the distance, bearing, and other points between latitude and longitude . The following methods have been adapted to work with Google google.maps.LatLng :
Number.prototype.toRad = function() { return this * Math.PI / 180; } Number.prototype.toDeg = function() { return this * 180 / Math.PI; } google.maps.LatLng.prototype.destinationPoint = function(brng, dist) { dist = dist / 6371; brng = brng.toRad(); var lat1 = this.lat().toRad(), lon1 = this.lng().toRad(); var lat2 = Math.asin( Math.sin(lat1)*Math.cos(dist) + Math.cos(lat1)*Math.sin(dist)*Math.cos(brng) ); var lon2 = lon1 + Math.atan2(Math.sin(brng)*Math.sin(dist)*Math.cos(lat1), Math.cos(dist)-Math.sin(lat1)*Math.sin(lat2)); if (isNaN(lat2) || isNaN(lon2)) return null; return new google.maps.LatLng(lat2.toDeg(), lon2.toDeg()); } google.maps.LatLng.prototype.bearingTo = function(point) { var lat1 = this.lat().toRad(), lat2 = point.lat().toRad(); var dLon = (point.lng()-this.lng()).toRad(); var y = Math.sin(dLon) * Math.cos(lat2); var x = Math.cos(lat1)*Math.sin(lat2) - Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon); var brng = Math.atan2(y, x); return ((brng.toDeg()+360) % 360); } google.maps.LatLng.prototype.distanceTo = function(point) { var lat1 = this.lat().toRad(), lon1 = this.lng().toRad(); var lat2 = point.lat().toRad(), lon2 = point.lng().toRad(); var dLat = lat2 - lat1; var dLon = lon2 - lon1; var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLon/2) * Math.sin(dLon/2); return 6371 * (2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))); }
Then we would need to add another loop that renders the intermediate circles inside the for loop that we used earlier to render the original circles. Here's how to do it:
var distanceStep = 50; // Render an intermediate circle every 50km. for (i = 0; i < pathPoints.length; i++) { new google.maps.Circle({ center: pathPoints[i], radius: pathPoints[i].radius * 1000, fillColor: '#FF0000', fillOpacity: 0.2, strokeOpacity: 0.5, strokeWeight: 1, map: map }); if (i < (pathPoints.length - 1)) { distanceToNextPoint = pathPoints[i].distanceTo(pathPoints[i + 1]); bearingToNextPoint = pathPoints[i].bearingTo(pathPoints[i + 1]); radius = pathPoints[i].radius; radiusIncrement = (pathPoints[i + 1].radius - radius) / (distanceToNextPoint / distanceStep); for (j = distanceStep; j < distanceToNextPoint; j += distanceStep, radius += radiusIncrement) { new google.maps.Circle({ center: pathPoints[i].destinationPoint(bearingToNextPoint, j), radius: radius * 1000, fillColor: '#FF0000', fillOpacity: 0.2, strokeWeight: 0, map: map }); } } }
Here is what we would get:

And this is how it would have looked without black strokes around the original circles:
Google Maps Cyclones - Figure 3 http://img181.imageshack.us/img181/2908/mp3t.png
As you can see, the main task will be to make the circles opaque, even if they overlap. There are several options for achieving this, but this may be the subject of another question.
In any case, the following implementation is the full implementation for this example:
<!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> <title>Google Maps Cyclones</title> <script src="http://maps.google.com/maps/api/js?sensor=false" type="text/javascript"></script> </head> <body> <div id="map" style="width: 600px; height: 400px"></div> <script type="text/javascript"> Number.prototype.toRad = function() { return this * Math.PI / 180; } Number.prototype.toDeg = function() { return this * 180 / Math.PI; } google.maps.LatLng.prototype.destinationPoint = function(brng, dist) { dist = dist / 6371; brng = brng.toRad(); var lat1 = this.lat().toRad(), lon1 = this.lng().toRad(); var lat2 = Math.asin( Math.sin(lat1)*Math.cos(dist) + Math.cos(lat1)*Math.sin(dist)*Math.cos(brng) ); var lon2 = lon1 + Math.atan2(Math.sin(brng)*Math.sin(dist)*Math.cos(lat1), Math.cos(dist)-Math.sin(lat1)*Math.sin(lat2)); if (isNaN(lat2) || isNaN(lon2)) return null; return new google.maps.LatLng(lat2.toDeg(), lon2.toDeg()); } google.maps.LatLng.prototype.bearingTo = function(point) { var lat1 = this.lat().toRad(), lat2 = point.lat().toRad(); var dLon = (point.lng()-this.lng()).toRad(); var y = Math.sin(dLon) * Math.cos(lat2); var x = Math.cos(lat1)*Math.sin(lat2) - Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon); var brng = Math.atan2(y, x); return ((brng.toDeg()+360) % 360); } google.maps.LatLng.prototype.distanceTo = function(point) { var lat1 = this.lat().toRad(), lon1 = this.lng().toRad(); var lat2 = point.lat().toRad(), lon2 = point.lng().toRad(); var dLat = lat2 - lat1; var dLon = lon2 - lon1; var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLon/2) * Math.sin(dLon/2); return 6371 * (2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))); } var i; var j; var distanceToNextPoint; var bearingToNextPoint; var radius; var radiusIncrement; var distanceStep = 50; </script> </body> </html>