d3.js:如何解决我的交互式饼图?
问题描述:
我在教自己如何在d3.js中制作交互式可视化,目前通过Elijah Meeks的D3.js In Action工作。我试图让他的饼图示例交互使用三个按钮。我在补间时做了一些错误 - 我试图保存当前显示的饼图,以便在它和新选择的饼图之间进行过渡。但是,我目前的派不断重置为初始派。我认为这可能很简单,但我无法弄清楚我做错了什么。d3.js:如何解决我的交互式饼图?
有人可以告诉我要改变什么来使我的转换工作?再次
- 运行下面的代码,
- 点击“统计2”按钮,
- 点击“统计2”按钮 - 你会看到馅饼重置为“统计:为了说明问题1',然后平稳过渡到'Stat 2'。
.as-console-wrapper { max-height: 20% !important;}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<div id="viz">
<button id="0"> Stat 1 </button>
<button id="1"> Stat 2 </button>
<button id="2"> Stat 3 </button>
<br>
<svg style="width:400px;height:300px;border:1px lightgray solid;" />
</div>
</body>
<script>
var obj = [{
name: "a",
stat1: 10,
stat2: 20,
stat3: 30,
}, {
name: "b",
stat1: 30,
stat2: 20,
stat3: 10,
}, {
name: "c",
stat1: 15,
stat2: 25,
stat3: 50,
}];
function piechart(data) {
var currentPie = 0; //Initialize to stat1
var fillScale = d3.scaleOrdinal(d3.schemeCategory10);
var pieChart = d3.pie().sort(null);
var newArc = d3.arc().innerRadius(50).outerRadius(100);
// Create each pie chart
pieChart.value(d => d.stat1);
var stat1Pie = pieChart(data);
pieChart.value(d => d.stat2);
var stat2Pie = pieChart(data);
pieChart.value(d => d.stat3);
var stat3Pie = pieChart(data);
// Embed slices on each name
data.forEach((d, i) => {
var slices = [stat1Pie[i], stat2Pie[i], stat3Pie[i]];
d.slices = slices;
});
d3.select("svg")
.append("g")
.attr("transform", "translate(200, 150)")
.selectAll("path")
.data(data)
.enter()
.append("path")
.attr("d", d => newArc(d.slices[currentPie]))
.attr("fill", (d, i) => fillScale(i))
.attr("stroke", "black")
.attr("stroke-width", "2px");
function transPie(d) {
var newPie = this.id;
console.log("Transition from pie " + currentPie + " to pie " + newPie);
d3.selectAll("path")
.transition()
.delay(500)
.duration(1500)
.attrTween("d", tweenPies)
function tweenPies(d, i) {
console.log(i + ":start tween function \n current pie = " + currentPie + "\n new pie = " + newPie);
var currentAngleStart = d.slices[currentPie].startAngle;
var newAngleStart = d.slices[newPie].startAngle;
var currentAngleEnd = d.slices[currentPie].endAngle;
var newAngleEnd = d.slices[newPie].endAngle;
return t => {
var interpolateStartAngle = d3.interpolate(currentAngleStart, newAngleStart);
var interpolateEndAngle = d3.interpolate(currentAngleEnd, newAngleEnd);
d.startAngle = interpolateStartAngle(t);
d.endAngle = interpolateEndAngle(t);
return newArc(d);
};
};
};
d3.selectAll("button").on("click", transPie);
};
piechart(obj);
</script>
</html>
答
你从未设置的currentPie
的状态到新状态的选择之后。我添加了一个.on('end',
处理器过渡到设置此状态:
.on('end', function(){
currentPie = newPie;
});
运行代码:
<html>
<head>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<div id="viz">
<button id="0"> Stat 1 </button>
<button id="1"> Stat 2 </button>
<button id="2"> Stat 3 </button>
<br />
<svg style="width:1000px;height:500px;border:1px lightgray solid;"></svg>
</div>
<script>
var obj = [{name: "a",stat1: 10,stat2: 20,stat3: 30,},
{name: "b",stat1: 30,stat2: 20,stat3: 10,},
{name: "c",stat1: 15,stat2: 25,stat3: 50,}];
function piechart(data){
var currentPie = 0; //Initialize to stat1
var fillScale = d3.scaleOrdinal(d3.schemeCategory10);
var pieChart = d3.pie().sort(null);
var newArc = d3.arc().innerRadius(50).outerRadius(100);
// Create each pie chart
pieChart.value(d => d.stat1);
var stat1Pie = pieChart(data);
pieChart.value(d => d.stat2);
var stat2Pie = pieChart(data);
pieChart.value(d => d.stat3);
var stat3Pie = pieChart(data);
// Embed slices on each name
data.forEach((d,i) => {
var slices = [stat1Pie[i], stat2Pie[i], stat3Pie[i]];
d.slices = slices;
});
d3.select("svg")
.append("g")
.attr("transform", "translate(250, 250)")
.selectAll("path")
.data(data)
.enter()
.append("path")
.attr("d", d => newArc(d.slices[currentPie]))
.attr("fill", (d,i) => fillScale(i))
.attr("stroke", "black")
.attr("stroke-width", "2px");
function transPie(d) {
var newPie = +this.id;
console.log("Transition from pie " +currentPie+ " to pie " + newPie);
d3.selectAll("path")
.transition()
.delay(500)
.duration(1500)
.attrTween("d", tweenPies)
.on('end', function(){
currentPie = newPie;
})
function tweenPies(d, i) {
console.log(i + ":start tween function \n current pie = " + currentPie + "\n new pie = "+newPie);
var currentAngleStart = d.slices[currentPie].startAngle;
var newAngleStart = d.slices[newPie].startAngle;
var currentAngleEnd = d.slices[currentPie].endAngle;
var newAngleEnd = d.slices[newPie].endAngle;
return t => {
var interpolateStartAngle = d3.interpolate(currentAngleStart, newAngleStart);
var interpolateEndAngle = d3.interpolate(currentAngleEnd, newAngleEnd);
d.startAngle = interpolateStartAngle(t);
d.endAngle = interpolateEndAngle(t);
return newArc(d);
};
};
};
d3.selectAll("button").on("click", transPie);
};
piechart(obj);
</script>
</body>
</html>
如果你想让人们运行您的代码,使用堆栈段(''符号)。 –