如何将D3数组从JS数组更改为JS对象

时间:2017-11-22 09:28:45

标签: javascript d3.js

最初,当数据是这样的简单数组[21,3,5,21,15]时,它工作得很好。但是,当我尝试使用对象数组时,我得到以下错误,我不知道如何解决它。

Error: <rect> attribute y: Expected length, "NaN".

当我在return yScale(d.Amount);停止使用控制台调试器时,我看到它在数据中读取但有错误。它return h - yScale(d.Amount);正上方的返回线不会产生错误。

var myData = [{
  'Name': 'User1',
  'Amount': 21
}, {
  'Name': 'User2',
  'Amount': 3
}, {
  'Name': 'User3',
  'Amount': 5
}, {
  'Name': 'User4',
  'Amount': 21
}, {
  'Name': 'User5',
  'Amount': 15
}];
//Width and height
var w = 240;
var h = 250;
var yScale = null;

function draw(initialData) {
  var xScale = d3.scale.ordinal()
    .domain(d3.range(initialData.length))
    .rangeRoundBands([0, w], 0.05);

  yScale = d3.scale.linear()
    .domain([0, d3.max(initialData)])
    .range([0, h]);

  //Create SVG element
  var svg = d3.select("#chart")
    .append("svg")
    .attr("width", w)
    .attr("height", h);

  var xAxis = d3.svg.axis()
    .scale(xScale)
    .orient("bottom")
    .ticks(5);

  var yAxis = d3.svg.axis()
    .scale(yScale);

  svg.selectAll("rect")
    .data(initialData)
    .enter()
    .append("rect")
    .attr("x", function(d, i) {
      return xScale(i);
    })
    .attr("y", function(d) {
      return h - yScale(d.Amount);
    })
    .attr("width", xScale.rangeBand())
    .attr("height", function(d) {
      return yScale(d.Amount);
    })
    .attr("fill", "steelblue");

  svg.selectAll("text")
    .data(initialData)
    .enter()
    .append("text")
    .text(function(d) {
      return d.Amount;
    })
    .attr("text-anchor", "middle")
    .attr("x", function(d, i) {
      return xScale(i) + xScale.rangeBand() / 2;
    })
    .attr("y", function(d) {
      return h - yScale(d.Amount) + 14;
    })
    .attr("font-family", "sans-serif")
    .attr("font-size", "11px")
    .attr("fill", "white");

  var xAxisGroup = svg.append("g")
    .attr("transform", "translate(0," + 248 + ")")
    .style("stroke-width", "1px")
    .call(xAxis);
}

function update(newData) {
  yScale.domain([0, d3.max(newData)]);

  var rects = d3.select("#chart svg")
    .selectAll("rect")
    .data(newData);

  // enter selection
  rects
    .enter().append("rect");

  // update selection
  rects
    .transition()
    .duration(300)
    .attr("y", function(d) {
      return h - yScale(d.Amount);
    })
    .attr("height", function(d) {
      return yScale(d.Amount);
    })

  // exit selection
  rects
    .exit().remove();

  var texts = d3.select("#chart svg")
    .selectAll("text")
    .data(newData);

  // enter selection
  texts
    .enter().append("rect");

  // update selection
  texts
    .transition()
    .duration(300)
    .attr("y", function(d) {
      return h - yScale(d.Amount) + 14;
    })
    .text(function(d) {
      return d.Amount;
    })

  // exit selection
  texts
    .exit().remove();
}

window.onload = draw(myData);

var newData = [{
  'Name': 'User1',
  'Amount': 11
}, {
  'Name': 'User2',
  'Amount': 13
}, {
  'Name': 'User3',
  'Amount': 5
}, {
  'Name': 'User4',
  'Amount': 7
}, {
  'Name': 'User5',
  'Amount': 5
}];
d3.select("#update").on("click", function() {
  update(newData);
})

1 个答案:

答案 0 :(得分:1)

问题在于yScale域。

如果您只有一个数组,则可以将其传递给d3.max

yScale.domain([0, d3.max(newData)])

但是,现在你有一个对象数组,你必须定义你想要d3.max使用哪个属性:

.domain([0, d3.max(initialData, function(d){
    return d.Amount
})])

以下是仅包含此更改的代码:

 var myData = [{
   'Name': 'User1',
   'Amount': 21
 }, {
   'Name': 'User2',
   'Amount': 3
 }, {
   'Name': 'User3',
   'Amount': 5
 }, {
   'Name': 'User4',
   'Amount': 21
 }, {
   'Name': 'User5',
   'Amount': 15
 }];
 //Width and height
 var w = 240;
 var h = 250;
 var yScale = null;

 function draw(initialData) {
   var xScale = d3.scale.ordinal()
     .domain(d3.range(initialData.length))
     .rangeRoundBands([0, w], 0.05);

   yScale = d3.scale.linear()
     .domain([0, d3.max(initialData, function(d){return d.Amount})])
     .range([0, h]);

   //Create SVG element
   var svg = d3.select("body")
     .append("svg")
     .attr("width", w)
     .attr("height", h);

   var xAxis = d3.svg.axis()
     .scale(xScale)
     .orient("bottom")
     .ticks(5);

   var yAxis = d3.svg.axis()
     .scale(yScale);

   svg.selectAll("rect")
     .data(initialData)
     .enter()
     .append("rect")
     .attr("x", function(d, i) {
       return xScale(i);
     })
     .attr("y", function(d) {
       return h - yScale(d.Amount);
     })
     .attr("width", xScale.rangeBand())
     .attr("height", function(d) {
       return yScale(d.Amount);
     })
     .attr("fill", "steelblue");

   svg.selectAll("text")
     .data(initialData)
     .enter()
     .append("text")
     .text(function(d) {
       return d.Amount;
     })
     .attr("text-anchor", "middle")
     .attr("x", function(d, i) {
       return xScale(i) + xScale.rangeBand() / 2;
     })
     .attr("y", function(d) {
       return h - yScale(d.Amount) + 14;
     })
     .attr("font-family", "sans-serif")
     .attr("font-size", "11px")
     .attr("fill", "white");

   var xAxisGroup = svg.append("g")
     .attr("transform", "translate(0," + 248 + ")")
     .style("stroke-width", "1px")
     .call(xAxis);
 }

 function update(newData) {
   yScale.domain([0, d3.max(newData)]);

   var rects = d3.select("#chart svg")
     .selectAll("rect")
     .data(newData);

   // enter selection
   rects
     .enter().append("rect");

   // update selection
   rects
     .transition()
     .duration(300)
     .attr("y", function(d) {
       return h - yScale(d.Amount);
     })
     .attr("height", function(d) {
       return yScale(d.Amount);
     })

   // exit selection
   rects
     .exit().remove();

   var texts = d3.select("#chart svg")
     .selectAll("text")
     .data(newData);

   // enter selection
   texts
     .enter().append("rect");

   // update selection
   texts
     .transition()
     .duration(300)
     .attr("y", function(d) {
       return h - yScale(d.Amount) + 14;
     })
     .text(function(d) {
       return d.Amount;
     })

   // exit selection
   texts
     .exit().remove();
 }

 window.onload = draw(myData);

 var newData = [{
   'Name': 'User1',
   'Amount': 11
 }, {
   'Name': 'User2',
   'Amount': 13
 }, {
   'Name': 'User3',
   'Amount': 5
 }, {
   'Name': 'User4',
   'Amount': 7
 }, {
   'Name': 'User5',
   'Amount': 5
 }];
 d3.select("#update").on("click", function() {
   update(newData);
 })
<script src="https://d3js.org/d3.v3.min.js"></script>