D3.js Auto font-sizing based on nodes individual radius/diameter

后端 未结 3 517
猫巷女王i
猫巷女王i 2020-12-16 00:24

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 inc

3条回答
  •  囚心锁ツ
    2020-12-16 01:05

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

提交回复
热议问题