Zooming, Scrolling, and Panning in Dojo Charting

By on May 15, 2008 12:37 am
Notice: There is a newer version of this post available

As mentioned in my previous post Dojo Charting Reorganization, this week I worked on zooming, scrolling, and panning of charts. It turned out to be a more complex task than I anticipated due to the little-known fact that Dojo Charting can stack multiple plots per chart and can show multiple independent axes on all 4 sides of the chart. These problems were solved and a new API was introduced on the chart object:

  • chart.setAxisWindow(name, scale, offset) — defines a window on the named axis with a scale factor, which starts at the set offset in data coordinates.
    • The scale parameter must be >= 1.
    • The offset parameter should be >= 0.
    • For example if I have an array of 10 numeric values, and I want to show them ##3-8, chart.setWindow(“x”, 3, 2) will do the trick.
    • This call affects only plots attached to the named axis, other plots are unaffected.
  • chart.setWindow(sx, sy, dx, dy) — sets scale and offsets on all plots of the chart.
    • The sx parameter specifies the magnification factor on horizontal axes. It should be >= 1.
    • The sy parameter specifies the magnification factor on vertical axes. It should be >= 1.
    • The dx parameter specifies the offset of horizontal axes in pixels. It should be >= 0.
    • The dy parameter specifies the offset of vertical axes in pixels. It should be >= 0.
    • All chart’s axes (and, by extension, plots) will be affected.

Obviously these new methods do sanity checks, and don’t allow you to scroll outside of axis’ boundaries, or zoom out too far.

As you can see these methods are enough to implement arbitrary zooming to drill down to the smallest details of your chart, scrolling, and panning (moving the chart with you mouse in two dimensions). The latter functionality is taxing on the browser, but the new generation of browsers (Firefox 3, Safari 3, Opera 9.5) are up to the task.

While this functionality is available now in the trunk, I plan to incorporate the panning support directly into the Charting widget, so it can be turned on and off by a parameter.

Now it is time for some show-and-tell. Below you can see my test chart in its normal state:

Normal chart.

As you can see this chart has 4 independent axis on all sides, and two plots, each with independent axes: the light brown plot uses the bottom and the the left axes, while the dark brown plot uses the axes on the top and the right sides.

You can access this test application in Dojo Nightlies. Warning: this link uses the raw Dojo served directly from Dojo development server, so the initial loading will be relatively slow. In real applications you should use Dojo builds.

This is the code required to build this chart:

// create our chart
var chart = new dojox.charting.Chart2D("test");

// set a theme
chart.setTheme(dojox.charting.themes.PlotKit.orange);

// create the ordinal horizontal axis with custom visual attributes,
// by default it will be attached to the bottom of the plot area
chart.addAxis("x", {
    fixLower: "minor", natural: true, stroke: "grey",
    majorTick: {stroke: "black", length: 4},
    minorTick: {stroke: "gray", length: 2}
});

// create the ordinal vertical axis with custom visual attributes,
// by default it will be attached to the left of the plot area
chart.addAxis("y", {
    vertical: true, min: 0, max: 30,
    majorTickStep: 5, minorTickStep: 1, stroke: "grey",
    majorTick: {stroke: "black", length: 4},
    minorTick: {stroke: "gray", length: 2}
});

// add the front plot, which uses default axes (named "x" and "y")
chart.addPlot("default", {type: "Areas"});

// add series to the default plot
chart.addSeries("Series A",
    [0, 25, 5, 20, 10, 15, 5, 20, 0, 25]
);

// create the ordinal horizontal axis with custom visual attributes,
// we specify explicitly that it should be attached to the top
chart.addAxis("x2", {
    fixLower: "minor", natural: true,
    leftBottom: false, stroke: "grey",
    majorTick: {stroke: "black", length: 4},
    minorTick: {stroke: "gray", length: 2}
});

// create the ordinal vertical axis with custom visual attributes,
// we specify explicitly that it should be attached to the right
chart.addAxis("y2", {
    vertical: true, min: 0, max: 20,
    leftBottom: false, stroke: "grey",
    majorTick: {stroke: "black", length: 4},
    minorTick: {stroke: "gray", length: 2}
});

// create the back plot, which uses our custom axes ("x2" and "y2")
chart.addPlot("plot2", {
    type: "Areas", hAxis: "x2", vAxis: "y2"
});

// add series to "plot2" we just created
chart.addSeries("Series B",
    [15, 0, 15, 0, 15, 0, 15, 0, 15,
        0, 15, 0, 15, 0, 15, 0, 15],
    {plot: "plot2"}
);

// add the bottom of our stack we put the grid
// that shows major lines, and horizontal minor lines
chart.addPlot("grid", {type: "Grid", hMinorLines: true});

// show what we've built
chart.render();

Now let’s see it magnified by 2 in both dimensions and moved so we can see the peaks in the middle-left part of the chart:

Zoomed chart.

This picture above was made from the previous picture with one call:

chart.setWindow(2, 2, 181, 143).render();

Obviously axes show new labels to reflect the new state of the chart. Using these labels we can get our bearings and understand what we are looking at.

If we want to return back we can always do:

chart.setWindow(1, 1, 0, 0).render();

Coming Attractions

Now is a good time to start working on Chart event support, so developers will be able to add actions depending on where the user clicked, or hovered over. A highly requested feature, events can be used to do a range of things starting from synchronizing an external table with the current position of the chart, to showing some supplementary information on clicked points.

I plan to add Tooltip widget support to the Chart widget — it will cover the most frequent case of the event processing. Stay tuned!

Comments

  • Awesome stuff!

    What is the plan for making it work in IE(6)?
    I.e. I tested http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/charting/tests/test_bars.html that one doenst show anything in IE6, is it because its using 3D bars? Is there a roadmap/plan one can look up?

    Thanks for the great work

    Wolfram

  • Only 2D charts are affected by recent changes. There is a new 3D graphics effort underway as a part of the Google SoC. I prefer waiting for it to be finished before we start advancing 3D charting.

  • Pingback: SitePen Blog » Dojo Charting: Event Support Has Landed!()

  • Pingback: SitePen Blog » A Beginner’s Guide to Dojo Charting, Part 2 of 2()

  • kunal

    Hi,

    Is there a way to get the grid values through mouse movement. What i mean here is that i want to zoom the chart on the x-axis, and the functionality should be that, considering the second chart here, if the user clicks between 3 and 4 on the chart, the chart could be redrawn with x-axis starting from 3 and ending at 4.
    SO to have a api from dojo which can give me the position of the mouse respective of the chart.

    Thanks
    Kunal

  • Laura

    It appears the “Offset” functionality is broken now? I can’t get it working in code, and the Offset sliders on the demo page don’t do anything :(

    http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/charting/tests/test_win2d.html

  • @kunal: it is simple to do. You can do it like that (example for x):

    var scaler = chart.getAxis(“x”).getScaler();
    var fromPlot = dojox.charting.scaler.linear.getTransformerFromPlot(scaler);
    var fromModel = dojox.charting.scaler.linear.getTransformerFromModel(scaler);

    You can use it like that:

    var x = 100; // x is a coordinate in pixel in the plot space
    var X = fromPlot(x); // X is in your model coordinates

    or:

    var X = 5; // X is in your model coordinates
    var x = fromModel(X); // x is in pixels relative to the plot

    You can get the plot area coordinates from chart.surface.rawNode.

  • @Laura: I’ll check this functionality tonight. It should work.

  • Tony

    A good product but nothing as frustrating as poor or lack of documentation. Since when did blogging replace proper documentation.

  • @Tony – There is a massive community and committer driven documentation project underway at http://docs.dojocampus.org – the initial tests from sphinx dumps has the content at a 500-page PDF, and a very comprehensive collection of working examples, notes, and techniques. We’ve gone to a wiki format for easiest editing, and will be producing static dumps in PDF and HTML form for offline viewing and increased online access speed.

    Also, the API pages are back online at http://api.dojotoolkit.org

    I urge you [and others] to participate in filling in any blanks in documentation, as Dojo is an enormous project, and our resources are not unlimited.

  • @Laura: just checked and it works as expected. Offsets do not allow you to scroll outside of the visible area of the chart. You should zoom in first before using offsets. The initial state shows all data, so there is no room for scrolling.

  • 胡三春

    x:6~17 y:0~500 Can you tell me how to do this with chart.setWindow(….).render(); Thanks.

  • 胡三春

    chart.addAxis(“x”, {
    fixLower: “minor”, natural: true, stroke: “grey”,
    majorTick: {stroke: “black”, length: 4},
    minorTick: {stroke: “gray”, length: 2}

    });

    chart.addAxis(“y”, {
    vertical: true, min: 0, max: 500,
    majorTickStep: 100, minorTickStep: 100, stroke: “grey”,
    majorTick: {stroke: “black”, length: 4},
    minorTick: {stroke: “gray”, length: 2}
    });

  • @胡三春: You can see how it is done in http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/charting/tests/test_win2d.html — the points of interest are calls to setWindow() method. The method itself is described in this blog post above. If you want to see a specific window, you should recalculate it to scale/offset parameters.

    The scale of 1 is fully shown picture. The scale of 2 will zoom in 2x. All offsets are in pixels. For example, if your X span is 1000px, and you have 10 units fit in here, in order to zoom in 2x and show the second half you shold use scale = 2, and offset = 1000 * scale * 0.5 = 1000.

    In order to know how much pixels you have for the plot, you can get a relevant axis using Chart2D.getAxis(name) (“y” in this case), and call getOffsets() on it. The latter returns an object with l, t, r, b properties (left, top, right, and bottom respectively). You should subtract relevant numbers from the total chart size you specified when creating the chart.

  • Nicholas

    @Peter Higgins

    “I urge you [and others] to participate in filling in any blanks in documentation, as Dojo is an enormous project, and our resources are not unlimited.”

    This something that can only be done by the people that wrote the code.. they’re the only ones with the knowledge to write the documentation. The rest of us could subsequently help out with tutorials and examples, but only if we have access to good API documentation. As Tony remarks, the current experience with Dojo often results in frustration due to a lack of good API documentation.

  • Eneko

    Just tested http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/charting/tests/test_event2d.html and http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/charting/tests/test_win2d.html with Iceweasel (Firefox) 3.0.5 on Debian Lenny and no charts are drawn. Javascript console shouts about “dojo._hasResource is undefined” lots of times. ¿Any hint? Thanks.

  • @Eneko: you witnessed a very rare event: the nightlies are broken by some unsuccessful patch causing all tests to fail. I don’t recall such thing since … forever.

    Do not forget that Dojo is under active development and nightlies are snapshots of the trunk. Just wait until the next snapshot is done (automatically once in 24 hourse) and try again.

  • luicky

    Eugene Lazutkin :
    Thanks for your excellent job make our life easy, and I have two question need your help.
    1. Just as Kunal says, does dojo have api which can give us the position of the mouse respective of the chart when click.
    2. Just as your reply to 胡三春,”if your X span is 1000px, and you have 10 units ….”. I want to know whether dojo has a api can tell us the current span of chart(and axis x,y).
    Looking forward your kindly reply as soon as possible.

  • Prashant

    How can I get the property values set for the axis?
    Example: I need to get the min value for the x axis because my graph does not starts with 0 on x axis for some charts but it works fine for other.