Test driving your visualization – pixel-perfect bar rendering

In this iteration we will finally generate the bars using the data we have. Through our test cases we will make sure all bars are not only rendered but rendered with pixel-perfect precision.

How to do it...

Let's see how we test it:

describe('chart body', function () {
        it('should create body g', function () {
            chart.render();
            expect(chartBody()).not.toBeEmpty();
        });

        it('should translate to (left, top)', function () {
            chart.render();
             expect(chartBody().attr('transform')).toBe('translate(30,10)')
        });
    });

    describe('bars', function () {
        beforeEach(function () {
            chart.data(data).width(100).height(100)
                .x(d3.scale.linear().domain([0, 3]))
                .y(d3.scale.linear().domain([0, 6]))
                .render();
        });

        it('should create 3 svg:rect elements', function () {
            expect(bars().size()).toBe(3);
        });

        it('should calculate bar width automatically', 
          function () {
            bars().each(function () {expect(d3.select(this).attr('width')).toBe('18'),
            });
        });

       it('should map bar x using x-scale', function () {expect(d3.select(bars()[0][0]).attr('x')).toBe('0'),expect(d3.select(bars()[0][1]).attr('x')).toBe('20'),expect(d3.select(bars()[0][2]).attr('x')).toBe('40'),
       });

       it('should map bar y using y-scale', function () {expect(d3.select(bars()[0][0]).attr('y')).toBe('60'),expect(d3.select(bars()[0][1]).attr('y')).toBe('30'),expect(d3.select(bars()[0][2]).attr('y')).toBe('0'),
       });

       it('should calculate bar height based on y', 
          function () {expect(d3.select(bars()[0][0]).
            attr('height')).toBe('10'),expect(d3.select(bars()[0][1]).attr('height')).toBe('40'),expect(d3.select(bars()[0][2]).attr('height')).toBe('70'),
        });
    });

 	 function chartBody() {
        return svg().select('g.body'),
    }

    function bars() {
        return chartBody().selectAll('rect.bar'),
}

How it works...

In the preceding test suite we describe our expectations of having the chart body svg:g element correctly transform and correct number of bars with appropriate attributes (width, x, y, height) set. The implementation is actually going to be shorter than our test case which is quite common in well tested implementation:

...
var _parent = p, _width = 500, _height = 350,
        _margins = {top: 10, left: 30, right: 10, bottom: 30},
        _data,
        _x = d3.scale.linear(),
        _y = d3.scale.linear();

that.render = function () {
        var svg = _parent
            .append("svg")
            .attr("height", _height)
            .attr("width", _width);

        var body = svg.append("g")
            .attr("class", 'body')
            .attr("transform", "translate(" + _margins.left + "," + _margins.top + ")")

        if (_data) {
            _x.range([0, quadrantWidth()]);
            _y.range([quadrantHeight(), 0]);

            body.selectAll('rect.bar')
                .data(_data).enter()
                .append('rect')
                .attr("class", 'bar')
                .attr("width", function () {
                    return quadrantWidth() / _data.length - BAR_PADDING;
                })
                .attr("x", function (d) {return _x(d.x); })
                .attr("y", function (d) {return _y(d.y); })
                .attr("height", function (d) {
                    return _height - _margins.bottom - _y(d.y);
                });
        }
};
...

I think you are getting the picture and now you can repeat this cycle over and over to drive your implementation. D3 visualization is built on HTML and SVG and both are simple mark-up languages that can be verified easily. Well thought-out test suite can make sure your visualization is pixel-perfect even sub-pixel perfect.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset