Mapping with D3
eyeseast.github.com
eyeseast.github.com
var counties = map.append('g');
counties.attr('class', 'counties')
.selectAll('path')
.data(countylines.features)
.enter().append('path')
.attr('d', path);
counties.on('mouseover', function(){
if (d3.event.target.tagName == "path")
showCaption();
})
.on('mouseout', function() {
if (d3.event.target.tagName != "path")
caption.html(starter);
});
You also don't need to repeat the process on mousemove, that triggers dozens of events per second for what mouseover and mouseout already accomplished.Try it out, I'm sure it will feel snappier.
Source is up at https://github.com/idan/telostats, janky though it may be. This was my first effort with geo and D3, and I'm a python person, so the JS is probably eight different kinds of terrible, but hopefully it's useful. There are a lot of examples like the OP's blogpost where D3 is used to render geometry, but very few that show you how to use D3 as an informational layer above an existing slippymap (which is what we did).
Additionally, smoothing shapefiles with tools like http://mapshaper.org can really help trim down filesizes.
There's still some issues we're having. SVG rendering performance isn't fast or consistent across browsers for 3000+ polygons and although TopoJSON shares arcs between common boundaries the rendered polygons don't. Also the large differences in the size of boundaries we're dealing with means the map needs to be zoom-able. Delivering higher detail boundaries dynamically is tough problem to solve. Ideally you could request a bounding box from a TopoJSON based server, and it would deliver a delta of higher detailed points precomputed from Visvalingam’s algorithm[2].
I found the default quantization level to be much too blocky. For anyone working with TopoJSON I'd recommend you first raise the quantization level while looking at your smallest features until they're no longer blocky, then use the inbuilt simplification to bring the file size down to manageable.
[1]: http://www.bts.nsw.gov.au/BTS-Visual [2]: http://bost.ocks.org/mike/simplify/ (explained at the bottom)
A useful technique with zoomable geometry is using Visvalingam's algorithm to precompute the salience (visual importance) of each point, but not prefiltering; then, you filter the points based on the zoom level during rendering. Thus, the rendered detail increases as you zoom in, but you only need to download one TopoJSON file.
Depending on how much zooming you're doing, breaking the geometry into tiles and zoom-level specific data would be helpful (à la Polymaps), but I think for many visualization applications it's overkill. For example, a single TopoJSON file of U.S. states and counties with enough detail for both a national and state-specific view is easily doable without tiling.
The next release of D3 (3.0) includes streaming geometry transformations. This can enable fast filtering of geometry using the precomputed salience during rendering as described above without the overhead of creating multiple copies of the geometry during the rendering pipeline. Also, D3 3.0 supports rendering directly to Canvas, which is excellent for animated or interactive changes to the projection. For example:
You can see the stream interface here:
https://github.com/mbostock/topojson/wiki
TopoJSON's --simplify flag uses Visvalingam's algorithm. And, since it's the mesh that is simplified rather than independent features, shared borders between features will be preserved. Without this feature, you end up with something that resembles shattered glass: