Animation 如何设置元素的动画以跟随圆弧';d3中的质心是什么?

Animation 如何设置元素的动画以跟随圆弧';d3中的质心是什么?,animation,d3.js,transition,pie-chart,Animation,D3.js,Transition,Pie Chart,我有一个简单的饼图,标签如下: var数据=[{ 标签:“星球大战”, 实例:20 }, { 标签:“迷失在太空”, 实例:32 }, { 标签:“波士顿流行音乐”, 实例:80 }, { 标签:“印第安纳琼斯”, 实例:74 }, { 标签:“哈利波特”, 实例:23 }, { 标签:“大白鲨”, 实例:10 }, { 标签:“林肯”, 实例:15 }]; svg=d3。选择(“svg”); 画布=d3。选择(“画布”); 艺术=d3.选择(“艺术”); 标签=d3。选择(“#标签”); v

我有一个简单的饼图,标签如下:

var数据=[{
标签:“星球大战”,
实例:20
}, {
标签:“迷失在太空”,
实例:32
}, {
标签:“波士顿流行音乐”,
实例:80
}, {
标签:“印第安纳琼斯”,
实例:74
}, {
标签:“哈利波特”,
实例:23
}, {
标签:“大白鲨”,
实例:10
}, {
标签:“林肯”,
实例:15
}];
svg=d3。选择(“svg”);
画布=d3。选择(“画布”);
艺术=d3.选择(“艺术”);
标签=d3。选择(“#标签”);
var pie=d3.layout.pie().value(函数(d,i){
返回d.instances;
})
.sort(空);
var高度=500,
宽度=500,
唇瓣半径=175;
svg.attr({
高度:高度,,
宽度:宽度
});
attr(“transform”、“translate”(+(width/2)+)、“+(height/2)+”);
arc=d3.svg.arc()
.内半径(50)
.外层(150);
颜色=d3.scale.category10();
var path=art.selectAll(“.wedge”).data(饼图(数据)).enter().append(“路径”)
.attr(“类”、“楔块”)
.attr(“d”,弧)
.样式(“填充”,功能(d,i){
返回颜色(i);
})
.每个功能(d){
这是。_电流=d;
});
输入标签=标签。选择全部(“.label”).data(饼图(数据)).enter();
labelGroups=输入labels.append(“g”).attr(“class”,“label”);
labelGroups.append(“圆圈”).attr({
x:0,,
y:0,
r:2,
填写:#000,
变换:函数(d,i){
质心=弧。质心(d);
返回“平移(“+弧形心(d)+”);
},
“类”:“标签圈”
});
textLines=labelGroups.append(“line”).attr({
x1:功能(d,i){
返回弧。质心(d)[0];
},
y1:功能(d,i){
返回弧。质心(d)[1];
},
x2:功能(d,i){
质心=弧。质心(d);
midAngle=Math.atan2(质心[1],质心[0]);
x=数学cos(中间角)*标签半径;
返回x;
},
y2:功能(d,i){
质心=弧。质心(d);
midAngle=Math.atan2(质心[1],质心[0]);
y=数学sin(中间角)*标签半径;
返回y;
},
“类”:“标签行”
});
textLabels=labelGroups.append(“text”).attr({
x:功能(d,i){
质心=弧。质心(d);
midAngle=Math.atan2(质心[1],质心[0]);
x=数学cos(中间角)*标签半径;
符号=(x>0)?1:-1
labelX=x+(5*符号)
返回标签;
},
y:函数(d,i){
质心=弧。质心(d);
midAngle=Math.atan2(质心[1],质心[0]);
y=数学sin(中间角)*标签半径;
返回y;
},
“文本锚定”:函数(d,i){
质心=弧。质心(d);
midAngle=Math.atan2(质心[1],质心[0]);
x=数学cos(中间角)*标签半径;
返回(x>0)?“开始”:“结束”;
},
“类”:“标签文本”
}).文本(功能(d){
返回d.data.label
});
α=0.5;
间距=12;
函数relax(){
再次=假;
文本标签。每个(函数(d,i){
a=这个;
da=d3。选择(a);
y1=日属性(“y”);
文本标签。每个(函数(d,j){
b=这个;
//a和b是相同的元素,不会发生碰撞。
如果(a==b)返回;
db=d3。选择(b);
//a&b位于图表的两侧,而
//不要碰撞
如果(da.attr(“文本锚”)!=db.attr(“文本锚”))返回;
//现在让我们计算一下
//这些元素。
y2=db.attr(“y”);
deltaY=y1-y2;
//我们的间距大于我们指定的间距,
//所以它们不会碰撞。
if(Math.abs(deltaY)>间距)返回;
//如果标签发生碰撞,我们将推动每个标签
//两个标签上下移动一点。
再次=正确;
符号=三角洲>0?1:-1;
调整=符号*α;
da.属性(“y”、+y1+调整);
db.attr(“y”+y2-调整);
});
});
//在这里调整我们的领队
//这样他们就能跟着标签走了。
如果(再次){
Labelements=textLabels[0];
textLines.attr(“y2”,函数(d,i){
labelForLine=d3.select(labelements[i]);
返回labelForLine.attr(“y”);
});
设置超时(放松,20)
}
}
放松();
d3.选择全部(“随机化”)
.on(“单击”,函数(){
data=U8;(data).map(函数(v){
v、 实例=Math.floor((Math.random()*100)+1);
返回v;
});
饼图值(函数(d){
返回d.instances;
});
路径=路径
.数据(pie(数据));
path.transition()持续时间(750)
.attrTween(“d”,函数(d){
var interpolate=d3.interpolate(该电流,d);
该值为._电流=插值(0);
返回函数(t){
返回弧(插值(t));
};
});
});
。标签文本{
路线基线:中间;
字体大小:12px;
字体系列:arial,helvetica,“无衬线”;
填写:#393939;
}
.标签线{
笔画宽度:1;
行程#393939;
}
.标签圈{
填写:#393939;
}
#随机化{
位置:绝对位置;
填充:10px;
z指数:100;
}

随机化

单击功能中,您需要重置绑定到各种DOM的数据:

//update the groups with the new data
enteringLabels = labels.selectAll(".label").data(pie(data));
//update the circle with the new data
labelGroups = d3.selectAll(".label-circle").data(pie(data));
//update the lines with the new data
textLines = d3.selectAll(".label-line").data(pie(data));
//update the text with the data
textLabels = d3.selectAll(".label-text").data(pie(data));
//for transition   
labelGroups.transition().duration(1000).attr({
  transform: function(d, i) {
    centroid = arc.centroid(d);
    return "translate(" + arc.centroid(d) + ")";
  },
  'class': "label-circle"
});   
//for transition   
textLines.transition().duration(1000).attr({
  x1: function(d, i) {
    return arc.centroid(d)[0];
  },
  y1: function(d, i) {
    return arc.centroid(d)[1];
  },
  x2: function(d, i) {
    centroid = arc.centroid(d);
    midAngle = Math.atan2(centroid[1], centroid[0]);
    x = Math.cos(midAngle) * labelRadius;
    return x;
  },
  y2: function(d, i) {
    centroid = arc.centroid(d);
    midAngle = Math.atan2(centroid[1], centroid[0]);
    y = Math.sin(midAngle) * labelRadius;
    return y;
  },
  'class': "label-line"
});

textLabels.transition().duration(1000).attr({
  x: function(d, i) {
    centroid = arc.centroid(d);
    midAngle = Math.atan2(centroid[1], centroid[0]);
    x = Math.cos(midAngle) * labelRadius;
    sign = (x > 0) ? 1 : -1
    labelX = x + (5 * sign)
    return labelX;
  },
  y: function(d, i) {
    centroid = arc.centroid(d);
    midAngle = Math.atan2(centroid[1], centroid[0]);
    y = Math.sin(midAngle) * labelRadius;
    return y;
  },
  'text-anchor': function(d, i) {
    centroid = arc.centroid(d);
    midAngle = Math.atan2(centroid[1], centroid[0]);
    x = Math.cos(midAngle) * labelRadius;
    return (x > 0) ? "start" : "end";
  },
  'class': 'label-text'
}).text(function(d) {
  return d.data.label
});

工作代码

这使圆/点跟随圆弧的质心:

label_circle = label_circle.data(pie(data));

label_circle
    .transition()
        .duration(750)
        .attrTween("transform", function(d) {
            var interpolate = d3.interpolate(this._current, d);
            this._current = interpolate(0);
            return function(t) {
                return "translate(" + arc.centroid(interpolate(t)) + ")";
            };
        });

酷。现在可以了,但如何平滑地设置动画,使其也跟随弧长动画?不要担心空值或0值。对于转换,请执行
textLines.transition().duration(1000).attr({all attributes changes})
更新了我的答案并相应地插入。这非常接近。看起来标签在直线上转换(新旧位置之间的最短距离)。看起来没那么糟。但出于学习的目的,它如何能在一个圆中移动(即恒定半径)?这将是最好的动画,因为圆弧动画将跟随圆弧动画。哈哈哈,这将是强悍的,但如果你确实找到了,那么请将其发布在这里:)但这里有一些放松技巧,你可能想尝试一下sheck,我添加了圆放松。我想这可能会给我一个提示:。我会继续努力的