Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Achieving animated zoom with d3 and Leaflet

Tags:

Using d3 to plot SVG artefacts on top of a Leaflet map is a simple way to get a solid map controller combined with the strength of d3. There are numerous examples and guides as how to achieve this and the two main approaches seem to be:

  1. Appending a new SVG element on Leaflet's "overlay pane" as demonstrated by Bostock here: http://bost.ocks.org/mike/leaflet/

  2. Implementing a custom vector tile layer that hooks in to Leaflets native tile layer ecosystem as demonstrated by Nelson Minar here: http://bl.ocks.org/NelsonMinar/5624141

The first approach avoids Leaflets scale-based zooming by attaching a leaflet-class so that any d3-elements are hidden while the scaling takes place. When the zoom animation is over, the element coordinates are re-calculated and redrawn whereafter the hide-class is removed to expose the elements again. This works, but gives a less clean zoom in/out experience than with Leaflet's native GeoJSON layer, as the latter supports animated zoom.

The second approach does not contain any implementation specific code that adress the zooming behaviour but does somehow work anyway! The d3 elements are scaled during animated zoom and then replaced neatly with the next zoom levels vectors.

What I would like to achieve is a combination of the two. I would like to plot non-tile-based vectors based on Geo/TopoJSON that are animated during zoom in/out. I've fiddled around with using different leaflet css-classes, different event-hooks, and attaching and/or reusing the SVG elements in numerous ways but have not yet achieved a behaviour that is similar to the behaviour experienced when using Leaflet's native GeoJSON vector layer. The reason I don't want to use the native layer is that I want to make use of plenty of other d3 functionality simply not part of the Leaflet implementation.

Question: Has anyone achieved animated zooming when combining Leaflet and d3 using non-tile-based vectors? If so - how?

like image 868
averas Avatar asked Jan 19 '14 11:01

averas


Video Answer


1 Answers

Example

I think this is one of the best solutions I have found for combining Leaflet and d3, by ZJONSSON.

d3 + Leaflet Integration

In this example the Leaflet map is initiated as SVG here map._initPathRoot(), with the SVG then selected using d3 var svg = d3.select("#map").select("svg"), g = svg.append("g");, after which all the d3 fun can be had.

In this example, the Leaflet map event map.on("viewreset", update); is used to call update and transition the d3 layer on map viewreset. After this, d3 transition options will determine how the d3 layer reacts to the Leaflet map pan/zoom event.

In this way you have the full scope of the d3 + Leaflet libraries without the hassle of calculating map bounds etc, as this is handled nicely by Leaflet.

Animated Vector Zooming

For animation, the latest Leaflet release includes a Pan and Zoom animation option. Whilst this is not as customisable as d3, you could always edit the Leaflet src code to alter the transition duration! Leaflet GeoJSON vector layers (L.geoJson) will not need to be updated on a Leaflet map event (in update), as they are already added to the map as SVG and handled by Leaflet.

Note that if implementing L.geoJson, this also means you wont need to map._initPathRoot(), as Leaflet will add the layer to the map as SVG, so you can just d3.select it.

It is also possible to add a className variable in the L.geoJson layer options so you can style via CSS or d3.select a feature via a unique class id assigned during Leaflet onEachFeature.

like image 120
fitzpaddy Avatar answered Nov 21 '22 23:11

fitzpaddy