mackwerk
mackwerk

Reputation: 1687

d3.js Uncaught TypeError: Cannot read property 'length' of undefined

I am trying to write a reusable linechart here, but I am getting the following error on load:

Uncaught TypeError: Cannot read property 'length' of undefined

JSfiddle here: http://jsfiddle.net/2qs95/

I first wrote it "directly" and un-reusable, and that works, but when I tried to convert it to a function it broke for some reason. I am sure it is some scope problem. Just can't seem to figure it out.

Working JSfiddle here: http://jsfiddle.net/ht9rG/

function LineChart (data, chart) {
    this.data = data;

    this.margin = chart.margin || { top: 0, bottom: 0, left: 0, right: 0 };
    this.height = chart.height || 100;
    this.width = chart.width || 400;
    this.target = chart.target || 'body';
    this.yLabelClass = chart.classes.yLabelClass || 'y-label';
    this.yTicksClass = chart.classes.yTicksClass || 'y-ticks';
    this.specialTextClass = chart.classes.specialTextClass || 'special-text';
}
LineChart.prototype = {
    draw: function () {
        this.g.selectAll("." + this.yLabelClass)
            .data(this.y.ticks(2))
            .enter().append("svg:text")
            .attr("class", this.yLabelClass)
            .text(String)
            .attr("x", d3.select(this.target).attr('width') - 50)
            .attr("y", function(d) { return -1 * this.y(d) })
            .attr("text-anchor", "left")
            .attr("dy", 5);

        this.g.selectAll("." + this.yTicksClass)
            .data(y.ticks(2))
            .enter().append("svg:line")
            .attr("class", this.yTicksClass)
            .attr("y1", function(d) { return -1 * this.y(d); })
            .attr("x1", this.x(-0.3))
            .attr("y2", function(d) { return -1 * this.y(d); })
            .attr("x2", d3.select('svg').attr('width') - 70);

        this.g.append('text')
            .attr({
                class: this.specialTextClass,
                y: -50,
                x: 0
            })
            .text(this.data[this.data.length - 1] + 'ms');

        this.g.append("svg:path").attr("d", line(this.data));
    },

    y: d3.scale.linear()
        .domain([0, d3.max(this.data)])
        .range([this.margin.bottom, this.height - this.margin.bottom]),

    x: d3.scale.linear()
        .domain([0, this.data.length])
        .range([this.margin.left, this.width - this.margin.left]),

    svg: d3.select(this.target)
        .append("svg:svg")
        .attr("width", this.width)
        .attr("height", this.height),

    g: svg.append("svg:g")
        .attr("transform", "translate(0, " + h + ")"),

    line: d3.svg.line()
        .interpolate('linear')
        .x(function (d, i) { return x(i); })
        .y(function (d) { return -1 * y(d); })
}

var data = [432, 123, 432,123,765,234,234,656,800,123,431,543,652, 100, 200];
var options = {
        width: 800,
        height: 100,
        margin: {
            top: 10,
            bottom: 10,
            left: 10,
            right: 10
        },
        target: 'body'
    };

var x = new LineChart(data, options);
x.draw();

Upvotes: 0

Views: 3553

Answers (1)

Lars Kotthoff
Lars Kotthoff

Reputation: 109232

You were missing a few things here and there, mostly

  • variables you hadn't prefixed with this.,
  • variables that you had given different names,
  • use of this inside a D3 callback, at which point it referred to the SVG element and not the chart object,
  • and a few other things.

I won't list everything here, but a working example is here and you can compare to your version.

Upvotes: 3

Related Questions