Reimplementation of Focus + Context visualization, using SVG's viewBox
attribute for the zoom/pan instead.
This approach uses SVG's viewBox to achieve the following effects:
- The area chart is only ever rendered once, since the underlying dataset never changes throughout this vis.
- The original had 2 initial renders, one in
focus
and one incontext
, with the one infocus
getting re-rendered dynamically on every view change (zoom/pan), and the one incontext
only getting rendered once.
- The original had 2 initial renders, one in
- Modern browsers implement mostly, if not fully complete, implementations of the SVG standard: thus they can all zoom/pan an SVG based on its viewBox values.
- Thus, instead of recalculating the path on every zoom/pan change, we offload that to the browser.
- The overhead of nested SVGs. For this example,
focus
is three SVGs deep. - At high zoom, the SVG rendering breaks down.
- The initial artifacts appear in the top-right corner (Chromium browser) at the resolution of 3-hours on the x-axis.
- Larger artifacts start to appear on the right edge at the resolution of 1-hour on the x-axis, breaking the bounds of the container SVG
- Artifacts appear on the left edge, at the 15-minute resolution on the x-axis, breaking the bounds of the container SVG
- The graph becomes very jittery during the 5-minute resolution
- The jittery and container breakouts become grotesque by the 1-minute resolution
- Gets much worse during 45-second resolution
- The render breaks down entirely to blank by the 1-second resolution
- The main SVG canvas which contains both the focus and context images remains
- All of the axes are moved into this top-level SVG
- The clipping rectangle is replaced by an SVG named 'aperture'
SVG#aperture
is at the same position and size of the clipping rectangle- Its width and height are as calculated
- Its viewBox is set to be "0 0 width height" so that its coordinate system and physical size match.
- The
<g>
element namedfocus
is replaced by an<svg>
element named 'focus'SVG#focus
is nested withinSVG#aperture
SVG#focus
is at the same position and size of<g#focus>
's bounding box
- The
<g>
element namedcontext
is replaced by an<svg>
element named 'context'SVG#context
is at the same position and size of the<g#context>
's bounding box
The layout is something like this:
<svg width=960 height=500>
<SVG#aperture width=900 height=370 viewBox="0 0 900 370" preserveAspectRatio="none">
<SVG#focus width=900 height=370>
<svg#context width=900 height=40 viewBox="0 0 900 370">
<use xlink:href="#focus">
The topmost SVG is the container for everything else. Its width
and height
attributes do two things:
- Sets the physical dimensions of the SVG
- Sets the internal coordinate system of the SVG
The aperture
SVG sets a width and height for its physical dimensions within the topmost SVG. We set its viewBox
attribute to define its internal (or user) coordinate system. We set its preserveAspectRatio
attribute to none
so that its contents will stretch to fit the entire viewport.
The focus
SVG sets a width and height identical to its parent, thus it fully covers its parent aperture
. This sets both its internal and external dimensions. Since the area chart doesn't change, the focus
SVG will always show the full area graph. We will use SVG#aperture
's viewBox
attribute to display the requested portions of the focus
SVG.
Finally the context
SVG is where the width/height and viewBox will diverge: the width is the same, but the height is the height of the actual SVG#context
(40 in this example). The internal coordinates are set to the same as the the focus
SVG. In order to show the contents of SVG#focus
, we use the <use>
call which shows an internal clone of SVG#focus
. Thus, SVG#focus
is simply duplicated and squished to fit the dimensions of SVG#context
. Since context
's internal coordinates are the same as focus
's dimensions, it will fully fit. Note that context
will also show any animations/transitions/changes that you put on focus
due to being a clone.
The brush on SVG#context
will now be the same dimensions as SVG#focus
, since both coordinate systems are identical. This means that whatever the size of this rectangle is after brushing/zooming will map directly to the new viewBox value in aperture
to implement the actual zoom/pan effect on focus
. Basically aperture
is like a window/lens on top of focus
and we can adjust how close in or how far out we want to look through that window/lens to see which bits of focus
below.
The axes are contained within the top-level SVG because they need to exist outside of all the zooming/panning happening, and they get updated in the same way as before.
The brush and zoom functions are updated to adjust the aperture's viewBox as well as the focus
x-axis.