Project

General

Profile

Customizing rendering of charts

Added by Stephan Kaiser over 8 years ago

We (company) are evaluating the charts for interactive and non-interactive use cases. At first glance, this works well and the built-in options already provide several customization hooks.

Now, we'd like to paint a few additional objects onto the chart. This is essential for the kind of charts that we need to generate.

Ideally, we could specify some kind of drawable object and position it using chart coordinates. Basically, a generalized form of the way custom series markers can be specified.

What I did is I tried deriving from WCartesianChart and hooking into one of the virtual render* methods like this:

void MyChart::renderBackground(Wt::WPainter& painter) const
{
    Wt::Chart::WCartesianChart::renderBackground(painter);

    painter.save();
    painter.setClipping(false); // <- Should actually clip to chartArea_ which is unaccessible in derived class.
    Wt::WPen p(Wt::black);
    p.setWidth(1);
    Wt::WPainterPath path;
    auto p0 = hv(Wt::WPointF(0.0, -0.5));
    auto p1 = hv(Wt::WPointF(30.0, -0.5));
    path.moveTo(p0);
    path.lineTo(p1);
    painter.strokePath(path, p);
    painter.restore();
}

While the initial rendering of the chart looks OK the geometry does not get updated properly during zoom and pan operations. For the chart's geometry this happens completely client-side.

The problems I see:

  1. Missing access to some internals like chartArea_ which makes some calculations difficult to pull off.
  2. I seem to be missing a clue to understanding how zoom and pan are implemented so that the repainting happens completely on the client-side. Even after scanning through the whole of WCartesianCart's (and its helper classes') code I do not really see what I'm missing. (I have some basic understanding of JSlot, JSignal and JavaScript bound values as I've used these features to integrate custom JS code.)

Is this even the right way to go about it?


Replies (2)

RE: Customizing rendering of charts - Added by Roel Standaert over 8 years ago

In order to allow for painting of extra objects, I've added the renderOther() method,

and made a few methods public or protected.

These methods are:

  • mapToDeviceWithoutTransform
  • zoomRangeTransform

This should allow you to override renderOther like this:

void MyChart::renderOther(Wt::WPainter& painter) const
{
    Wt::Chart::WCartesianChart::renderOther(painter);

    painter.save();
    painter.setClipping(true);
    Wt::WPen p(Wt::black);
    p.setWidth(1);
    Wt::WPainterPath path;
    // assuming that (0.0, -0.5) and (30.0, -0.5) are model coordinates,
    // not device coordinates
    auto p1 = mapToDeviceWithoutTransform(0.0, -0.5);
    auto p2 = mapToDeviceWithoutTransform(30.0, -0.5);
    path.moveTo(p0);
    path.lineTo(p1);
    painter.strokePath(zoomRangeTransform().map(path), p);
    painter.restore();
}

RE: Customizing rendering of charts - Added by Stephan Kaiser over 8 years ago

I just tested renderOther() in our application. It seems to be exactly what we need.

I'll test some more and report back with the results.

Thank you very much!

    (1-2/2)