我正在尝试使用D3.js创建条形图。条件是条形图应具有固定的宽度和条形图之间的填充,并且应绘制在网格线的中心。
单击时工具提示应显示一条垂直线
我能够用绘制的条形创建网格线,不知何故rx,ry从两侧都取整。 我如何获得相同的结果。
first()
答案 0 :(得分:4)
一种选择是使用剪切路径,但是您也可以使用与构建矩形相同的信息来创建简单的路径生成器:x,y,宽度,高度以及半径。路径很简单:
哪个是类似的东西
看起来像这样(一个相当懒惰的实现):
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);
请参阅小提琴: