2013-11-21 44 views
8

怎样才可以有D3.js根据他们个人的半径/直径自动调节字体大小为每个节点?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)) 

有没有一种方法可以自动格式化节点字体单独;写入适当的大小,所以当放大被调用的节点字体将出现与节点大小成比例,与单一字体大小适合所有?

enter image description here

正确列出圈:NAME(SIZE)
我喜欢工作的例子可以借鉴。因此,在图像大小的情况下,P旁边的驱动圆以北的绿色小点将会有黑色的不可读的单词,直到我们放大以查看圆圈上写的内容为止。目标是放大时具有相称的可读字体..?

回答

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; 
} 
+0

做工精良...有一个简单的解决这个词之前和之后获得的空间或缩小字的大小几步小吗? – Understood

+0

这完全取决于cscale是如何确定的 - 您可以在其中添加一个因子或为bbox.width添加一个常量偏移量作为空间。 –

+0

可能是这个getBBox()在FF上创建的问题! –

1

感谢OP &接受的答案(包括upvoted);我最终做了一点不同,因为我的文本在一个圆圈内偏移了,而不是沿着它的直径向右移动。文本节点具有dy值或圆内来接班了下来,我用它来找出我需要测量圆上有我的文字还是自动调整在希望的高度偏移弦。它也满足了我的需要,将计算的大小存储在文本元素的数据属性中,而不是修改源数据。认为未来任何人都会遇到这种情况可能会有帮助。

jsfiddle

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; 
}