Подтвердить что ты не робот

Добавить эллипсы для переполнения текста в SVG?

Я использую D3.js Я хотел бы найти SVG-эквивалент этого CSS-класса, который добавляет эллипсы, если текст вытекает из содержащего его div:

.ai-ellipsis {
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  -o-text-overflow: ellipsis;
  -moz-binding: url(<q>assets/xml/ellipsis.xml#ellipsis</q>);
}

Это мой SVG:

<g class="bar" transform="translate(0,39)">
    <text class="label" x="-3" y="6.5" dy=".35em" text-anchor="start">Construction</text>    
    <rect height="13" width="123"></rect>
</g>

Он генерируется следующим образом:

barEnter.append("text").attr("class", "label")
        .attr("x", -3).attr("y", function() { return y.rangeBand() / 2})
        .attr("dy", ".35em").attr("text-anchor", "start")
        .text(function(d) {
            return d.Name;
        });

В настоящее время текст переполняется и перекрывает прямоугольный элемент.

Можно ли как-то сказать "если текст больше определенной ширины, обрезать его и добавить эллипсы"?

4b9b3361

Ответ 1

Мне не известно об эквивалентном CSS-классе для SVG, но вы можете использовать foreignObject для встраивания HTML в SVG. Это дает вам доступ к этой функции и является более гибким в целом (например, вы можете легко автоматизировать разбиение строк).

Подробнее см. здесь.

Ответ 2

функция обертки для переполнения текста:

    function wrap() {
        var self = d3.select(this),
            textLength = self.node().getComputedTextLength(),
            text = self.text();
        while (textLength > (width - 2 * padding) && text.length > 0) {
            text = text.slice(0, -1);
            self.text(text + '...');
            textLength = self.node().getComputedTextLength();
        }
    } 

использование:

text.append('tspan').text(function(d) { return d.name; }).each(wrap);

Ответ 3

Я реализовал нативную функцию, которая не зависит от d3, эта функция реализует 3-х сторонние резервные копии:

function textEllipsis(el, text, width) {
  if (typeof el.getSubStringLength !== "undefined") {
    el.textContent = text;
    var len = text.length;
    while (el.getSubStringLength(0, len--) > width) {}
    el.textContent = text.slice(0, len) + "...";
  } else if (typeof el.getComputedTextLength !== "undefined") {
    while (el.getComputedTextLength() > width) {
      text = text.slice(0,-1);
      el.textContent = text + "...";
    }
  } else {
    // the last fallback
    while (el.getBBox().width > width) {
      text = text.slice(0,-1);
      // we need to update the textContent to update the boundary width
      el.textContent = text + "...";
    }
  }
}

Ответ 4

function trimText(text, threshold) {
    if (text.length <= threshold) return text;
    return text.substr(0, threshold).concat("...");
}

Используйте эту функцию для установки текста узла SVG. Значение порога (например, 20) зависит от вас. Это означает, что вы будете отображать до 20 символов из вашего текста узла. Все тексты, содержащие более 20 символов, будут обрезаны, и в конце обрезанного текста будет отображаться "...".

Использование, например. :

var self = this;
nodeText.text(x => self.trimText(x.name, 20)) // nodeText is the text element of the SVG node

Ответ 5

Просто обновление функции обертки, предложенное пользователем2846569. getComputedTextLength() имеет тенденцию быть очень медленным, поэтому...

EDIT

Я старательно применял совет user2846569 и делал версию с "двоичным" поиском с некоторой калибровкой и параметризованной точностью.

'use strict';

var width = 2560;

d3.select('svg').attr('width', width);

// From http://stackoverflow.com/info/10726909/random-alpha-numeric-string-in-javascript
function randomString(length, chars) {
    var result = '';
    for (var i = length; i > 0; --i)
        result += chars[Math.floor(Math.random() * chars.length)];
    return result;
}

function wrap() {
    var self = d3.select(this),
        textWidth = self.node().getComputedTextLength(),    // Width of text in pixel.
        initialText = self.text(),                          // Initial text.
        textLength = initialText.length,                    // Length of text in characters.
        text = initialText,
        precision = 10, //textWidth / width,                // Adjustable precision.
        maxIterations = 100; // width;                      // Set iterations limit.

    while (maxIterations > 0 && text.length > 0 && Math.abs(width - textWidth) > precision) {

        text = /*text.slice(0,-1); =*/(textWidth >= width) ? text.slice(0, -textLength * 0.15) : initialText.slice(0, textLength * 1.15);
        self.text(text + '...');
        textWidth = self.node().getComputedTextLength();
        textLength = text.length;
        maxIterations--;
    }
    console.log(width - textWidth);
}

var g = d3.select('g');

g.append('text').append('tspan').text(function(d) {
    return randomString(width, 'a');
}).each(wrap);

Просмотр в JSFiddle.