Making a D3 chart responsive

Introduction

Building charts and data visualization is awesome. D3 provides amazing capabilities in that domain.

I previously explained how to create the various building blocks of a chart, but one thing is lacking: how to make the chart behave properly at all screen resolutions, aka responsive? Starting from where I left off in the previous post, I will explain how to make a chart responsive. Code can be found on GitHub.

Preparation

Before anything, let’s get rid of the hard-coded size that was set in the test page, to set only the width as a percentage:

<div id="test" style="width:50%;">
</div>

In charting.ts , let’s set the height according to the width instead of retrieving it:

var height = 3 / 4 * width;
this._height = height;

This now creates a 4/3 chart. One might think that’s it! Well, it’ a start, but that’s not all. What about window resize? If the screen is small, what about overlapping labels?

The resize function

So let’s take a moment to think what has to change according to the size. Several elements are to consider:

  • the size of the container svg
  • the width of the axis and the related scale
  • the position of the x axis
  • the height of the y axis
  • the position of the circles in the chart

Let’s create a resize function in charting.ts:

private resize() {
    var width = this._container.node().clientWidth;
    this._width = width;
    var height = this._ratio * width;
    this._container.select('svg')
        .attr({
            'width': width,
            'height': height
        });
    this._height = height;
    this._xAxis.resize(width, height);
    this._xAxis.translate(this._paddingLeft, (this._height - this._paddingBottom));
    this._yAxis.resize(width, height - this._paddingBottom - this._paddingTop);
    this._dataGroup
        .selectAll('.post')
        .attr({
            'cx': (d: any, i) => this._xAxis.scale()(d.date),
            'cy': (d: any, i) => this._yAxis.scale()(d.value)
        });
}

The resize function requires access to the original container via the _container private variable, that has to be set in the init function. The init function can actually be further cleaned, as most of the work related to size is now handled by the resize function. The updated init function looks like:

private init(container) {
    var selection = d3.select(container);
    this._container = selection;
    var svg = selection.append('svg');
    this._group = svg
        .append('g');

    this._xAxis = new xAxis(this._group, 400);
    this._yAxis = new yAxis(this._group, 300);

    this._yAxis.translate(this._paddingLeft, this._paddingTop);

    this._dataGroup = this._group.append('g')
        .classed('data', true)
        .attr({
            'transform': 'translate(' + 0 + ',' + this._paddingTop + ')'
        });
    this.resize();
}

To be able to use the resize function, new resize methods have to be defined on the x and y axis elements. In xAxis.ts, let’s add the following method:

resize(width: number, height: number) {
    this._scale.range([0, width]);
    if (width < 650) {
        this._axis.ticks(5);
    } else {
        this._axis.ticks(10);
    }
    this._group.call(this._axis);
}

What this does is :

  • set the range of the scale according to current width
  • adapt the number of ticks according to the width of the chart
  • redraw the axis

The resize function for the y axis is left as an exercise to the reader.

Our chart now behaves as expected when it is resized.

Responding to the resize event

The final piece to throw in is the resizing of the chart when the window is resized. That part is as simple as responding to the window resize event. Let’s add the following code at the end of the init method:

d3.select(window)
    .on('resize', () => {
        this.resize();
    });

And voila. Our chart now adapts automatically to the size of the screen, even when this changes. To know more about the event callback syntax used in TypeScript, refer to my other article.

Conclusion

This article presents a method to make a chart responsive and auto-adaptive when the size of the screen changes. The way D3 is built and the use of scales makes our lives pretty easy in that area.

Advertisements
Leave a comment

1 Comment

  1. Creating a chart with D3 and TypeScript – part 3 | Wandering in the community

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: