BRENDAN KENNY: And it's brought you
mostly by Mike Bostock.
And here we can see a bunch of examples.
So the great thing about the d3 is there's just tons and
tons of examples, all with code to let you
know how to do them.
And a big part of the d3 has been geoapplications--
so using geographical data and doing visualizations with this
geographical data.
So for the most part, it seems like d4 lives separately from
something like a Maps application.
But really all it does is, takes data and binds it to
some way of displaying that data.
That's kind of the underlying thesis of d3--
Data Driven Documents is what the d3 stands for.
And so we can take advantage of that, to use kind of d3
skill sets and the tools d3 brings, and put it on top of a
map so that you can put things in place.
So we're going to start with a really simple example, just to
show how this kind of binding to the Maps API works.
So here's a cool example that's been highlighted
recently by Mike.
And it has to do with, well, scale-dependent sampling as it
says on screen--
using the kind of scale of the thing that you're displaying
and the amount of precision that you need to show at that
scale to re-sample a line so that you get a smooth curve.
And you can see here that we have these control points
multiply as you zoom in so you get a
really nice smooth curve.
But as you zoom out it starts eliminating these control
points so that you don't draw too many of these line
segments, filling pixels that you would never see in the
first place.
And so we're going to use that and bring it
over to this example.
So here all I've done is taken that same exact thing.
I've removed the animation just so it's slightly less
distracting.
And whereas this is some triggy projection, this is
just a really simple Mercator projection.
And I've taken a line.
And all I'm doing is saying, show me a line that kind of
undulates around the equator.
And if you want to see what that looks like, it just looks
like this right here.
I'm just defining a line string kind of in this GeoJSON
like format.
And I'm keeping it right on, around the equator.
So here's 20 degrees north past the equator, 20 degrees
south and back again.
And then it just rotates around the earth.
And so the key thing here is, actually we only have five
points-- really four.
It begins and ends at the same point.
But d3 knows that you want to draw a great circle.
And so it actually fills then and smooths that curve for us.
So that's great.
It's now in a different projection, and that's a great
thing about d3 is that you can throw any projection in the
world at it.
But really we want to bring this into Google Maps.
So how do we do this?
So the way that d3 renders paths--
well, the way that most examples of d3 render paths
either falls down to SVG or Canvas.
So these are the two kind of newer browser technologies,
"newer" browser technologies, that let us draw things
dynamically.
So each brings its own benefits.
So SVG lives in the DOM, you can add mouse events to it.
You can select things after the fact and do logic on that
sort of thing.
Whereas Canvas, it gets rasterized,
puts it into display.
But then you get really fast display if you have maybe
thousands or millions of elements.
That's what lets you do WebGL, you can rasterize to an image
and put it on screen, even if it's a huge amount of elements
that you could never put in the DOM.
So each has its trade-offs.
But really, it's actually abstracted.
There's actually an interface that d3 uses to write to these
different graphics contexts.
And there's different methods that it uses that lets you
bind SVG or the Canvas to the thing you want to display, in
this case a path.
You want to draw this red path.
So we're going to use the Canvas kind of method of
binding these things, because it's a little bit easier.
So if you dig into that to d3 docs, you can go to
d3.geo.path here.
And if you look, we can see path.context.
So this is actually used in that code that we were looking
at, where we create a path from that
line around the equator.
And then when that path is being created, actually, we
have a context that we pass it to draw to, sort of.
But if you just look at the code afterwards, you'll see
what I mean.
But you pass through the context and it
binds to that context.
But if you look at these docs, it doesn't actually have to be
a Canvas context.
All it has to do is fulfill a certain interface.
And here are the following methods that you have to
fulfill if you're implementing that interface.
So you beginPath, moveTo, lineTo, arc, and closePath.
And so if you've ever used HTML5 Canvas those should look
very familiar.
Those are the basic drawing tools.
And it allows you to construct paths and then, once you have
that path kind of in your context state, you can either
stroke it or fill it.
But there's no reason, again, that this has to be in Canvas.
Again, it's just an interface.
And we can actually fulfill that ourselves.
And if you look, there's actually scattered throughout
examples-- you'll see places where they cheat.
And they actually pass a context in to buffer objects
into an array, for instance, and then pass that array to a
different way of rendering.
So that's what we're going to do.
We're going to cheat and we're going to implement this
context in terms of the v3 Maps API geometry methods.
So let's go back to the code.
And I've created this really simple thing called the
PolyLineContext.
And it's about as dumb as you can get.
And it relies on the fact that in this case we know we have
just a line.
So we don't have to worry about polygons, for instance,
that might have breaks with different polyline rings that
we then need to fill.
Or we don't have to worry about arcs.
We know that it's never actually going to call arcs.
Because we'd be in trouble if it tried to call an arc.
So we've implemented these four methods on this polyline
context, or five methods.
And most of them do nothing.
So beginPath, we don't really care.
It doesn't do anything.
In that case you could've made it so it creates a new
polyline, for instance.
The same thing with arc and closePath.
These are just empty functions, and in fact they're
never actually called by the path code.
And the important ones are moveTo and lineTo.
And I've made a really simple method here.
It's actually the same for both, where if a current path
is selected--
sorry, a polyline on the map is selected, then I create a
LatLng object and push that on to the polyline path array.
And so if we go to the map code, we have two
things going on here.
We have-- first we initialize a map, just like always.
And on that map we make a polyline.
And then we init d3 to do the same thing as in
the previous example.
But now instead of context from a Canvas, now we're doing
a polyline context, that context we just made up.
And when we create our path object, that's with our
equi-rectangular projection so that we can do-- just like an
identity projection.
We pass that to the context.
So now, we're finally at the point when we can
actually draw this.
And so to draw it we've changed our style methods that
set properties on Canvas context to setting those
options on the polylines.
So we have a red and a stroke weight of two.
And then we set our current polyline, that's part of the
polyline context that we wrote.
And finally, we just pass it to this path method that we
created up here.
And that projects those points and then passes it to the
context through those five functions, or
really two in this case.
And just calls point, point, point, point, point.
And so finally we can take a look at what that looks like.
And if we refresh we can see that we have this line.
In fact, let's make it a little thicker, just a little
bit more obvious.
You can see this path that we've created.
And so we're actually using the d3, all its different
machinery, and then driving these points on the map.
So this could be anything.
So in this case I created a simple GeoJSON in code.
But you can bring that GeoJSON in.
You can use topojson, which is natively supported by d3.
You can use any sort of thing and pass it in to draw these
draw commands.
And then, just like we drew these polylines, we can also
draw polygons, that sort of thing.
You just have to be careful with your context.
And so just as a last, really simple example, we can see as
we zoom in we get these hard corners here where you see a
definite angle.
So we're not adaptively re-sampling.
And so we can actually do a couple of things there.
We can tell that d3 that the scale has changed.
Or we can totally cheat and go to the console here and just
set the precision of the projection manually.
So here we've moved to a much smoother polyline.
And we can even do that-- so on Zoom, for instance, we can
change the precision of the polyline if we
wanted to do that.
And it goes the other way, too.
We can set so it's just like this very angular thing.
And so, as you can see, it's the full pipeline.
It's really easy to bind.
And so that's something to keep in mind in the future
when you're looking at kind of, I want d3.
But I also want to put on a map if it actually needs to be
in context.
And so there's no reason why these can't live together. d3
is designed exactly for this kind of adaptability.
So try it out.
Check out the code, where it's going to be in a simple gist
linked on the video.
And let me know what you think.
And if anything interesting comes up we can covered in
future Maps Shortcuts.
Thanks.