简体   繁体   中英

Adding 'rect' elements to blank svg canvas in d3 is failing on .data()

I'm using Polymer to render some d3 charts. When the Polymer is initially rendered I only draw a graph with axes and no data, since the data comes later once the API calls succeed. However, when I get around to selecting the 'rect' elements in the svg, calling data() on that fails. Here's my code:

dataChanged: function() {
    var data = this.data;
    var margin = {top: 20, right: 20, bottom: 30, left: 50},
        width = this.width - margin.left - margin.right,
        height = this.height - margin.top - margin.bottom;

      // format the data
    data.forEach(function(d) {
        d.date = d3.isoParse(d.date);
    });

    // set the ranges
    var x = d3.scaleTime()
        .domain(d3.extent(data, function(d) { return d.date; }))
        .rangeRound([0, width]);
    var y = d3.scaleLinear()
        .range([height, 0]);

    var svg = d3.select(this.$.chart).transition();

    var histogram = d3.histogram()
        .value(function(d) { return d.date; })
        .domain(x.domain())
        .thresholds(x.ticks(d3.timeMonth));

    var bins = histogram(data);

    y.domain([0, d3.max(bins, function(d) { return d.length; })]);

    svg.selectAll("rect")
        .data(bins)
        .enter().append("rect")
        .attr("class", "bar")
        .attr("x", 1)
        .attr("transform", function(d) {
          return "translate(" + x(d.x0) + "," + y(d.length) + ")";
        })
        .attr("width", function(d) { return x(d.x1) - x(d.x0) -1 ; })
        .attr("height", function(d) { return height - y(d.length); });

    svg.select(".xAxis")
        .duration(300)
        .call(d3.axisBottom(x));

    svg.select(".yAxis")
        .duration(300)
        .call(d3.axisLeft(y));
},
ready: function() {
    var margin = {top: 20, right: 20, bottom: 30, left: 50},
        width = this.width - margin.left - margin.right,
        height = this.height - margin.top - margin.bottom;

    // set the ranges
    var x = d3.scaleTime()
        .domain([new Date(2010, 6, 3), new Date(2012, 0, 1)])
        .rangeRound([0, width]);
    var y = d3.scaleLinear()
        .range([height, 0]);

    // Add the SVG to my 'chart' div.    
    var svg = d3.select(this.$.chart).append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform",
              "translate(" + margin.left + "," + margin.top + ")");

    // Add the X Axis
    svg.append("g")
        .attr("class","xAxis")
        .attr("transform", "translate(0," + height + ")")
        .call(d3.axisBottom(x));

    // Add the Y Axis
    svg.append("g")
        .attr("class","yAxis")
        .call(d3.axisLeft(y));
 }

ready() gets called upon rendering, dataChanged() when the parent component passes a chunk of data down. Everything works fine until svg.selectAll("rect").data(bins) is called when it crashes with Uncaught TypeError: svg.selectAll(...).data is not a function . bins has the right data in it, so that's not empty. I know that there are no rect elements for it to select, but in the example I followed here there are no rect elements prior to them being appended by this call anyway, so I'm confused as to why this doesn't work.

What's the purpose of this line:

var svg = d3.select(this.$.chart).transition();

This would make svg a transition, your code is implying it should be selection. So, just drop it the .transition :

var svg = d3.select(this.$.chart);

...

svg.selectAll("rect")
  .data(bins)
  ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM