我正在尝试创建一个视觉,它是Arc Tween演示的修改。在其中,我想要一组数据来定义每个弧的颜色和一般半径,并且在一个间隔上,开始和结束角度都应该慢慢地生成动画。但我认为我定义每个弧的方式导致事物过度生动。
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<script src="https://d3js.org/d3.v4.min.js"></script>
<title>Arcs</title>
</head>
<body>
<svg width="960" height="500"></svg>
</body>
</html>
SCRIPT
// Modified from Arc Tween
// https://bl.ocks.org/mbostock/5100636
var tau = 2 * Math.PI; // http://tauday.com/tau-manifesto
var overlap = 50
var jsonArcs = [
{ "base_radius": 370, "color" : "red"},
{ "base_radius": 330, "color" : "orange"},
{ "base_radius": 290, "color" : "yellow"},
{ "base_radius": 250, "color" : "green"},
{ "base_radius": 210, "color" : "blue" },
{ "base_radius": 170, "color" : "purple"},
{ "base_radius": 130, "color" : "black"},
{ "base_radius": 90, "color" : "red"}
];
var arc = d3.arc()
.startAngle(function(d) { return Math.random() * tau; })
.endAngle(function(d) { return Math.random() * tau; })
.innerRadius(function(d) { return d.base_radius - overlap * Math.random(); })
.outerRadius(function(d) { return d.base_radius + overlap * Math.random(); });
var center_def = d3.arc()
.innerRadius(0)
.outerRadius(60)
.startAngle(0);
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var path = g.selectAll("path")
.data(jsonArcs)
.enter().append("path")
.attr("fill", function(d, i) { return d.color; })
.attr("d", arc);
var center = g.append("path")
.datum({endAngle: tau})
.style("fill", "black")
.attr("d", center_def);
d3.interval(function() {
path.transition()
.duration(750)
.attrTween("d", arcTween(Math.random() * tau, arc));
}, 2500);
function arcTween(newAngle, obj) {
return function(d) {
var interpolate = d3.interpolate(d.endAngle, newAngle);
return function(t) {
d.endAngle = interpolate(t);
return obj(d);
};
};
}
而不是每个弧线从起始角度平滑地动画到新角度,整个视觉跳跃多次到新状态。
如何配置此功能,使每个弧平滑地将其开始和结束角度从旧转换为新?
答案 0 :(得分:2)
这里有一些问题
你的弧函数将在每次调用时返回随机半径,这不是我想你想要的。您可以将弧从一个内/外半径转换到下一个半径,但为简单起见,假设每个路径最初只获得一个随机半径
为了从旧的一对开始/结束角度过渡到新角度,您需要将当前角度存储在某处。我们会将其存储在local variable中,该here将绑定到每条路径
因为每条路径都有不同的内/外半径,我们也需要为每个分段设置不同的弧函数。
这里的工作代码:
var tau = 2 * Math.PI; // http://tauday.com/tau-manifesto
var overlap = 50;
var currentSegment = d3.local();
var segmentRadius = d3.local();
var jsonArcs = [
{ "base_radius": 370, "color" : "red"},
{ "base_radius": 330, "color" : "orange"},
{ "base_radius": 290, "color" : "yellow"},
{ "base_radius": 250, "color" : "green"},
{ "base_radius": 210, "color" : "blue" },
{ "base_radius": 170, "color" : "purple"},
{ "base_radius": 130, "color" : "black"},
{ "base_radius": 90, "color" : "red"}
];
var arc = d3.arc()
.innerRadius(function() { return segmentRadius.get(this).innerRadius })
.outerRadius(function() { return segmentRadius.get(this).outerRadius });
var center_def = d3.arc()
.innerRadius(0)
.outerRadius(60)
.startAngle(0);
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var path = g.selectAll("path")
.data(jsonArcs)
.enter().append("path")
.attr("fill", function(d, i) { return d.color; })
.each(function(d) {
var angles = randomAngles();
d.startAngle = angles.startAngle;
d.endAngle = angles.endAngle;
segmentRadius.set(this, {
innerRadius: d.base_radius - overlap * Math.random(),
outerRadius: d.base_radius + overlap * Math.random()
});
})
.attr("d", arc)
.each(function(d) {currentSegment.set(this, d)});
var center = g.append("path")
.datum({endAngle: tau})
.style("fill", "black")
.attr("d", center_def);
d3.interval(function() {
path.transition()
.duration(750)
.attrTween("d", arcTween);
}, 2500);
function arcTween() {
var thisPath = this;
var interpolate = d3.interpolate(currentSegment.get(this), randomAngles());
currentSegment.set(this, interpolate(0));
return function(t) {
return arc.call(thisPath, interpolate(t));
};
}
function randomAngles() {
var angles = [Math.random() * tau, Math.random() * tau].sort();
return {startAngle: angles[0], endAngle: angles[1]};
}
请注意有关已更改代码的一些事项:
我有一个类似的例子,如果你想了解更多,我一直在{{3}}上工作。