我正在尝试包装宽度大于10px的标签。为此,我使用了Bostock的wrap function:
我在我的代码中使用了wrap
函数,并通过传递标签来调用它,例如“titanic eva mission impossible”。但是,标签彼此重叠,而不是每个单词以分开的行分开。
我的项目在这里:StreamGraph With AreaLabel
<!doctype html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.8/d3.min.js" type="text/JavaScript"></script>
<script src="https://unpkg.com/d3-area-label@1.2.0"></script>
<style>
body {
margin: 0px;
}
.area-label {
font-family: sans-serif;
height: 20;
width: auto;
fill-opacity: 0.7;
fill: white;
}
path:hover {
fill-opacity: 1;
fill:black;
}
path {
fill-opacity: 0.8;
stroke-width: 0.5;
}
text {
pointer-events: none;
}
</style>
</head>
<body>
<div id="viz">
<svg style="width:960px;height:500px;" ></svg>
</div>
<script>
d3.csv("movies.csv", dataViz);
function dataViz(data)
{
var xScale = d3.scaleLinear().domain([0, 10]).range([0, 960]);
var yScale = d3.scaleLinear().domain([0, 100]).range([500, 0]);
var movies = ["titanic eva mission impossible", "avatar", "akira", "frozen", "deliverance", "avengers"];
var fillScale = d3.scaleOrdinal().domain(movies)
.range(["#fcd88a", "#cf7c1c", "#93c464", "#75734F", "#5eafc6", "#41a368"]);
stacked = d3.stack()
.offset(d3.stackOffsetSilhouette)
.order(d3.stackOrderInsideOut)
.keys(movies);
yScale.domain([-50, 50]);
var xValue = function (d) { return d.day; };
var stackArea = d3.area()
.x(d => xScale(xValue(d.data)))
.y0(d => yScale(d[0]))
.y1(d => yScale(d[1]))
.curve(d3.curveBasis);
d3.select("svg")
.selectAll("path").data(stacked(data)).enter().append("path")
.style("fill", d => fillScale(d.key))
.attr("d", d => stackArea(d));
labels = d3.select("svg")
.selectAll('text').data(stacked(data))
labels
.enter().append("g")
.append('text')
.attr('class', 'area-label')
.text(d => d.key)
.attr('transform',
d3.areaLabel(stackArea).interpolateResolution(1000).interpolate(true));
d3.select("svg").select("g").select("text").call(wrap,10);
}
function wrap(text, width)
{
text.each(function() {
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr("y"),
dy = parseFloat(text.attr("dy")),
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
while (word = words.pop()) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
}
}
});
}
</script>
答案 0 :(得分:0)
只需设置y
和dy
属性:
labels.enter().append("g")
.append('text')
.attr("y", 0)
.attr("dy", 0)
//etc...
这是您更新的代码:
var movies = `day,titanic eva mission impossible,avatar,akira,frozen,deliverance,avengers
1,40,8,10,0,0,0
2,18,5,1,13,0,0
3,14,3,1,10,0,0
4,7,3,0,5,27,15
5,4,3,0,2,20,14
6,3,1,0,0,10,13
7,2,0,0,0,8,12
8,0,0,0,0,6,11
9,0,0,0,0,3,9
10,0,0,0,0,1,8`;
var data = d3.csvParse(movies);
dataViz(data);
function dataViz(data) {
var xScale = d3.scaleLinear().domain([0, 10]).range([0, 960]);
var yScale = d3.scaleLinear().domain([0, 100]).range([500, 0]);
var movies = ["titanic eva mission impossible", "avatar", "akira", "frozen", "deliverance", "avengers"];
var fillScale = d3.scaleOrdinal().domain(movies)
.range(["#fcd88a", "#cf7c1c", "#93c464", "#75734F", "#5eafc6", "#41a368"]);
stacked = d3.stack()
.offset(d3.stackOffsetSilhouette)
.order(d3.stackOrderInsideOut)
.keys(movies);
yScale.domain([-50, 50]);
var xValue = function(d) {
return d.day;
};
var stackArea = d3.area()
.x(d => xScale(xValue(d.data)))
.y0(d => yScale(d[0]))
.y1(d => yScale(d[1]))
.curve(d3.curveBasis);
d3.select("svg")
.selectAll("path").data(stacked(data)).enter().append("path")
.style("fill", d => fillScale(d.key))
.attr("d", d => stackArea(d));
labels = d3.select("svg")
.selectAll('text').data(stacked(data))
labels.enter().append("g")
.append('text')
.attr("y", 0)
.attr("dy", 0)
.attr('class', 'area-label')
.text(d => d.key)
.attr('transform', d3.areaLabel(stackArea).interpolateResolution(1000).interpolate(true));
d3.select("svg").select("g").select("text").call(wrap, 10);
}
function wrap(text, width) {
text.each(function() {
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr("y"),
dy = parseFloat(text.attr("dy")),
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
while (word = words.pop()) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
}
}
});
}
&#13;
body {
margin: 0px;
}
.area-label {
font-family: sans-serif;
height: 20;
width: auto;
fill-opacity: 0.7;
fill: white;
}
path:hover {
fill-opacity: 1;
fill: black;
}
path {
fill-opacity: 0.8;
stroke-width: 0.5;
}
text {
pointer-events: none;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.8/d3.min.js" type="text/JavaScript"></script>
<script src="https://unpkg.com/d3-area-label@1.2.0"></script>
<div id="viz">
<svg style="width:960px;height:500px;"></svg>
</div>
&#13;
PS:d3-area-label将文本定位在路径的垂直中心。但是,您必须将其向上移动一点,以避免文本与下面的路径重叠。