我有一个简单的饼图,标签如下:
var data = [{
label: 'Star Wars',
instances: 20
}, {
label: 'Lost In Space',
instances: 32
}, {
label: 'the Boston Pops',
instances: 80
}, {
label: 'Indiana Jones',
instances: 74
}, {
label: 'Harry Potter',
instances: 23
}, {
label: 'Jaws',
instances: 10
}, {
label: 'Lincoln',
instances: 15
}];
svg = d3.select("svg");
canvas = d3.select("#canvas");
art = d3.select("#art");
labels = d3.select("#labels");
var pie = d3.layout.pie().value(function(d, i) {
return d.instances;
})
.sort(null);
var height = 500,
width = 500,
labelRadius = 175;
svg.attr({
height: height,
width: width
});
canvas.attr("transform", "translate(" + (width / 2) + "," + (height / 2) + ")");
arc = d3.svg.arc()
.innerRadius(50)
.outerRadius(150);
colors = d3.scale.category10();
var path = art.selectAll(".wedge").data(pie(data)).enter().append("path")
.attr("class", "wedge")
.attr("d", arc)
.style("fill", function(d, i) {
return colors(i);
})
.each(function(d) {
this._current = d;
});
enteringLabels = labels.selectAll(".label").data(pie(data)).enter();
labelGroups = enteringLabels.append("g").attr("class", "label");
labelGroups.append("circle").attr({
x: 0,
y: 0,
r: 2,
fill: "#000",
transform: function(d, i) {
centroid = arc.centroid(d);
return "translate(" + arc.centroid(d) + ")";
},
'class': "label-circle"
});
textLines = labelGroups.append("line").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 = labelGroups.append("text").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
});
alpha = 0.5;
spacing = 12;
function relax() {
again = false;
textLabels.each(function(d, i) {
a = this;
da = d3.select(a);
y1 = da.attr("y");
textLabels.each(function(d, j) {
b = this;
// a & b are the same element and don't collide.
if (a == b) return;
db = d3.select(b);
// a & b are on opposite sides of the chart and
// don't collide
if (da.attr("text-anchor") != db.attr("text-anchor")) return;
// Now let's calculate the distance between
// these elements.
y2 = db.attr("y");
deltaY = y1 - y2;
// Our spacing is greater than our specified spacing,
// so they don't collide.
if (Math.abs(deltaY) > spacing) return;
// If the labels collide, we'll push each
// of the two labels up and down a little bit.
again = true;
sign = deltaY > 0 ? 1 : -1;
adjust = sign * alpha;
da.attr("y", +y1 + adjust);
db.attr("y", +y2 - adjust);
});
});
// Adjust our line leaders here
// so that they follow the labels.
if (again) {
labelElements = textLabels[0];
textLines.attr("y2", function(d, i) {
labelForLine = d3.select(labelElements[i]);
return labelForLine.attr("y");
});
setTimeout(relax, 20)
}
}
relax();
d3.selectAll("#randomize")
.on("click", function() {
data = _(data).map(function(v) {
v.instances = Math.floor((Math.random() * 100) + 1);
return v;
});
pie.value(function(d) {
return d.instances;
});
path = path
.data(pie(data));
path.transition().duration(750)
.attrTween("d", function(d) {
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
return arc(interpolate(t));
};
});
});

.label-text {
alignment-baseline: middle;
font-size: 12px;
font-family: arial, helvetica, "sans-serif";
fill: #393939;
}
.label-line {
stroke-width: 1;
stroke: #393939;
}
.label-circle {
fill: #393939;
}
#randomize {
position: absolute;
padding: 10px;
z-index: 100;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore.js"></script>
<button id="randomize">Randomize</button>
<svg>
<g id="canvas">
<g id="art" />
<g id="labels" /></g>
</svg>
&#13;
我可以更新/随机化数据以使弧长动画,但我不知道如何制作标签&#34;关注&#34;弧的质心。我知道我可能需要沿着圆弧的质心/路径插入标签,但我似乎无法弄清楚如何开始。
答案 0 :(得分:2)
在click
函数内部,您需要重置绑定到各种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
});
工作代码here
答案 1 :(得分:0)
这使得圆/点跟随弧的质心:
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)) + ")";
};
});