D3.js自动字体大小调整根据节点各自的半径/直径

13

如何使D3.js根据每个节点的半径/直径自动调整字体大小?

我使用一种样式,可以自动增加大小。

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

此效果会从较小的节点中删除文本。我还有一个缩放功能,可以将原始覆盖12像素的点增加到整个屏幕大小。

; * 10 + "px"; })


此代码片段与上下文无关,无法进行翻译或说明。
.call(d3.behavior.zoom().scaleExtent([1, 200]).on("zoom", zoom))

有没有一种方法可以自动地个别格式化节点字体;根据适当的大小编写,以便在缩放时,所调用的节点字体与节点大小成比例显示,而不是一个字体大小适合所有?

输入图像描述

正确列表圆圈:名称(大小)
我希望有可行的示例供我学习。因此,在图像大小下,驾驶圆圈北侧的小绿点旁边的P将有黑色不可读的单词,直到我们放大以查看圆圈上写了什么为止。目标是在缩放时具有成比例的可读字体..?

3个回答

20

您可以通过根据容器的大小动态设置文本大小来实现此操作。为此,您需要添加文本,获取其边界框,获取容器元素的边界框,并根据当前字体大小和这些边界框推导出正确的字体大小。

代码看起来会像这样。

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

非常出色...是否有一个简单的解决方案来在单词OR之前和之后获得空格,或者将单词大小缩小几个步骤? - Understood
这完全取决于如何确定 cscale -- 你可以在那里添加一个因子或者为空格添加一个常量偏移量到 bbox.width - Lars Kotthoff

2
为了让文本在圆内偏移,而不是沿着直径运行,我采用了不同的方法实现: 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);

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接