How to create bar chart with path property in d3js?

巧了我就是萌 提交于 2020-02-23 04:28:07

问题


Below is how I creat a bar chart using rects in D3. However, how would I modify that to get the bar chart with path property in d3js?

I have a json file which has the data to be read and am trying to create a bar chart with paths rather than rectangles in d3js.

Json :

[
  {
    "name": "sam",
    "age": 24
  },
  {
    "name": "baby",
    "age": 23
  },
  {
    "name": "adu",
    "age": 21
  },
  {
    "name": "ja",
    "age": 23
  },
  {
    "name": "mack",
    "age": 34
  }
]

Code:

   <script>
        d3.json("mydata.json", function (data) {

           var canvas = d3.select('body').append('svg')
               .attr('width', 500)
               .attr('height', 500);

           canvas.selectAll('rect')
               .data(data)
               .enter()
                   .append('rect')
                   .attr('width',function (d) { return d.age * 10; })
                   .attr('height', 48)
                   .attr('y', function (d, i) { return i * 50; })
                   .attr('fill', 'blue');

           canvas.selectAll('text')
               .data(data)
               .enter()
                    .append('text')
                    .attr('fill','white')
                    .attr('y', function (d, i) {
                        return i* 50 + 24;
                    })
               .text(function (d) {
                   return d.name;
               })
        });
    </script>

I have searched through many sites. I am unable to get though


回答1:


You can't assign a d attribute to a rectangle, but you can make a bar chart out of paths rather than rectangles. All you need to do is know the coordinates of the corners of the rectangle. You really only need two corners on opposite sides. If you had top left and bottom right coordinates ([x0,y0] and [x1,y1] respectively) you could do something like:

function drawRect(x0,y0,x1,y1) {
  var p1 = x0 + " " + y0;
  var p2 = x0 + " " + y1;
  var p3 = x1 + " " + y1;
  var p4 = x1 + " " + y0;

  var l = "L";  // cause I'm lazy.
  return "M"+p1+l+p2+l+p3+l+p4+"Z";

}

This moves the cursor to p1, then draws connecting lines from p1 to p2 to p3 to p4 and then returns to the start with Z.

With scaled values this could get a bit verbose either passing scaled parameters or scaling the values in the path making function (as I do below).

This might look like (paths fade in so you can see that they match the rects):

var data = [1,2,3,5,8,3];
var width = 500;
var height = 300;

var svg = d3.select("body")
  .append("svg")
  .attr("width",width)
  .attr("height",height);
  
var x = d3.scaleBand()
  .domain(d3.range(data.length))
  .range([0,width]);
  
var y = d3.scaleLinear()
  .domain([0,d3.max(data)])
  .range([height,0]);
  
svg.selectAll("rect")
  .data(data)
  .enter()
  .append("rect")
  .attr("width", x.bandwidth())
  .attr("height", function(d) { return height-y(d); })
  .attr("x", function(d,i) { return x(i); })
  .attr("y", function(d) { return y(d); })
  
svg.selectAll("path")
  .data(data)
  .enter()
  .append("path")
  .attr("d", makeRect)
  .attr("fill","orange")
  .style("opacity",0)
  .transition()
  .style("opacity",1)
  .duration(1500);
  
  
function makeRect(d,i) {
  var x0 = x(i);
  var y0 = y(d);
  var x1 = x(i) + x.bandwidth();
  var y1 = height;

  var p1 = x0 + " " + y0;
  var p2 = x0 + " " + y1;
  var p3 = x1 + " " + y1;
  var p4 = x1 + " " + y0;
  var l = "L";
  
  return "M"+p1+l+p2+l+p3+l+p4+"Z";

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>

But, this can't really be a preferred option in most cases. It is more complex than the rectangles for sure. The rectangle should be preferable, unless of course you are trying to do some sort of manipulation on the path that you can't do with a rectangle, or maybe you want rounded edges. Perhaps you are projecting the path on a globe or maybe you want to do some path transition (I've added extra vertices to the rectangle path to smooth the transition, in most cases, ideally the start and end paths of a transition have the same number of vertices):

var data = [1,2,3,5,8,3];
var width = 500;
var height = 200;

var svg = d3.select("body")
  .append("svg")
  .attr("width",width)
  .attr("height",height);
  
var x = d3.scaleBand()
  .domain(d3.range(data.length))
  .range([0,width]);
  
var y = d3.scaleLinear()
  .domain([0,d3.max(data)])
  .range([height,0]);
  
  
  
svg.selectAll("path")
  .data(data)
  .enter()
  .append("path")
  .attr('d', d3.symbol().type( d3.symbols[1]).size(function(d){ return  d*100; }) )
  .attr("transform","translate(0,"+height/2+")")
  .transition()
  .attr("transform",function(d,i) { return "translate("+(x(i)+x.bandwidth()/2) + "," + height/2 + ")" })
  .attr("fill","steelblue")
  .duration(1500)
  .transition()
  .attr("d", makeRect)
  .attr("fill","orange")
  .attr("transform","translate(0,0)")
  .duration(1500);
  //*/
  
function makeRect(d,i) {
  var x0 = x(i);
  var y0 = y(d);
  var x1 = x(i) + x.bandwidth();
  var y1 = height;
  
  var p1 = x0 + " " + y0;
  var p2 = x0 + " " + y1;
  var p3 = x1 + " " + y1;
  var p4 = x1 + " " + y0;
  var l = "L";
  
  return "M"+p1+l+p1+l+p1+l+p4+l+p4+l+p4+l+p3+l+p3+l+p3+l+p2+l+p2+l+p2+"Z";

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>


来源:https://stackoverflow.com/questions/51275960/how-to-create-bar-chart-with-path-property-in-d3js

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!