Sunday, 21 September 2014

Quickly Finding the Center Point and Zoom Level in Google Maps

When I'm putting together Google Maps API applications for demos or classroom exercises, I often start off zoomed into a particular location to spare students the pain of watching my clumsy efforts to find the area I'm interested in.

I've got a couple of methods I use to grab the current zoom level and lat/lng of the center point. I can then put these into a mapOptions object and have the map position itself to this location automatically when the page loads.

Method number one is a little app I wrote specifically for this purpose. You can see it above and access it here.

Just zoom to the extent you want to set your map at and press the "Create MapOptions for this Location" button.

You'll be presented with a dialog box, which formats the current location into a mapOptions object ready for pasting into your app.

There's another way of getting this information though, just by using a little bit of code in your browser console. But be warned: it only works when the variable you use for the map object is global and actually called "map".

Here's the code:
 (function() {console.log("Lat:" + map.getCenter().lat().toFixed(3) + ", Lng:" + map.getCenter().lng().toFixed(3) + " Zoom Level:" + map.getZoom() );})();  

It's pretty ugly, but it does the job. Basically, this is just a self-executing function that calls getter functions on the global map variable, and outputs the display to the console:

Paste code into console and click Run
I don't want to type this out every time I use it, so I have got it configured as a keyboard shortcut using Autohotkey. (If you're on Windows and you haven't checked out AutoHotKey yet, you're doing yourself a disservice. AutoHotKey lets you automate just about any Windows task, from text expansion to changing display resolution, and I'm lost on any machine where my AutoHotKey scripts are not installed.) 

AutoHotKey Script
 :*:@@map::  
 (  
 (function() {console.log("Lat:" + map.getCenter().lat().toFixed(5) + ", Lng:" + map.getCenter().lng().toFixed(5) + " Zoom Level:" + map.getZoom() );})();  
 )  

Without delving into the syntax, this means that every time I type @@map (I had to suspend the script just to type that!), the function executes and returns the map details.

I find these methods useful on an almost daily basis. I hope you get as much mileage out of them as I do! What are your favourite Google Maps API tips?

Tuesday, 9 September 2014

Rubber Band Zooming With the Google Maps API

One of the things I really like about working with Esri’s ArcGIS Server API for JavaScript is the out of the box zoom capability, using what Esri calls “rubber band” zooming.

To zoom in, you just hold down the SHIFT key and draw a rectangle on the map using the mouse. The map then zooms to that extent. To zoom out again, hold down SHIFT and CONTROL and draw another rectangle.

So I got to thinking about what it would take to enable this functionality using the Google Maps API.

First, I needed a way to check which keys are being pressed at the time the map drawing occurs. The approach I used was to store any depressed keys in an array which I can then inspect when the user starts drawing on the map. If the SHIFT key is depressed, then my app needs to take notice, because the user plans to either zoom in (SHIFT + mouse draw), or zoom out (SHIFT + CTRL + mouse draw):

 var keys = [];  
 onkeydown = onkeyup = function(e) {  
      e = e || event; // for IE  
      keys[e.keyCode] = e.type == 'keydown';  
      if (keys[16]) {  
           drawingManager.setMap(map);  
      } else {  
           drawingManager.setMap(null);  
      }  
 }  

If the user has the SHIFT key depressed then they are about to draw an extent on the map, so I enable the Google Maps API DrawingManager. The drawing mode is set to RECTANGLE because a rectangle has a bounds property I can use for the new extent. I want everything to be keyboard-driven, so I hide the drawing control:


 var drawingManager = new google.maps.drawing.DrawingManager({  
      drawingMode: google.maps.drawing.OverlayType.RECTANGLE,  
      drawingControl: false  
 });  

When the user draws on the map, we want to see if either the SHIFT key (keyCode=16) and/or the CTRL key are pressed. (I got the key codes from this handy site.)

If the user is zooming in, then we get the bounds of the rectangle they have drawn on the map and call the map's fitBounds() method to zoom to that extent:

 google.maps.event.addListener(drawingManager, "rectanglecomplete", function(rect) {  
      // user zooming in  
      if (keys[16]) {  
           map.fitBounds(rect.bounds);  
           rect.setMap(null);  
           return;  
      }  
 });  

But what to do about zooming out? To be honest, I'm not 100% sure how Esri implement this, but for my purposes it's good enough just to recenter the map at the center of the rectangle the user has drawn and then zoom out one level:

 google.maps.event.addListener(drawingManager,"rectanglecomplete", function(rect) {  
      // user zooming out  
      if (keys[16] || keys[17]) {  
           map.setCenter(rect.getBounds().getCenter());  
           var zoom = map.getZoom();  
           map.setZoom(--zoom);  
           rect.setMap(null);  
           return;  
      }  
      // user zooming in  
      if (keys[16]) {  
           map.fitBounds(rect.bounds);  
           rect.setMap(null);  
           return;  
      }  
 });  

I check for the user zooming out first (i.e. CTRL (keycode=17) is pressed in addition to SHIFT (keycode=16)), so I can drop to the next test (SHIFT only) if CTRL is not depressed.

You can see the JS Fiddle for it here.

And that's about it. It's not perfect, and I'd want to do a bit more to it if I was using it in a production app, but it's a workable solution. If I'm unhappy about anything it's the zooming out behavior. Could I zoom out based on the size of the extent, perhaps? How would you implement this? Let me know in the comments!

Greetings!

I've been meaning to get this site up and running for a while now, but with the recent release of my very first Pluralsight course, now seemed a good time to do it.

I love maps, and I love the Internet, so putting maps on the web is just about enough to send me over the edge. In this blog I intend to cover many different aspects of web mapping, including, (but certainly not limited to), the Google Maps API and ESRI's ArcGIS API for JavaScript.

So please watch this space. I've got several posts planned over the next couple of weeks, covering all sorts of webmappingy goodness, so I hope you'll find something of interest.

Thanks for stopping by. Don't be a stranger ;)