BRENDAN KENNY: Hi, this is Brendan Kenny.
I'm an engineer with the Google Maps Developer
Relations team.
Today, I wanted to share with you a few simple tips on how
the Chrome developer tools can make developing with the
Google Maps APIs a whole lot easier.
Now, if you've never opened up the dev tools before, you can
do so by coming up here to the Wrench menu, dropping down to
Tools, and selecting Developer Tools.
You can also use the really handy keyboard shortcuts,
Command Option I on the Mac, and Control Shift I
on Windows and Linux.
Now, once they're opened up, you should see something
familiar if you've ever used the developer tools on a lot
of the major browsers.
Over here on the left, we have an outline of all the DOM
elements in the page.
And if we select one, on the right, you'll see the matching
CSS rules and the styles they apply to that element.
But we're not that interested in that today.
Instead, I'd like to stop by the network panel where, if we
load a map, we can see all the files that had to be loaded in
order to put this page in a map on the screen.
What's good about this is we can look at any individual
file and see if there's some kind of network problem, see
if it's too large or bloated, and we need
to shrink that image.
We can also see timing information to see how long it
took for the server to respond.
And then finally, download that file.
So that's pretty helpful.
But what we're most interested in today is here in the
developer console.
Now, what the developer console gives us is actually
an interactive JavaScript execution environment.
What's more, it's the same execution environment that the
page itself is running in.
What this means is that the code that we write on our
page, and any code that we've loaded, like the Google Maps
API, is actually code that we can interact with
right now at runtime.
Now, since maps are such a visual medium, this provides a
great way to tweak our code and algorithms and see the
results instantly, as opposed to going back to our source
code, making an edit, saving, and then refreshing every time
we want to make a small change.
Now, in order to take advantage of this, we have to
make a slight change to our source code so that everything
that we need is in the global scope and we can find it right
here in the console.
So if we switch over, we can see that this map is a pretty
typical "Hello, World" example of the Maps API.
We start off with an options object, which gives it a
default view and a map type.
We take that options object and a DOM element, and we can
create our map itself.
Now, the problem here is we're keeping a
reference to the map.
But we're declaring that
reference inside this function.
So as soon as this function is over, this reference is gone.
Now instead, we can take that reference and declare it
outside in the global scope.
And now, if we save and return to our page.
Now, if we refresh and write "map" here, you can actually
see that the console provides us with an interactive
representation of the map object.
You might even recognize some of the Maps API here.
So just as I said, we can now interact with this just as we
would in the code on the page.
So if I write map.getZoom, I can see the current zoom.
But I can actually set things as well.
So just as a really simple example, map.setZoom5 gives us
a nice, zoomed out view of Sydney.
Now, this actually brings up one of the things that is
really handy just for setting up even a basic map.
You want the perfect view to start off.
So maybe you want to start off looking at Japan.
So we find our nice view here.
We come back down to the console.
And you see that things have gotten kind of crowded with
these network errors and warnings.
So one really nice thing you can write is "clear." And
that'll actually clear the console.
So I want to look at this view every time I
want to open the map.
So I can actually ask the map, what is the current view?
So map.getZoom tells us level 10.
And I can do map.getCenter to find out the center.
But that will return a latlong object.
And I'll have to look at it and interrogate it.
But what I can do to be extra sneaky, I know there's a
toString method on here that will give me a string
representation of the latitude and longitude of the
center of the map.
So now, I can copy this, go back to the source code, paste
it into the beginning.
And I know I need to change my zoom to level 10.
And when I save this and then refresh the page, you can see
that I'm now starting exactly where I wanted to.
Let's look at a slightly more advanced example.
Now here, we have the amazing wireframe that my designer
gave me for our new site.
So I've taken that wireframe and dropped it into the
background of this page.
And he's told me that a map needs to go here in this
center area.
So I've re-structured the page a bit, put a div there, and
dropped a map in it.
But as you can clearly see, nothing is there.
So let's open up the dev tools and try to figure out
what's going on.
The first thing we notice is this JavaScript error-- cannot
set property position of undefined.
Now, the problem is I never set a property named position
at any point in my code, so that seems a little bit odd.
If I dropped down this arrow here, I can actually see a
stack trace of all the functions that were called
that led to this error.
But once again, I see a bunch of function names
that I don't recognize.
[? Nee ?] and [? To ?]
[? j.O ?] aren't functions that I ever
wrote in my own code.
And the explanation for this can be found here on the right
where you can see that all these errors
took place in main.js.
That's a JavaScript file that was loaded by the
Maps API, not by me.
Now, my first instinct might be to go file a
bug on the Maps API.
After all, the error is happening in their code.
But I have a sneaking suspicion that the problem
actually lies in my own.
I started with known, good, working code, the earlier
example, and added to it and changed it until I could get
it to work in this design.
So it's possible I introduced a bug somewhere in the steps
in between.
There are few ways we can track down this problem.
One is the old fashioned brute force method of starting with
a known, good code, and then adding the new code line by
line, saving and refreshing every time, until we finally
encounter the bug.
A somewhat better approach would be to
use the console object.
Console is an object that lives on the window in the
global scope and provides an API so that your JavaScript
code can utilize the developer console here just as if you
were sitting here typing on it.
Now, one of the most helpful methods that it provides is
the log method, which basically just logs statements
to the developer console.
So it's just console.log and some value.
So here's a string.
And there you go.
So let's switch over to the source for this page.
And you can see things are mostly the same here.
And so I'm going to guess that maybe I changed something in
my options that caused a problem.
So I'm just going to add a console.log
statement here, my options.
And we save it, and come back here, and refresh.
Now, we can see before this error statement, I do indeed
have an object here.
And I can look.
And as we did before, we can see that, well, OK, the center
look rights.
The map ID looks right.
And zoom looks right.
So maybe that's not the issue.
So let's switch back over to our source code.
And here, we have the log statement.
And now, we can add one after map div and
make sure that's OK.
And one after map, and make sure that's OK.
But you can tell as this scales to hundreds and
thousands of lines of code, it's not really feasible
anymore to use console.log.
Log is great for actual logging.
But if you have hundreds and thousands of lines to go
through to find out where the problem occurred, you really
haven't made your problem any easier.
So let's get rid of this console.log statement.
Go back to our page.
So the last approach I want to take to solving this problem
lies in the scripts panel.
Now, the scripts panel has kind of an intimidating UI.
And I think a common first reaction to seeing it is, the
JavaScript problem you're facing today isn't tough
enough to justify the time it'll take to learn how to use
the scripts panel.
But it turns out the tools available here are enough to
solve basically any JavaScript problem.
So it's really worth at least trying out.
Here on the left, you can see all the JavaScript files that
were loaded to create this page.
This can be a little confusing at first, until you notice
that the top of each tree has the domain listed.
So here, localhost is where I'm hosting most of my files.
And mapgrid.html is my main page.
So when I open it up, you can see the full source of the
page, and then down here, the actual
JavaScript that's executing.
Now, like the debuggers in many languages, the scripts
panel provides a way to set break points.
So if I click here on a line of code, the JavaScript engine
will actually pause execution when it reaches this line and
allow me to inspect the state interactively.
Now, the problem here is, of course, that the break point
is in the initialized function, which is executed
when the page is first loaded.
But as long as we have the developer tools open, we can
actually refresh the page, and Chrome will remember our break
point and pause there.
So now, we've paused before things have even started in
our initialized function.
And so now, we can take a look at what's going on.
Up here in the top right, we have the buttons that control
our experience during this debugging session.
First, we have a Resume button.
That just resumes execution as if there
never was a break point.
We have a Step Over button, and this will let us move from
line to line and actually see how each line develops within
this function.
And then, we actually have a Step Into button that will go
and dig down into any functions that we encounter so
we can see what's going on in those functions as well.
Now, in this case, we don't really have any function calls
that we're interested in.
We have a latlong and map constructors, but that's just
obfuscated code.
And then, we have actually the selector for the map canvas
div, but that just digs into jQuery code.
So in this case, we're only going to be using the Step
Over button.
So below here, you can see all the variables we're going to
be using within this function.
The map div objects, we're going to be initializing down
here, and the myOptions object, we're about to
initialize.
And if you're really brave, you can see all the global
variables that are available at this point.
The problem is there's a whole lot of them.
Everything that's declared in the window is listed here.
But if you scroll down to "M," you can see our lonely, little
map that we're going to be constructing soon.
And we put it in the global scope here.
But we're not that interested in the global variables, so
let's collapse that.
And we can start looking through this
code step by step.
So if we hit Step Over, we execute this statement.
And the myOptions object is now initialized.
And you can see, just as when we logged it to the
console.log, everything looks OK.
We have a center, and we have the correct map type ID, and
the correct zoom.
So let's keep going.
In this next line, we use jQuery to select the correct
map canvas div that we're going to use
to create the map.
So if we execute that statement, we can now see
something strange.
mapdiv is set to [? e.fn.e.anet1 ?], which is
definitely not what we'd expect.
We'd expect some kind of
representation of a DOM element.
Once again, our secret weapon for figuring out what's going
on is the developer console.
Now, I could go over to the developer console panel.
Or I could hit Escape and get a mini one right here.
So I want to figure out what's going on with mapdiv, so I'll
just log that and see what's going on.
And it looks like I do have the correct DOM element.
But it's inside of an array for some reason.
So at this point, I would know that this came back from the
jQuery function.
So I'd go and check the jQuery docs.
And I'd remember that the jQuery function doesn't return
the selected objects directly.
It actually creates a new jQuery object with those
objects associated with it.
Now, this is great for jQuery because it allows all the
really fun jQuery function chaining that
you can do with jQuery.
The problem is the Maps API expects a DOM element
directly, and not something wrapped up in another object.
To fix the issue, I want to come back to my source code.
And there's a couple of ways you can do this.
But the easiest one, I find, is just .get(0).
And since I know this is an ID and there's only one of them,
"0" is the appropriate index to use.
I save it, come back here.
And I can exit from dev tools.
And when I refresh the page, there's my map.
And there's the basic introduction to using the
Chrome developer tools with the Google Maps APIs.
If you don't use any developer tools today, you should really
try them out.
And I think you'll find your life as a developer will
become considerably easier.
And you'll be able to concentrate on problems that
actually matter.
If you'd like to know more, you can visit this link.
And you can find a list of all the commands and APIs
available, as well as further screencasts that gives more
information into using developer tools.