我正在使用d3创建水平条形图。而且我正在使用动画在启动时“增长”图表。这是代码。
// Create the svg element
d3.select("#chart-area")
.append("svg")
.attr("height", 800)
.attr("width", 800);
.data(dataValues) // This data is previously prepared
.enter().append("rect")
.style("fill", "blue")
.attr("x", function () { return xScale(0); }) // xScale is defined earlier
.attr("y", function (d) { return yScale(d); }) // yScale is defined earlier
.attr("height", yScale.bandwidth()) // yScale is defined earlier
// Initial value of "width" (before animation)
.attr("width", 0)
// Start of animation transition
.transition()
.duration(5000) // 5 seconds
.ease (d3.easeLinear);
// Final value of "width" (after animation)
.attr("width", function(d) { return Math.abs(xScale(d) - xScale(0)); })
上面的代码可以正常工作,并且线条将在5秒钟内按预期的方式从0增长到任意宽度。
现在,如果我们将宽松线更改为以下内容
// This line changed
.ease (d3.easeElasticIn);
然后,轻松度将尝试使宽度达到负值,然后再达到最终的正值。 As you can see here,d3.easeElasticIn
随着时间的流逝返回负值,然后返回正值,从而导致动画中某些点的宽度为负。因此,这些条不能正确渲染(因为SVG规范指出,如果width为负,则使用0)
我尝试了每种解决方案,以使金条负增长然后退出。但是找不到任何东西。我该如何解决这个问题?
谢谢。
答案 0 :(得分:2)
您已经知道,在您的特定代码中使用d3.easeElasticIn
将为矩形的宽度创建负值,这是不允许的。
此基本演示重现了该问题,在控制台(您的浏览器的控制台,而不是代码段的控制台)中填充了错误消息,如下所示:
错误:属性width =“-85.90933910798789”的无效负值
看看:
const svg = d3.select("svg");
const margin = 50;
const line = svg.append("line")
.attr("x1", margin)
.attr("x2", margin)
.attr("y1", 0)
.attr("y2", 150)
.style("stroke", "black")
const data = d3.range(10).map(function(d) {
return {
y: "bar" + d,
x: Math.random()
}
});
const yScale = d3.scaleBand()
.domain(data.map(function(d) {
return d.y
}))
.range([0, 150])
.padding(0.2);
const xScale = d3.scaleLinear()
.range([margin, 300]);
const bars = svg.selectAll(null)
.data(data)
.enter()
.append("rect")
.attr("x", margin)
.attr("width", 0)
.style("fill", "steelblue")
.attr("y", function(d) {
return yScale(d.y)
})
.attr("height", yScale.bandwidth())
.transition()
.duration(2000)
.ease(d3.easeElasticIn)
.attr("width", function(d) {
return xScale(d.x) - margin
})
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg></svg>
那么,解决方案是什么?
其中之一是在生成负值时捕获这些负值,然后将矩形向左移动(使用x
属性并将这些负数转换为正数。
为此,我们必须在过渡选择中使用attrTween而不是attr
。
赞:
.attrTween("width", function(d) {
return function(t){
return Math.abs(xScale(d.x) * t);
};
})
.attrTween("x", function(d) {
return function(t){
return xScale(d.x) * t < 0 ? margin + xScale(d.x) * t : margin;
};
})
在上面的代码段中,margin
只是我创建的一个空白,因此您可以看到轴左侧的条形图。
这是演示:
const svg = d3.select("svg");
const margin = 100;
const line = svg.append("line")
.attr("x1", margin)
.attr("x2", margin)
.attr("y1", 0)
.attr("y2", 150)
.style("stroke", "black")
const data = d3.range(10).map(function(d) {
return {
y: "bar" + d,
x: Math.random()
}
});
const yScale = d3.scaleBand()
.domain(data.map(function(d) {
return d.y
}))
.range([0, 150])
.padding(0.2);
const xScale = d3.scaleLinear()
.range([0, 300 - margin]);
const bars = svg.selectAll(null)
.data(data)
.enter()
.append("rect")
.attr("x", margin)
.attr("width", 0)
.style("fill", "steelblue")
.attr("y", function(d) {
return yScale(d.y)
})
.attr("height", yScale.bandwidth())
.transition()
.duration(2000)
.ease(d3.easeElasticIn)
.attrTween("width", function(d) {
return function(t) {
return Math.abs(xScale(d.x) * t);
};
})
.attrTween("x", function(d) {
return function(t) {
return xScale(d.x) * t < 0 ? margin + xScale(d.x) * t : margin;
};
})
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg></svg>