The extent functionality is simplified, such that the zoom behavior only
supports an extent on the scale factor. Furthermore, the extent is expressed as
a scale factor rather than a zoom level, for consistency. An extent on translate
is no longer supported; this isn't possible unless the zoom behavior also knows
the size of the canvas.
The scale transform functionality is also simplified; simply register an x or y
scale, and the zoom behavior will automatically update the domain before a zoom
event is dispatched. If you change the scale's domain programmatically, you can
simply reassign the scale to the zoom behavior.
Both of these changes are strictly backwards-incompatible. However, since this
class is undocumented, I'll probably let this slide with a minor version bump
rather than waiting until v3.
This commit also reduces the scroll speed slightly, since the previous
implementation seemed a little too fast for my liking. It would be easy to make
the scroll speed configurable as a future enhancement.
Implementation note: rather than using global event listeners on the window, and
needing to copy local state into globals on interaction start, the zoom behavior
now uses closures that are temporarily bound (e.g., mousemove and mouseup are
bound on mousedown, and removed on mouseup).
Fixes#484, allowing scale and translate to be get or set externally.
Fixes#485, providing an example of integration with d3.geo.projection.
Fixes#487, using a scale extent rather than a zoom-level extent.
Fixes#428. This is built on top of existing tick support for linear scales: for
small intervals, a linear scale computes ticks based on milliseconds; for large
intervals, a linear scale computes ticks based on fractional years. This commit
also extends the time scale's formatter to display milliseconds.
There's an edge condition which is not discussed in the original algorithm
("Visualization of Large Hierarchical Data by Circle Packing", Wang et. al):
what happens if the first intersecting circle C_j is equidistant from C_m and
C_n? In other words, it is both after C_n on the front-chain, and before C_m.
The correct answer is that you should splice the smaller of the two circles. If
C_m is smaller than C_n, then splice from C_j to C_n and set C_m to C_j;
otherwise, splice from C_m to C_j, and set C_n to C_j.
A small optimisation: only call insertBefore() if node.nextSibling isn't
already what we want, so that document nodes that are already in the
correct order can be skipped.