Duncan's blog

October 19, 2013

Google maps – map size

Filed under: Google Maps,Javascript — duncan @ 10:47 am
Tags: , ,

I posted an answer in response to this question on StackOverflow, ‘How can I know the actual scale that my Google maps is currently in?‘.  Which perhaps didn’t exactly answer Joaquín M‘s problem, but I thought was useful enough anyway to warrant its own blog post, in my infrequent Google Map API series.  In his question he stated “The information I need is the actual width in kilometers of my map“, which my answer does do.

What we want to do is have an event listener for whenever the size of the map changes, using the bounds_changed event.  This way we get the updated size if the user resizes the window or adjusts the zoom.  And in fact this also happens when the map first appears.  If we try and use map.getBounds() within our initialize function, we run the risk of calling it too soon before the map has fully rendered, so we need that event listener.

We can find out the map’s size from its bounds, which represent a rectangular box of what’s currently visible.  But from the bounds object, we can only find out the coordinates for its north-east and south-west corners.  So we’ve still got a bit of work to do to turn this into a distance.

We’ll need to use the geometry library to turn degrees into metres.  So we specify libraries=geometry in the Google Maps API URL.

Let’s assume we have a map with its north-east coordinates as (lat1, lng1) and its south-west coordinates as (lat2, lng2), e.g.:

map1-001

Sidenote: confusingly whenever I look at coordinates I always think of Cartesian coordinates, e.g. (x, y), where the first value x represents the horizontal value, and the second value y represents the vertical value.  However when dealing with LatLng objects in Google Maps it’s always latitude first (degrees north/south from the equator), then longitude second (degrees east/west from the Greenwich meridian).  So that’s how I’ll be referring to them here.

I’m assuming we want to calculate both the width and height of the bounds, not just its area or the diagonal distance between the two corners.  So what we really need to do is work out the vertical distance from lat1 to lat2, and then the horizontal distance from lng1 to lng2.  To do this we have to construct LatLng objects representing the points (lat1, lng1) and (lat2, lng1) [fig 1] for the vertical distance.  And again (lat1, lng1) and (lat1, lng2) [fig 2] for the horizontal.  Or equally we could have done (lat1, lng2) – (lat2, lng2), and then (lat2, lng1) – (lat2, lng2).

map1(1)

Fig 1

Fig 2

Fig 2

I could have simply put all the below into the initialize function.  However certain parts of it made sense to put into their own functions, as they could then easily be re-used, e.g. for any time we might want the distance between any two points on the map, or for calculating the distance of any rectangular area on the map.

<!DOCTYPE html>
<html>
<head>
<title></title>

<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<style type="text/css">
html { height: 90% }
body { height: 100%; margin: 0; padding: 0 }
#map_canvas { height: 100% }
</style>

<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false&libraries=geometry"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>

<script type="text/javascript">
    function initialize() {
        var homeLatlng = new google.maps.LatLng(51.476706,0); // London

        var myOptions = {
            zoom: 15,
            center: homeLatlng,
            mapTypeId: google.maps.MapTypeId.ROADMAP
        };

        var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);

        google.maps.event.addListener(map, 'bounds_changed', function() {            
            var bounds = map.getBounds();

            var sizes = getBoundsSize(bounds);

            $('#size').text(sizes.horizontalkm + ' km horizontal, ' + sizes.verticalkm + ' km vertical');
        });
    }

    function getBoundsSize(bounds) {
        var sizes, NE, SW, lat1, lat2, lng2, lng2, horizontalLatLng1, horizontalLatLng2, verticalLatLng1, verticalLatLng2, horizontal, vertical;

        // get the coordinates for the NE and SW corners
        NE = bounds.getNorthEast();
        SW = bounds.getSouthWest();

        // from that, figure out the latitudes and the longitudes
        lat1 =  NE.lat();
        lat2 =  SW.lat();

        lng1 =  NE.lng();
        lng2 =  SW.lng();

        // construct new LatLngs using the coordinates for the horizontal distance between lng1 and lng2
        horizontalLatLng1 = new google.maps.LatLng(lat1,lng1);
        horizontalLatLng2 = new google.maps.LatLng(lat1,lng2);

        // construct new LatLngs using the coordinates for the vertical distance between lat1 and lat2
        verticalLatLng1 = new google.maps.LatLng(lat1,lng1);
        verticalLatLng2 = new google.maps.LatLng(lat2,lng1);

        // work out the distance horizontally
        horizontal = getDistance(horizontalLatLng1, horizontalLatLng2);

        // work out the distance vertically
        vertical = getDistance(verticalLatLng1, verticalLatLng2);

        // round to kilometres to 1dp
        sizes = {
            horizontalkm: convertMetresToKm(horizontal),
            verticalkm:   convertMetresToKm(vertical)
        };

        return sizes;
    }

    function getDistance(point1, point2) {
        // computeDistanceBetween is fine if we only have 2 points, but if we have more we need to use computeLength
        return google.maps.geometry.spherical.computeDistanceBetween(point1, point2);
    }

    function convertMetresToKm(metres) {
        return Math.round(metres / 1000 *10)/10;    // distance in km rounded to 1dp
    }

    google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
    <div id="map_canvas"></div>
    <div id="size"></div>
</body>
</html>

And finally you end up with a map looking something like this, and as you zoom or resize the window, the sizes update.
gmap

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: