【发布时间】:2021-05-06 09:36:06
【问题描述】:
我正在尝试弄清楚如何将文本放入圆弧内并自动调整标签的字体大小以适应圆弧,以免发生文本溢出。
我正在使用 D3.js 创建一个形状,然后尝试将文本放在圆弧上并调整我的值,我将文本放入甜甜圈形状中。
问题是文本没有从适当的位置开始,我也希望文本集中。
以下是我一直在使用的代码和当前输出:
function wrap(text, width) {
let lineNumbers = 1;
text.each(function () {
let text = d3.select(this),
line = [],
lineNumbers = 1,
lineNumber = 0,
words = text.text().split(/\s+/).reverse();
words2 = text.text().split(/\s+/).reverse();
console.log("text", text);
while ((word = words.pop())) {
line.push(word);
current_line = line.join(" ");
console.log("current_line", current_line.length);
if (current_line.length > width) {
line.pop();
current_line = line.join(" ");
line = [word];
lineNumbers += 1;
}
}
console.log("lineNumbers", lineNumbers);
append_line = [];
(lineHeight = 1), // ems
(x = text.attr("x")),
(y = text.attr("y")),
(dy = 1), //parseFloat(text.attr("dy")),
(tspan = text
.text(null)
.append("tspan")
.attr("x", x)
.attr("y", y)
.attr("dy", dy + "em"));
while ((word = words2.pop())) {
line = 0;
append_line.push(word);
tspan.text(append_line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
append_line.pop();
line = 1;
tspan.text(append_line.join(" "));
append_line = [word];
if (line == 0) {
tspan = text
.append("tspan")
.attr("x", x)
.attr("y", y)
.attr("dy", ++lineNumber * lineHeight + dy + "em")
.attr("dx", -9 + "em")
.text(word);
}
if (line == 1) {
tspan = text
.append("tspan")
.attr("x", x)
.attr("y", y)
.attr("dy", ++lineNumber * lineHeight + dy + "em")
.attr("dx", -10 + "em")
.text(word);
}
}
}
});
}
let screenWidth = window.innerWidth;
let margin = { left: 20, top: 20, right: 20, bottom: 20 },
width = Math.min(screenWidth, 500) - margin.left - margin.right,
height = Math.min(screenWidth, 500) - margin.top - margin.bottom;
let svg = d3
.select("#chart")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("class", "wrapper")
.attr(
"transform",
"translate(" +
(width / 2 + margin.left) +
"," +
(height / 2 + margin.top) +
")"
);
//////////////////////////////////////////////////////////////
///////////////////// Data & Scales /////////////////////////
//////////////////////////////////////////////////////////////
//Some random data
let donutData = [
{ name: "Antelope sjvadknk saoindosa savasa slahslas sasas", value: 15 },
{ name: "Bear fhfxhxfhxgxhg hgxhx", value: 9 },
{ name: "Cheetah", value: 19 },
{ name: "Dolphin", value: 12 },
{ name: "Elephant", value: 14 },
{ name: "Flamingo", value: 21 },
{ name: "Giraffe", value: 18 },
{ name: "Other", value: 8 },
];
//Create a color scale
let colorScale = d3.scale
.linear()
.domain([1, 3.5, 6])
.range(["#2c7bb6", "#ffffbf", "#d7191c"])
.interpolate(d3.interpolateHcl);
//Create an arc function
let arc = d3.svg
.arc()
.innerRadius((width * 0.75) / 2)
.outerRadius((width * 0.75) / 2 + 30);
//Turn the pie chart 90 degrees counter clockwise, so it starts at the left
let pie = d3.layout
.pie()
.startAngle((-90 * Math.PI) / 180)
.endAngle((-90 * Math.PI) / 180 + 2 * Math.PI)
.value(function (d) {
return d.value;
})
.padAngle(0.01)
.sort(null);
//////////////////////////////////////////////////////////////
//////////////////// Create Donut Chart //////////////////////
//////////////////////////////////////////////////////////////
//Create the donut slices and also the invisible arcs for the text
svg
.selectAll(".donutArcs")
.data(pie(donutData))
.enter()
.append("path")
.attr("class", "donutArcs")
.attr("d", arc)
.style("fill", function (d, i) {
if (i === 7) return "#CCCCCC";
//Other
else return colorScale(i);
})
.each(function (d, i) {
//Search pattern for everything between the start and the first capital L
let firstArcSection = /(^.+?)L/;
//Grab everything up to the first Line statement
let newArc = firstArcSection.exec(d3.select(this).attr("d"))[1];
//Replace all the comma's so that IE can handle it
newArc = newArc.replace(/,/g, " ");
//If the end angle lies beyond a quarter of a circle (90 degrees or pi/2)
//flip the end and start position
if (d.endAngle > (90 * Math.PI) / 180) {
let startLoc = /M(.*?)A/, //Everything between the first capital M and first capital A
middleLoc = /A(.*?)0 0 1/, //Everything between the first capital A and 0 0 1
endLoc = /0 0 1 (.*?)$/; //Everything between the first 0 0 1 and the end of the string (denoted by $)
//Flip the direction of the arc by switching the start en end point (and sweep flag)
//of those elements that are below the horizontal line
let newStart = endLoc.exec(newArc)[1];
let newEnd = startLoc.exec(newArc)[1];
let middleSec = middleLoc.exec(newArc)[1];
//Build up the new arc notation, set the sweep-flag to 0
newArc = "M" + newStart + "A" + middleSec + "0 0 0 " + newEnd;
} //if
//Create a new invisible arc that the text can flow along
svg
.append("path")
.attr("class", "hiddenDonutArcs")
.attr("id", "donutArc" + i)
.attr("d", newArc)
.style("fill", "none");
});
//Append the label names on the outside
svg
.selectAll(".donutText")
.data(pie(donutData))
.enter()
.append("text")
.attr("class", "donutText")
//Move the labels below the arcs for those slices with an end angle greater than 90 degrees
.attr("dy", 20)
.append("textPath")
.attr("startOffset", "50%")
.style("text-anchor", "middle")
.attr("xlink:href", function (d, i) {
return "#donutArc" + i;
})
.attr("font-size", function (d, i) {
return 10;
})
.text(function (d) {
return d.data.name;
})
.call(wrap, 100);
任何帮助都会非常好,提前感谢:)
【问题讨论】:
-
有些文本在弧内,有些在弧外?是故意的吗?
-
目前实际上是有意为之,但所有内容都可以在拱门内移动,如果发生文本溢出,则应为多行
标签: javascript html css d3.js