Jutting Bytes

Digressions of a research engineer

QChart.js: QML Bindings for Chart.js

| Comments

Working with Qt/QML on a new project on electro-magnetism data collection, I wanted to implement some simple yet meaningful and eye friendly charts to display data. It happens that some days before, I used Chart.js on the web backend of this mobile application and thought that for the sake of consistence I would give it a shot with QML since it integrates nicely with javascript.

Find it on GitHub.

Canvas

On the one hand, HTML5, among other things, brings the canvas – an element to draw graphics, on the fly, using scripting, most of the time, javascript. Every canvas has a drawing context, which only supports 2D primitives so far.

On the other hand, Qt5, with QtQuick >= 2.0, also brings an new QML item, the Canvas, which curiously reminds of its HTML5 counterpart. Having a closer look at its API, it actually completely mimics the first one, and provides a Context2D item, that can be drawn into using javascript.

Chart.js

Chart.js, published under the terms of the MIT license, describes itself as a simple and object oriented javascript library, that much is true. It is indeed well designed, and anyone who is not that much familiar with javascript but knows object oriented programming can very quickly dig into it.

Getting rid of this window variable that doesn’t mean anything in a QML document, by changing it to a reference to the canvas itself, makes Chart.js work as expected right away. Awesome. Nearly.

Animations

Chart.js makes use of HTLM5 animation mechanism, using intervals and timeouts, within an animation loop that is triggered according to the chart options, whenever it is displayed for the very first time.

This mechanism is not supported by QML’s Canvas, and the documentation says to replace it with a timer, or using an equivalent method that did not produce any result for me.

On the other side, QML already features a wonderful animation system, much more powerful than the one embedded in Chart.js. It also provides such a level of integration that it would not be possible not to use it.

So I dropped the animation system within Chart.js and refactored the code a little bit so that each object exposes two methods:

  • this.init = function () that initializes the chart. According to its kind, it will compute bounds for the scale, compute the legend, etc.
  • this.draw = function (t) that draws the chart for an interpolation of its data for t from 0 to 1, as it was already the case in the original version of the script, but in such a way that this parameter can be defined as a property on the QML side, which value is changed by a QML PropertyAnimation, with a callback that requests an update for the drawing area.

Setup

This shows how to integrate QChart.js as a jbQuick.Charts submodule into your git project.

1
2
3
4
$ cd /path/to/project/root/
$ mkdir -p qml/jbQuick
$ git submodule add git://github.com/jwintz/qchart.js.git qml/jbQuick/Charts
$ git commit -a -m "Added QChart.js as a submodule."

When cloning a repository with submodules, use:

1
2
3
$ git clone git://your/project/repository.git
$ git submodule init
$ git submodule update

To update your local submodule, use:

1
$ git submodule update

Usage

Assuming jbQuick is in your qml import path:

1
import jbQuick.Charts 1.0

QChart.js qmldir provides:

  • Chart QML item inheriting Canvas
  • Charts Javascript library

In addition, Chart provides the following properties:

  • chartAnimated: whether chart data should be animated on initialization
  • chartAnimationEasing: an easing type enumeration provided to a PropertyAnimation
  • chartAnimationDuration: the length (ms) of the animation
  • chartData: a javascript construct of the data set, see Chart.js documentation
  • chartType: a value amongst:
    • Charts.chartType.BAR for a bar chart
    • Charts.chartType.DOUGHNUT for a doughnut chart
    • Charts.chartType.LINE for a line chart
    • Charts.chartType.PIE for a pie chart
    • Charts.chartType.POLAR for a polar chart
    • Charts.chartType.RADAR for a radar chart

The following snippet creates a line chart.

1
2
3
4
5
6
7
8
9
10
11
12
Chart {
  id: chart_line;
  width: 400;
  height: 400;
  chartAnimated: true;
  chartAnimationEasing: Easing.InOutElastic;
  chartAnimationDuration: 2000;
  chartType: Charts.ChartType.LINE;
  Component.onCompleted: {
      chartData = ...;
  }
}

Enjoy. And drop me a comment if you happen to use it.


Comments