admin管理员组文章数量:1193565
How can I have D3.js automatically adjust font-size for each node based on their individual radius/diameter?
I use a style that allows automatic increase 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"; })
This effect removes the text from the smaller nodes. I also have a zoom function that I can increase a dot that originally cover 12 px to cover my entire screen.
.call(d3.behavior.zoom().scaleExtent([1, 200]).on("zoom", zoom))
Is there a way I can automatically format node-font individually; to write at appropriate sizes so when zoom-in the called node-font will appear proportionate to node-size vs a single font-size fits all?
The Right Lists Circles: NAME(SIZE)
I would love a working examples to learn from. So at the image size the little green dot north of driving circle next to the P would have black unreadable words until we zoom in to see what is written on the circle. The goal is to have proportionate readable font when zoomed in..?
How can I have D3.js automatically adjust font-size for each node based on their individual radius/diameter?
I use a style that allows automatic increase 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"; })
This effect removes the text from the smaller nodes. I also have a zoom function that I can increase a dot that originally cover 12 px to cover my entire screen.
.call(d3.behavior.zoom().scaleExtent([1, 200]).on("zoom", zoom))
Is there a way I can automatically format node-font individually; to write at appropriate sizes so when zoom-in the called node-font will appear proportionate to node-size vs a single font-size fits all?
The Right Lists Circles: NAME(SIZE)
I would love a working examples to learn from. So at the image size the little green dot north of driving circle next to the P would have black unreadable words until we zoom in to see what is written on the circle. The goal is to have proportionate readable font when zoomed in..?
3 Answers
Reset to default 21You can do this by dynamically setting the text size based on the size of the container. For this, you have to add the text, get its bounding box, get the bounding box of the container element and derive the correct font size based on the current font size and those bounding boxes.
The code would look something like this.
// ...
.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;
}
To offset text within a circle, rather than running along the diameter, I implement this differently:
dy
shifts a text node up or down within the circle and is used to calculate the width or the chord to size the text.
The scale is then stored in a data attribute on the text element, rather than modifying the source data.
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);
// in other cases could be parentElement or nextElementSibling
var circ = d3.select(this.previousElementSibling);
var radius = Number(circ.attr("r"));
var offset = Number(d3text.attr("dy"));
// TODO: this could be bounding box instead
var textWidth = this.getComputedTextLength();
// TODO: could adjust based on ratio of dy to radius
var availWidth = chordWidth(Math.abs(offset), radius);
// fixed 15% 'padding', could be more dynamic/precise based on above TODOs
availWidth = availWidth * 0.85;
d3text.attr("data-scale", availWidth / textWidth);
}
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;
}
Alternatively, you can create text label embedded with each node as follows:
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";
})
本文标签: javascriptD3js Auto fontsizing based on nodes individual radiusdiameterStack Overflow
版权声明:本文标题:javascript - D3.js Auto font-sizing based on nodes individual radiusdiameter - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1738451496a2087510.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论