Using d3.range with a floating point step is a bit sketchy, because there's a
chance that too many or too few elements could be generated. Instead, we now we
generate an integer range and scale it accordingly.
This includes a d3.extent convenience method for [d3.min, d3.max], and fixes the
brush component such that the resizers are hidden when the extent is empty.
This required a couple core changes. First, the brush shouldn't notify listeners
when redrawing, because this commonly causes an infinite loop if one brush
triggers a change in another brush (as in a scatterplot matrix, where only one
brush is active at a given time). I suppose an alternative implementation might
use just a single brush, and assign the axes dynmically; I might try that in a
future commit. Second, I added a clear convenience method to reset a brush.
The brush component now reports brushstart and brushend events at the start and
end of a brushing gesture, which is useful for some types of interaction. You
can now set the brush extent programmatically, as well. Note, however, that
you'll probably want to redraw the brush after setting the extent.
You can now query the brush for its selection. This commit also includes a new
d3.random.normal for generating random numbers with a normal distribution. This
is useful for jittering points for display.
The d3.svg.brush component allows one- or two-dimensional rectangular brushing.
A future commit will allow the brushed region to be resized by grabbing an edge,
and also provide some way of reporting the selection (duh)!
We can't check for existence of event.touches to decide whether to use
it or not for touchend, as it always exists, just not containing the
touch that just ended.
We still weren't sorting subgroups correctly. Also, we now sort chords by their
average value, rather than the source value, which works well with one-sided
chords (where either the source or target value is zero).
The extents parameter is a 3-element array of ranges, corresponding to
the ranges allowed in pixel-space at zoom-level 0. Each range is a
two-element array. For example, to restrict zooming and panning to a
rectangle of width w and height h, with minimum zoom level 0, use:
.extents([[0, w], [0, h], [0, Infinity]])
This defaults to storing the absolute scale and transform across
multiple zooms. However, it can be modified to retrieve state from
outside the behaviour e.g. if the offsets have been restricted in some
way, the true values should be returned in a custom offset accessor.
The offset accessor is called on "mousedown" or "touchstart", and so has
access to the current mouse position.
Due to the ordering in which the prototypes are defined, it was still undefined!
Also, the empty method depends on the node method being defined. Added a test.
It was previously possible for small differences in the reference time for
subtransitions. This could lead to tearing with expensive transitions, as some
transitions would have slightly different reference times than the others. This
is fixed by passing the reference time along explicitly when deriving a new
transition, either by the transition or selection operators.