放大时如何显示全文并在缩小时将其截断

Mat*_*ics 17 javascript css d3.js

我正在使用d3.js创建一个树形图表,它运行正常...但我希望文本对缩放作出反应,这是JSFiddle.

请看第一个节点......它有很多字符(在我的情况下,最大值为255)

放大或缩小时,我的文字保持不变,但我希望看到所有内容都放大.

var json = {
  "name": "Maude Charlotte Licia  Fernandez Maude Charlotte Licia  Fernandez Maude Charlotte Licia  Fernandez Maude Charlotte Licia  FernandezMaude Charlotte Licia  Fernandez Maude Charlotte Licia  Fernandez Maude Charlotte Licia  Fernandez Maude asdlkhkjh asd asdsd",
  "id": "06ada7cd-3078-54bc-bb87-72e9d6f38abf",
  "_parents": [{
    "name": "Janie Clayton Norton",
    "id": "a39bfa73-6617-5e8e-9470-d26b68787e52",
    "_parents": [{
      "name": "Pearl Cannon",
      "id": "fc956046-a5c3-502f-b853-d669804d428f",
      "_parents": [{
        "name": "Augusta Miller",
        "id": "fa5b0c07-9000-5475-a90e-b76af7693a57"
      }, {
        "name": "Clayton Welch",
        "id": "3194517d-1151-502e-a3b6-d1ae8234c647"
      }]
    }, {
      "name": "Nell Morton",
      "id": "06c7b0cb-cd21-53be-81bd-9b088af96904",
      "_parents": [{
        "name": "Lelia Alexa Hernandez",
        "id": "667d2bb6-c26e-5881-9bdc-7ac9805f96c2"
      }, {
        "name": "Randy Welch",
        "id": "104039bb-d353-54a9-a4f2-09fda08b58bb"
      }]
    }]
  }, {
    "name": "Helen Donald Alvarado",
    "id": "522266d2-f01a-5ec0-9977-622e4cb054c0",
    "_parents": [{
      "name": "Gussie Glover",
      "id": "da430aa2-f438-51ed-ae47-2d9f76f8d831",
      "_parents": [{
        "name": "Mina Freeman",
        "id": "d384197e-2e1e-5fb2-987b-d90a5cdc3c15"
      }, {
        "name": "Charlotte Ahelandro Martin",
        "id": "ea01728f-e542-53a6-acd0-6f43805c31a3"
      }]
    }, {
      "name": "Jesus Christ Pierce",
      "id": "bfd1612c-b90d-5975-824c-49ecf62b3d5f",
      "_parents": [{
        "name": "Donald Freeman Cox",
        "id": "4f910be4-b827-50be-b783-6ba3249f6ebc"
      }, {
        "name": "Alex Fernandez Gonzales",
        "id": "efb2396d-478a-5cbc-b168-52e028452f3b"
      }]
    }]
  }]
};

var boxWidth = 250,
  boxHeight = 100;

// Setup zoom and pan
var zoom = d3.behavior.zoom()
  .scaleExtent([.1, 1])
  .on('zoom', function() {
    svg.attr("transform", "translate(" + d3.event.translate + ") scale(" + d3.event.scale + ")");
  })
  // Offset so that first pan and zoom does not jump back to the origin
  .translate([600, 600]);

var svg = d3.select("body").append("svg")
  .attr('width', 1000)
  .attr('height', 500)
  .call(zoom)
  .append('g')
  // Left padding of tree so that the whole root node is on the screen.
  // TODO: find a better way
  .attr("transform", "translate(150,200)");

var tree = d3.layout.tree()
  // Using nodeSize we are able to control
  // the separation between nodes. If we used
  // the size parameter instead then d3 would
  // calculate the separation dynamically to fill
  // the available space.
  .nodeSize([100, 200])
  // By default, cousins are drawn further apart than siblings.
  // By returning the same value in all cases, we draw cousins
  // the same distance apart as siblings.
  .separation(function() {
    return .9;
  })
  // Tell d3 what the child nodes are. Remember, we're drawing
  // a tree so the ancestors are child nodes.
  .children(function(person) {
    return person._parents;
  });

var nodes = tree.nodes(json),
  links = tree.links(nodes);

// Style links (edges)
svg.selectAll("path.link")
  .data(links)
  .enter().append("path")
  .attr("class", "link")
  .attr("d", elbow);

// Style nodes    
var node = svg.selectAll("g.person")
  .data(nodes)
  .enter().append("g")
  .attr("class", "person")
  .attr("transform", function(d) {
    return "translate(" + d.y + "," + d.x + ")";
  });

// Draw the rectangle person boxes
node.append("rect")
  .attr({
    x: -(boxWidth / 2),
    y: -(boxHeight / 2),
    width: boxWidth,
    height: boxHeight
  });

// Draw the person's name and position it inside the box
node.append("text")
  .attr("text-anchor", "start")
  .attr('class', 'name')
  .text(function(d) {
    return d.name;
  });

// Text wrap on all nodes using d3plus. By default there is not any left or
// right padding. To add padding we would need to draw another rectangle,
// inside of the rectangle with the border, that represents the area we would
// like the text to be contained in.
d3.selectAll("text").each(function(d, i) {
  d3plus.textwrap()
    .container(d3.select(this))
    .valign("middle")
    .draw();
});


/**
 * Custom path function that creates straight connecting lines.
 */
function elbow(d) {
  return "M" + d.source.y + "," + d.source.x + "H" + (d.source.y + (d.target.y - d.source.y) / 2) + "V" + d.target.x + "H" + d.target.y;
}
Run Code Online (Sandbox Code Playgroud)
body {
  text-align: center;
}
svg {
  margin-top: 32px;
  border: 1px solid #aaa;
}
.person rect {
  fill: #fff;
  stroke: steelblue;
  stroke-width: 1px;
}
.person {
  font: 14px sans-serif;
}
.link {
  fill: none;
  stroke: #ccc;
  stroke-width: 1.5px;
}
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3plus/1.8.0/d3plus.min.js"></script>
Run Code Online (Sandbox Code Playgroud)

Sen*_*cob 15

我在这个小提琴里做了一个你的要求的样本

可能需要进行一些调整以将文本定位在垂直中间; 但这可以成为您工作的基础.计算在函数中完成,wrap()并在页面加载和缩放时调用.

function wrap() {
  var texts = d3.selectAll("text"),
    lineHeight = 1.1, // ems
    padding = 2, // px
    fSize = scale > 1 ? fontSize / scale : fontSize,
    // find how many lines can be included
    lines = Math.floor((boxHeight - (2 * padding)) / (lineHeight * fSize)) || 1;
  texts.each(function(d, i) {
    var text = d3.select(this),
      words = d.name.split(/\s+/).reverse(),
      word,
      line = [],
      lineNumber = 0,
      tspan = text.text(null).append("tspan").attr("dy", "-0.5em").style("font-size", fSize + "px");
    while ((word = words.pop())) {
      line.push(word);
      tspan.text(line.join(" "));
      // check if the added word can fit in the box
      if ((tspan.node().getComputedTextLength() + (2 * padding)) > boxWidth) {
        // remove current word from line
        line.pop();
        tspan.text(line.join(" "));
        lineNumber++;
        // check if a new line can be placed
        if (lineNumber > lines) {
          // left align text of last line
          tspan.attr("x", (tspan.node().getComputedTextLength() - boxWidth) / 2 + padding);
          --lineNumber;
          break;
        }
        // create new line
        tspan.text(line.join(" "));
        line = [word]; // place the current word in new line
        tspan = text.append("tspan")
          .style("font-size", fSize + "px")
          .attr("dy", "1em")
          .text(word);
      }
      // left align text
      tspan.attr("x", (tspan.node().getComputedTextLength() - boxWidth) / 2 + padding);
    }
    // align vertically inside the box
    text.attr("text-anchor", "middle").attr("y", padding - (lineHeight * fSize * lineNumber) / 2);
  });
}
Run Code Online (Sandbox Code Playgroud)

另请注意,我已将该样式添加dominant-baseline: hanging;.person课堂中

  • 使用wrap函数注意到哪些主要错误?也许我可以帮助解决这些问题. (3认同)

Con*_*Fan 7

此jsfiddle中的代码是尝试解决您在非常大的树形图表中遇到的性能问题.setTimeout在缩放事件处理程序中设置延迟以允许以"全速"缩放,而不调整文本大小.一旦缩放停止一小段时间,文本将根据新的缩放重新排列:

var scaleValue = 1;
var refreshTimeout;
var refreshDelay = 0;

var zoom = d3.behavior.zoom()
    .scaleExtent([.1, 1.5])
    .on('zoom', function () {
        svg.attr("transform", "translate(" + d3.event.translate + ") scale(" + d3.event.scale + ")");
        scaleValue = d3.event.scale;
        if (refreshTimeout) {
            clearTimeout(refreshTimeout);
        }
        refreshTimeout = setTimeout(function () {
            wrapText();
        }, refreshDelay);
    })
Run Code Online (Sandbox Code Playgroud)

延迟(以毫秒为单位)取决于树中的节点数.您可以尝试使用数学表达式来查找树中所需的各种节点计数的最佳参数.

// Calculate the refresh delay
refreshDelay = Math.pow(node.size(), 0.5) * 2.0;
Run Code Online (Sandbox Code Playgroud)

您还可以设置参数calcFontSize以满足您的需求:

// Calculate the font size for the current scaling
var calcFontSize = function () {
    return Math.min(24, 10 * Math.pow(scaleValue, -0.25))
}
Run Code Online (Sandbox Code Playgroud)

节点的初始化略有修改:

node.append("rect")
    .attr({
        x: 0,
        y: -(boxHeight / 2),
        width: boxWidth,
        height: boxHeight
    });

node.append("text")
    .attr("text-anchor", "start")
    .attr("dominant-baseline", "middle")
    .attr('class', 'name')
    .text(function (d) {
        return d.name;
    });
Run Code Online (Sandbox Code Playgroud)

并且文本处理在wrapText:

// Adjust the font size to the zoom level and wrap the text in the container
var wrapText = function () {
    d3.selectAll("text").each(function (d, i) {
        var $text = d3.select(this);
        if (!$text.attr("data-original-text")) {
            // Save original text in custom attribute
            $text.attr("data-original-text", $text.text());
        }
        var content = $text.attr("data-original-text");
        var tokens = content.split(/(\s)/g);
        var strCurrent = "";
        var strToken = "";
        var box;
        var lineHeight;
        var padding = 4;
        $text.text("").attr("font-size", calcFontSize());
        var $tspan = $text.append("tspan").attr("x", padding).attr("dy", 0);
        while (tokens.length > 0) {
            strToken = tokens.shift();
            $tspan.text((strCurrent + strToken).trim());
            box = $text.node().getBBox();
            if (!lineHeight) {
                lineHeight = box.height;
            }
            if (box.width > boxWidth - 2 * padding) {
                $tspan.text(strCurrent.trim());
                if (box.height + lineHeight < boxHeight) {
                    strCurrent = strToken;
                    $tspan = $text.append("tspan").attr("x", padding).attr("dy", lineHeight).text(strCurrent.trim());
                } else {
                    break;
                }
            }
            else {
                strCurrent += strToken;
            }
        }
        $text.attr("y", -(box.height - lineHeight) / 2);
    });
}
Run Code Online (Sandbox Code Playgroud)