如何防止SVG文本流出其圈子?

时间:2018-04-04 02:29:22

标签: javascript d3.js svg

这就是文本现在在圈内显示的方式:

enter image description here

这就是我想在圆圈内显示文字的方式:

enter image description here

我正在寻找切断/隐藏/或?的方法?文本中不适合圆圈的部分,并在这些太长文本的末尾显示三个点。我找到了很多答案,解释了如何将多个单词包装成一个圆圈,但我找不到一种方法可以用这种方式在一个圆圈中插入一个太长的单词。

这些是在输入时添加到圆圈和文本中的样式:

enterNode = (selection) => {
        selection.select('circle')
            .attr("r", 30)
            .style("fill", function (d) {
                return color(d.label)
            })
            .style("stroke", "#4D5061")

        selection.select('text')
            .style("fill", "#3D3B30")
            .style("font-weight", "600")
            .style("text-transform", "uppercase")
            .style("text-anchor", "middle")
            .style("alignment-baseline", "middle")
    }

圆圈是以这种方式显示的d3力布局的一部分

<svg>
  <g class="node-group">
    <g class="node>
      <circle class="circle"></circle>
      <text class="text"></text>
    </g>
  </g>
  <g class="link-group">...</g>
</svg>

如果您对如何解决这个问题有所了解,我会非常感激!

3 个答案:

答案 0 :(得分:2)

这是一个基于D3的SVG元素解决方案,因为你有一个带有D3力导向图的SVG。

它涉及获取圆的宽度(您可以使用attr("r")作为吸气剂,但我在这里使用getBBox())和文本的长度(这里我使用{{1} })并将这些值传递给自定义函数。

首先,让我们看看没有任何功能的圆圈和文字。这是我演示中的文字:

  

最重要的是:你自己是真实的,而且必须遵循,就像白天的夜晚一样,你不能对任何人都是假的。

正如您所看到的,它不仅比圆形更长,它实际上比SVG更大:

getComputedTextLength()
var svg = d3.select("svg");
var circle = svg.append("circle")
  .attr("cx", 200)
  .attr("cy", 110)
  .attr("r", 100)
  .style("fill", "powderblue")
  .style("stroke", "darkslategray");

var text = svg.append("text")
  .style("text-anchor", "middle")
  .style("dominant-baseline", "central")
  .attr("x", 200)
  .attr("y", 110)
  .text("This above all: to thine own self be true, And it must follow, as the night the day, Thou canst not then be false to any man.");
svg {
  border: 1px solid gray;
}

现在让我们调用我们的函数,这里名为<script src="https://d3js.org/d3.v5.min.js"></script> <svg width="400" height="220"></svg>。必须在文本选择上调用它,使用圆选择作为第二个参数,如下所示:

crop()

这就是功能:

text.call(crop, circle);

正如您所看到的,它基本上取值,并在function crop(text, circle) { var circleRadius = circle.node().getBBox().width; while (text.node().getComputedTextLength() > circleRadius) { text.text(text.text().slice(0, -4) + "..."); } }; 循环中裁剪文本(使用while)直到它适合空格。我实际上是在每个循环中再次打印文本,以获得节点的计算长度...但是,那些现代浏览器非常快,以至于人们无法注意到。

以下是演示:

"..."
var svg = d3.select("svg");
var circle = svg.append("circle")
  .attr("cx", 200)
  .attr("cy", 110)
  .attr("r", 100)
  .style("fill", "powderblue")
  .style("stroke", "darkslategray");

var text = svg.append("text")
  .style("text-anchor", "middle")
  .style("dominant-baseline", "central")
  .attr("x", 200)
  .attr("y", 110)
  .text("This above all: to thine own self be true, And it must follow, as the night the day, Thou canst not then be false to any man.");

text.call(crop, circle);

function crop(text, circle) {
  var circleRadius = circle.node().getBBox().width;
  while (text.node().getComputedTextLength() > circleRadius) {
    text.text(text.text().slice(0, -4) + "...");
  }
}
svg {
  border: 1px solid gray;
}

答案 1 :(得分:1)

我想你会想要类似的东西...... 文本受限于它无法在SVG的容器之外绘制的事实,因此您只需将SVG嵌套在SVG中

&#13;
&#13;
<svg width="25%" height="25%" viewBox="0 0 42 42" class="donut">
  <circle class="donut-segment" cx="21" cy="21" r="15.91549430918954" fill="transparent" stroke="#ce4b99" stroke-width="3"></circle>
  <svg width="25%" height="25%" viewBox="0 0 52 52" x="13" y="15.5">
    <g x="0" y="25">
      <text x="0" y="27">TEXasT</text>
    </g>
  <svg>
</svg>
&#13;
&#13;
&#13;

编辑: O.P想要省略号,所以这是新的小提琴。 它使用绝对定位并转换为垂直和水平的内部文本。

&#13;
&#13;
#p {
  height: 250px;
  width: 250px;
  position: relative;
}
#c {
  width: 112px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  position: absolute;
  left: 50%;
  transform: translateX(-50%) translateY(-50%);
  top: 50%;
}
&#13;
<div id="p">
<svg width="100%" height="100%" viewBox="0 0 42 42" class="donut">
  <circle class="donut-segment" cx="21" cy="21" r="15.91549430918954" fill="transparent" stroke="#ce4b99" stroke-width="3"></circle>
    <div id="c">
      BLAHAHAHHAasdsadsadas
    </div>
    </svg>
</div>
&#13;
&#13;
&#13;

答案 2 :(得分:0)

使用className抓取DOM元素,并将innerText更改为您想要的任何内容。然后设置maxWidth。我的函数将该文本添加到DOM中,然后检查DOM元素的长度(其中innerText)是否太大。如果它更小,则不执行任何操作,但如果它更大,则开始在字符串上使用slice并删除尾随字符并添加...。冲洗并重复。

我有setTimeout来展示这两种情况并证明它有效。

确保您使用的css实际上会根据其中的文本更改html元素的宽度,否则它将永远运行并冻结您的浏览器。这就是我使用display: flex

的原因

function reduceWord(className, innerText, maxWidth) {
  let textElement = document.getElementsByClassName(className)[0] //assuming only one html element named that class
  textElement.innerHTML = innerText
  if (textElement.offsetWidth > maxWidth) {
    let nextInnerText
    while (textElement.offsetWidth > maxWidth) {
      nextInnerText = textElement.innerHTML
      textElement.innerHTML = nextInnerText.slice(0, nextInnerText.length - 4) + '...'
    }
  }
}

reduceWord('example', 'Programming', 100)

setTimeout(() => reduceWord('example', 'Programming', 50), 5000)
.container {
display: flex;
}

.example {
border: 1px solid black;
display: flex;
}
<div class="container">
  <div class="example"> </div>
</div>