如何让D3.js根据各自的半径/直径自动调整每个节点的字体大小?
我使用的风格允许自动增加insize
node.append("text")
.attr("dy", ".3em")
.style("text-anchor", "middle")
.text(function(d) { return d.className.substring(0, d.r / 3); })
.style("font-size", "10px") // initial guess
//This is what gives it increased size...
.style("font-size", function(d) { return (2 * d.r - 10) / this.getComputedTextLength() * 10 + "px"; })
* 10 +“px”; })
此效果将从较小的节点中删除文本。我还有一个缩放功能,我可以增加一个最初覆盖12像素的点来覆盖我的整个屏幕。
.call(d3.behavior.zoom().scaleExtent([1, 200]).on("zoom", zoom))
有没有办法可以自动格式化节点字体; 以适当的大小编写,这样当放大被调节点字体时,节点大小与单个字体成比例 - 尺寸适合所有?
正确的名单圈子:名称(大小)
我想要一个可以学习的实例。因此,在图像尺寸处,P旁边的驱动圆圈以北的小绿点将具有黑色不可读的单词,直到我们放大以查看圆上写入的内容。目标是在放大时具有相应的可读字体。?
答案 0 :(得分:13)
您可以通过根据容器的大小动态设置文本大小来执行此操作。为此,您必须添加文本,获取其边界框,获取容器元素的边界框,并根据当前字体大小和那些边界框导出正确的字体大小。
代码看起来像这样。
// ...
.append("text")
.text("text")
.style("font-size", "1px")
.each(getSize)
.style("font-size", function(d) { return d.scale + "px"; });
function getSize(d) {
var bbox = this.getBBox(),
cbbox = this.parentNode.getBBox(),
scale = Math.min(cbbox.width/bbox.width, cbbox.height/bbox.height);
d.scale = scale;
}
答案 1 :(得分:1)
感谢OP&接受的答案(均为upvoted);我最后做的有点不同,因为我的文字在一个圆圈内偏移,而不是沿着它的直径向右移动。文本节点有一个dy
值可以在圆圈内向上或向下移动,我用它来计算我需要在圆上测量的和弦,让我的文本仍然自动适合所需的高度偏移。它还更好地满足了我的需求,将计算出的大小存储在文本元素的数据属性中,而不是修改源数据。认为这可能对将来偶然遇到这种情况的人有所帮助。
function appendScaledText(parentGroup, textVal, dyShift) {
parentGroup
.append("text")
.attr("dy", dyShift)
.attr("text-anchor", "middle")
.attr("dominant-baseline", "central")
.attr("font-family", "sans-serif")
.attr("fill", "white")
.text(textVal)
.style("font-size", "1px")
.each(getSize)
.style("font-size", function() {
return d3.select(this).attr("data-scale") + "px";
});
}
function getSize() {
var d3text = d3.select(this);
var circ = d3.select(this.previousElementSibling); // in other cases could be parentElement or nextElementSibling
var radius = Number(circ.attr("r"));
var offset = Number(d3text.attr("dy"));
var textWidth = this.getComputedTextLength(); // TODO: this could be bounding box instead
var availWidth = chordWidth(Math.abs(offset), radius); // TODO: could adjust based on ratio of dy to radius
availWidth = availWidth * 0.85; // fixed 15% 'padding' for now, could be more dynamic/precise based on above TODOs
d3text.attr("data-scale", availWidth / textWidth); // sets the data attribute, which is read in the next step
}
function chordWidth(dFromCenter, radius) {
if (dFromCenter > radius) return Number.NaN;
if (dFromCenter === radius) return 0;
if (dFromCenter === 0) return radius * 2;
// a^2 + b^2 = c^2
var a = dFromCenter;
var c = radius;
var b = Math.sqrt(Math.pow(c, 2) - Math.pow(a, 2)); // 1/2 of chord length
return b * 2;
}
答案 2 :(得分:0)
或者,您可以创建嵌入每个节点的文本标签,如下所示:
this.g.append("g")
.attr("class", "labels")
.selectAll(".mytext")
.data(NODE_DATA)
.enter()
.append("text")
.text(function (d) {
return d.LabelText; // Here label text is the text that you want to show in the node
})
.style("font-size", "1px")
.attr("dy", ".35em") // You can adjust it
.each(function (d) {
var r = Number(d.Size), a = this.getComputedTextLength(),
c=0.35, // Same as dy attribute value
b = 2*Math.sqrt(r*r-c*c), s = Math.min(r, b/a);
d.fs = s;
})
.style("font-size", function (d) {
return d.fs + "px";
})