如何在d3.js中制作带有扩展网格的圆角条形图?

时间:2018-09-17 17:17:29

标签: javascript d3.js charts

我正在尝试使用D3.js创建条形图。条件是条形图应具有固定的宽度和条形图之间的填充,并且应绘制在网格线的中心。

单击时工具提示应显示一条垂直线

我能够用绘制的条形创建网格线,不知何故rx,ry从两侧都取整。 我如何获得相同的结果。

first()

Js Fiddle for the same

我正在努力实现这样的目标。enter image description here

2 个答案:

答案 0 :(得分:4)

一种选择是使用剪切路径,但是您也可以使用与构建矩形相同的信息来创建简单的路径生成器:x,y,宽度,高度以及半径。路径很简单:

  1. 移动到左下角
  2. 直线到左上角弧的底部
  3. 弧到左上角弧的顶部
  4. 直线到右上角的弧顶
  5. 弧到右上角的底部。
  6. 直线到右下角
  7. 关闭路径。

哪个是类似的东西

  1. M x,y
  2. L x,y-height + radius
  3. 半径,半径,0、0、1,x +半径,y高度
  4. L x + width-r,y-height
  5. 半径,半径,0、0、1,x +宽度,y-高度+半径
  6. L x + width,y
  7. Z

看起来像这样(一个相当懒惰的实现):

function bar(x,y,w,h,r,f) {
    // Flag for sweep:
    if(f == undefined) f = 1;
    // x coordinates of top of arcs
    var x0 = x+r;
    var x1 = x+w-r;
    // y coordinates of bottom of arcs
    var y0 = y-h+r;

    // assemble path:
    var parts = [
      "M",x,y,               // step 1
      "L",x,y0,              // step 2
      "A",r,r,0,0,f,x0,y-h,  // step 3
      "L",x1,y-h,            // step 4
      "A",r,r,0,0,f,x+w,y0,  // step 5
      "L",x+w,y,             // step 6
      "Z"                    // step 7
     ];
    return parts.join(" ");
}

我包括了一个可选的扫掠标志(f)-如果设置为0,它将反转弧。

并应用如下内容:

 .attr("d", function(d) { 
    return bar(x(d),y(0),x.bandwidth(),y(0)-y(d),15);  
  })

放在一起,您可能会得到类似的东西:

var width = 500;
var height = 200;
var svg = d3.select("body").append("svg").attr("width",width).attr("height",height);
var data = [ 10,20,30,40,20,50,60 ];

var x = d3.scaleBand().domain(d3.range(data.length)).range([10,width-10]).paddingInner(0.1);
var y = d3.scaleLinear().domain([0,60]).range([height-10,10]);

var bars = svg.selectAll(null)
  .data(data)
  .enter()
  .append("path")
  .attr("d", function(d,i) { 
	  return bar(x(i),y(0),x.bandwidth(),y(0)-y(d),10);  
  })
  
function bar(x,y,w,h,r,f) {
	// Flag for sweep:
	if(f == undefined) f = 1;
	
	// x coordinates of top of arcs
	var x0 = x+r;
	var x1 = x+w-r;
	// y coordinates of bottom of arcs
	var y0 = y-h+r;
	// just for convenience (slightly different than above):
	var l = "L", a = "A";

	var parts = ["M",x,y,l,x,y0,a,r,r,0,0,f,x0,y-h,l,x1,y-h,a,r,r,0,0,f,x+w,y0,l,x+w,y,"Z"];
	return parts.join(" ");
}

// Still transitionable:
bars.data(data.reverse())
 .transition()
 .attr("d", function(d,i) { 
  return bar(x(i),y(0),x.bandwidth(),y(0)-y(d),30);  
 })
 .duration(2000)
 .transition()
 .attr("d", function(d,i) { 
  return bar(x(i),y(0),x.bandwidth(),y(0)-y(d),0);  
 })
 .duration(2000)
 .transition()
 .attr("d", function(d,i) { 
  return bar(x(i),y(0),x.bandwidth(),y(0)-y(d),15);  
  })
 .duration(2000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>

如果半径超过钢筋高度或宽度的一半,则会得到一些更时髦的结果,对此的完整实现将考虑进行检查,以确保钢筋的半径不要太大 < / p>

答案 1 :(得分:0)

我的第一个选择是使用clipPath(在此处回答:Rounded corner only on one side of svg <rect>

另一种选择是简单地在具有正方形角的底部绘制另一个矩形:

rectCluster
                    .enter().append("rect")
                    .attr("class", function(d) {
                        return "bar";
                    })
                    .attr(attrs)
                    .attr({ry : (20), rx : 20 })
                    .attr("x", function(d) { return x(d.text); })
                    .attr("y", function(d) {
                        return height;
                    })
                    .style("fill", function(d) {
                        return color(d.text);
                    })
                    .attr("width", x.rangeBand())
                    .attr("height", 0)
                    .transition()
                    .duration(animationDelay)
                    .delay(function(d, i) {
                        return i * animationDelay;
                    })
                    .attr("y", function(d) { return y(d.score); })
                    .attr("height", function(d) { return height - y(d.score) });

                 // SQUARE CORNERS
                 rectCluster
                    .enter().append("rect")
                    .attr("class", function(d) {
                        return "bar";
                    })
                    .attr(attrs)
                    .attr({ry : (20), rx : 0 })
                    .attr("x", function(d) { return x(d.text); })
                    .attr("y", 0)
                    .style("fill", function(d) {
                        return color(d.text);
                    })
                    .attr("width", x.rangeBand())
                    .attr("height", 0)
                    .transition()
                    .duration(animationDelay)
                    .delay(function(d, i) {
                        return i * animationDelay;
                    })
                    .attr("y", height-20)
                    .attr("height", 20);

请参阅小提琴:

https://jsfiddle.net/6x2y35gn/40/