In the course of the last two months I have been talking to people about dojox.charting changes. I collected a lot of wishes, valuable feedback, and even some great patches introducing new exciting features. But in order to accommodate suggestions and planned features, we need to reorganize the codebase. The reorganization was looming and its time has come. This week I was going over Dojo charting trac tickets and the roadmap.
Let’s go over the major changes.
The underlying graphics API (dojox.gfx) does not support any form of clipping due to the fact that one of major renderers (VML) doesn’t support this functionality. Borrowing the idea from the original Dojo Charts in Dojo 0.4 by Tom Trenka, I implemented a simple pseudo-clipping using the matting technique. The idea of matting is to create a mat with a hole, and stack the mat on top of a picture exposing only the selected part. It requires putting some opaque objects on top of the plot to “clip” it visually. Now all plots are clipped before proceeding to render the plot axes.
This change doesn’t introduce new API, but improves visuals. Already several bug reports were resolved by this feature.
Change: Separating all Scaling Concerns
This is the major change under the hood. While it is not as visible as the pseudo-clipping, it is essential to what we can do with charting in the future.
After reorganization, we have a linear scaler, which is responsible for mapping data from user space to a plot:
- Scaler can calculate tick placements automatically from data statistics (min/max), available area in pixels, and plot parameters.
- Up to 3 levels of ticks can be calculated: major, minor, and micro ticks.
- A simple heuristic is used to keep number of levels sane, and ticks visually distinguishable.
- Major ticks tend to be placed using power-of-10 steps.
- Ticks of lower level tend to be placed 2, 5, or 10 per 1 tick of higher level.
- Users can override the automatic placement of ticks of any level by supplying a tick step number explicitly.
- Users can require skipping micro ticks (the default), or minor and micro ticks.
- Precision (the number of required digits after a decimal point) is calculated automatically for every tick level. This number will be used later to generate numeric labels.
- Given the scaler’s results, we can calculate all tick placements and produce labels.
- All intersecting ticks are removed, leaving the higher level tick in place.
- Users can assign a text label to a specific value, and this label will be used for the tick with this value (determined using a tolerance for real values). Otherwise, a numeric label will be constructed using a precision calculated by the scaler.
- The resulting lists of ticks can be effectively visualized by 2D or 3D axis renderers.
- Transformation functions are defined to map values from the model space to the plot space and back.
- This provision opens a possibility for non-linear space transformations (e.g., logarithmic scales or timelines with gaps).
- A plot space to model space transformation can be used to map mouse events to the model space.
As you can see, now we are ready for some serious heavy-duty charting including future scientific charts and financial charts. For now, the linear module is available. Expect more in the future.
Fix: Sometimes Labels Split Into Multiple Lines
Several people have reported that custom labels with spaces in them can split into multiple lines. It happened only when HTML labels were used. While the bug looks spectacular, the fix was trivial. A test case was added to make sure we don’t break this change.
Won’t fix: Chart Layout Problems with Dynamically Sized Widgets
We received many reports that placing charts in dynamically sized widgets produces visual artifacts. Examples: placing a chart in the Dialog widget, opening it, closing, and re-opening it again => visual problem, placing a chart in the ContentPane widget => visual problem. In all cases, the visual problem related to HTML labels: they look misplaced, or pushed a chart down or left. I have tried to find a solution for this problem for almost 6 months. This week, I dedicated two days to finding a fix. Initial absolute placement calculations gave way to relatively positioned labels, which were replaced with statically positioned absolute labels. Nothing helped resolve the problem.
I am declaring this and related problems as “wontfix” for now. If you have good ideas how to place HTML labels in a compatible way with dynamically sized widgets, don’t hesitate to tell me.
For now if you are absolutely forced to use charts inside such widgets you have following choices:
- Don’t use HTML labels. It is easy: just specify “htmlLabels: false” in parameters of your axes. The caveat: Canvas doesn’t implement text. If you use Canvas as your renderer this solution will not work. Presently on some platforms Canvas is the only available graphics API (e.g., iPhone, iPod).
- Don’t keep charts when the Dialog is closed, or when a ContentPane is resized. Remove charts instead, and recreate them from scratch. In most cases this is an acceptable solution.
Besides general cleanup, several bugs were squashed including better clean-up for HTML labels (some nodes were previously not deleted properly), and more accurate detection of what should be updated (in some cases when a series was updated, it didn’t force a related axis to redraw). In order to debug some problems, I updated our unit tests
The next logical step is to capitalize on new clipping facilities and scalers, and implement frequently asked features: zooming (drilling down, and overview), panning (moving data area with mouse), and scrolling. In parallel I plan to start working with our contributors on the timeline axis. Stay tuned!