我正在尝试连续制作条形图的动画。我使用以下作为参考......
How to animate a horizontal D3 bar chart?
我看到动画每3秒出现一次,但是每个备用数据栏都会显示不正确的数据。无法弄清楚原因。
我的代码:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
width: 960px;
height: 500px;
position: relative;
}
svg {
width: 100%;
height: 100%;
position: center;
}
.toolTip {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
position: absolute;
display: none;
width: auto;
height: auto;
background: none repeat scroll 0 0 white;
border: 0 none;
border-radius: 8px 8px 8px 8px;
box-shadow: -3px 3px 15px #888888;
color: black;
font: 12px sans-serif;
padding: 5px;
text-align: center;
}
text {
font: 10px sans-serif;
color: white;
}
<!-- text.value { -->
font-size: 120%;
fill: white;
}
.axisHorizontal path{
fill: none;
}
.axisHorizontal .tick line {
stroke-width: 1;
stroke: rgba(0, 0, 0, 0.2);
}
.bar {
fill: steelblue;
fill-opacity: .9;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
data = [
{label:"Category 1", value:19},
{label:"Category 2", value:5},
{label:"Category 3", value:13},
{label:"Category 4", value:17},
{label:"Category 5", value:19},
{label:"Category 6", value:27}
];
var div = d3.select("body").append("div").attr("class", "toolTip");
var axisMargin = 20,
margin = 40,
valueMargin = 4,
width = parseInt(d3.select('body').style('width'), 10),
height = parseInt(d3.select('body').style('height'), 10),
barHeight = (height-axisMargin-margin*2)* 0.4/data.length,
barPadding = (height-axisMargin-margin*2)*0.6/data.length,
data, bar, svg, scale, xAxis, labelWidth = 0;
max = d3.max(data, function(d) { return d.value; });
svg = d3.select('body')
.append("svg")
.attr("width", width)
.attr("height", height);
bar = svg.selectAll("g")
//.exit()
.data(data)
.enter()
.append("g")
;
bar.attr("class", "bar")
.attr("cx",0)
.attr("transform", function(d, i) {
return "translate(" + margin + "," + (i * (barHeight + barPadding) + barPadding) + ")";
});
bar.append("text")
.attr("class", "label")
.attr("y", barHeight / 2)
.attr("dy", ".35em") //vertical align middle
.text(function(d){
return d.label;
}).each(function() {
labelWidth = Math.ceil(Math.max(labelWidth, this.getBBox().width));
});
scale = d3.scale.linear()
.domain([0, max])
.range([0, width - margin*2 - labelWidth]);
xAxis = d3.svg.axis()
.scale(scale)
.tickSize(-height + 2*margin + axisMargin)
.orient("bottom");
bar.append("rect")
.attr("transform", "translate("+labelWidth+", 0)")
.attr("height", barHeight)
.attr("width", 0)//this is the initial value
.transition()
.duration(1500)//time in ms
//.delay(function(d,i){ if(d.label == 'Category 6'){return 0}else{return i*350}})//a different delay for each bar
.attr("width", function(d){return scale(d.value);})
;
//now, the final value
function repeat() {
var rect = bar.selectAll("rect")
.remove()
.data(data, function(d) { return d.value; })
.enter()
.append("rect")
.attr("transform", "translate("+labelWidth+", 0)")
.attr("height", barHeight)
.attr("width", 0)//this is the initial value
;
rect.transition()
.duration(1500)
.attr("width",0)
//.delay(function(d,i){ if(d.label == 'Category 6'){return 0}else{return i*350}})//a different delay for each bar
.attr("width", function(d){return scale(d.value);});
//rect.exit().transition()
//.duration(1500)
//.attr("width", function(d){return scale(d.value);})
//.remove();
rect.exit().remove();
}
setInterval(function(){repeat();},3000);
</script>
</body>
答案 0 :(得分:1)
在repeat
功能中,您不需要每次重新创建条形图以重新运行转换。它可以简化为:
function repeat() {
bar.select('rect')
.attr('width',0) //<-- width 0
.transition()
.duration(1500)
.attr("width", function(d){return scale(d.value);}); //<-- transition to full
}
运行代码:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
width: 960px;
height: 500px;
position: relative;
}
svg {
width: 100%;
height: 100%;
position: center;
}
.toolTip {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
position: absolute;
display: none;
width: auto;
height: auto;
background: none repeat scroll 0 0 white;
border: 0 none;
border-radius: 8px 8px 8px 8px;
box-shadow: -3px 3px 15px #888888;
color: black;
font: 12px sans-serif;
padding: 5px;
text-align: center;
}
text {
font: 10px sans-serif;
color: white;
}
<!-- text.value { -->
font-size: 120%;
fill: white;
}
.axisHorizontal path{
fill: none;
}
.axisHorizontal .tick line {
stroke-width: 1;
stroke: rgba(0, 0, 0, 0.2);
}
.bar {
fill: steelblue;
fill-opacity: .9;
}
</style>
<body>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script>
data = [
{label:"Category 1", value:19},
{label:"Category 2", value:5},
{label:"Category 3", value:13},
{label:"Category 4", value:17},
{label:"Category 5", value:19},
{label:"Category 6", value:27}
];
var div = d3.select("body").append("div").attr("class", "toolTip");
var axisMargin = 20,
margin = 40,
valueMargin = 4,
width = parseInt(d3.select('body').style('width'), 10),
height = parseInt(d3.select('body').style('height'), 10),
barHeight = (height-axisMargin-margin*2)* 0.4/data.length,
barPadding = (height-axisMargin-margin*2)*0.6/data.length,
data, bar, svg, scale, xAxis, labelWidth = 0;
max = d3.max(data, function(d) { return d.value; });
svg = d3.select('body')
.append("svg")
.attr("width", width)
.attr("height", height);
bar = svg.selectAll("g")
//.exit()
.data(data)
.enter()
.append("g")
;
bar.attr("class", "bar")
.attr("cx",0)
.attr("transform", function(d, i) {
return "translate(" + margin + "," + (i * (barHeight + barPadding) + barPadding) + ")";
});
bar.append("text")
.attr("class", "label")
.attr("y", barHeight / 2)
.attr("dy", ".35em") //vertical align middle
.text(function(d){
return d.label;
}).each(function() {
labelWidth = Math.ceil(Math.max(labelWidth, this.getBBox().width));
});
scale = d3.scale.linear()
.domain([0, max])
.range([0, width - margin*2 - labelWidth]);
xAxis = d3.svg.axis()
.scale(scale)
.tickSize(-height + 2*margin + axisMargin)
.orient("bottom");
bar.append("rect")
.attr("transform", "translate("+labelWidth+", 0)")
.attr("height", barHeight)
.attr("width", 0)//this is the initial value
.transition()
.duration(1500)//time in ms
//.delay(function(d,i){ if(d.label == 'Category 6'){return 0}else{return i*350}})//a different delay for each bar
.attr("width", function(d){return scale(d.value);})
;
//now, the final value
function repeat() {
bar.select('rect')
.attr('width',0)
.transition()
.duration(1500)
.attr("width", function(d){return scale(d.value);});
}
setInterval(function(){repeat();},3000);
</script>
</body>
&#13;