Обрезка текста до заданной ширины пикселя в SVG - PullRequest
22 голосов
/ 11 февраля 2012

Я рисую текстовые метки в SVG. У меня есть фиксированная ширина (скажем, 200 пикселей). Когда текст слишком длинный, как я могу его обрезать?

Идеальное решение также добавило бы многоточие (...), где текст обрезается. Но я тоже могу жить без него.

Ответы [ 7 ]

26 голосов
/ 12 февраля 2012

Один из способов сделать это - использовать элемент textPath , поскольку все символы, которые выпадают из пути, будут автоматически вырезаны.См. Text-path examples из комплекта тестов SVG.

Другой способ - использовать CSS3 text-overflow для текстовых элементов SVG, пример здесь .Opera 11 поддерживает это, но вы, вероятно, обнаружите, что другие браузеры в настоящее время поддерживают его только для html-элементов.

Вы также можете измерить текстовые строки и вставить многоточие самостоятельно со скриптом, я бы предложилиспользуя метод getSubStringLength для текстового элемента, увеличивая параметр nchars до тех пор, пока вы не найдете подходящую длину.

21 голосов
/ 31 декабря 2014

Использование библиотеки d3

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

    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);
17 голосов
/ 09 июня 2014

Реализуя 3-е предложение Эрика, я придумал что-то вроде этого:

//places textString in textObj, adds an ellipsis if text can't fit in width
function placeTextWithEllipsis(textObj,textString,width){
    textObj.textContent=textString;

    //ellipsis is needed
    if (textObj.getSubStringLength(0,textString.length)>=width){
        for (var x=textString.length-3;x>0;x-=3){
            if (textObj.getSubStringLength(0,x)<=width){
                textObj.textContent=textString.substring(0,x)+"...";
                return;
            }
        }
        textObj.textContent="..."; //can't place at all
    }
}

Кажется, чтобы сделать трюк:)

4 голосов
/ 21 августа 2015

@ user2846569 покажи мне, как это сделать (да, используя d3.js).Но я должен внести небольшие изменения, чтобы работать:


         function wrap( d ) {
                var self = d3.select(this),
                    textLength = self.node().getComputedTextLength(),
                    text = self.text();
                while ( ( textLength > self.attr('width') )&& text.length > 0) {
                    text = text.slice(0, -1);
                    self.text(text + '...');
                    textLength = self.node().getComputedTextLength();
                }
            }
            svg.append('text')
                .append('tspan')
                .text(function(d) { return d; }) 
                .attr('width', 200 )
                .each( wrap );
1 голос
/ 16 мая 2016

Попробуйте, я использую эту функцию в своей библиотеке графиков:

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 + "...";
    }
  }
}
0 голосов
/ 12 апреля 2018

Элемент linearGradient может использоваться для получения чистого решения SVG. Этот пример затеняет усеченный текст (без многоточия):

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
  <defs>
    <linearGradient gradientUnits="userSpaceOnUse" x1="0" x2="200" y1="0" y2="0" id="truncateText">
      <stop offset="90%" stop-opacity="1" />
      <stop offset="100%" stop-opacity="0" />
    </linearGradient>
    <linearGradient id="truncateLegendText0" gradientTransform="translate(0)" xlink:href="#truncateText" />
    <linearGradient id="truncateLegendText1" gradientTransform="translate(200)" xlink:href="#truncateText" />
  </defs>

  <text fill="url(#truncateLegendText0)" font-size="50" x="0" y="50">0123456789</text>
  <text fill="url(#truncateLegendText1)" font-size="50" x="200" y="150">0123456789</text>
  
</svg>

(Мне пришлось использовать линейные градиенты для решения этой проблемы, поскольку используемый мной рендерер SVG не поддерживает решение textPath.)

0 голосов
/ 18 мая 2016

Мой подход был похож на OpherV, но я попытался сделать это с помощью JQuery

function getWidthOfText(text, fontSize, fontFamily) {
    var span = $('<span></span>');
    span.css({
       'font-family': fontFamily,
        'font-size' : fontSize
    }).text(text);
    $('body').append(span);
    var w = span.width();
    span.remove();
    return w;
}

function getStringForSize(text, desiredSize, fontSize, fontFamily) {
    var curSize = getWidthOfText(text, fontSize, fontFamily);
    if(curSize > size)
    {
        var curText = text.substring(0,text.length-5) + '...';
        return getStringForSize(curText, size, fontSize, fontFamily);
    }
    else
    {
        return text;
    }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Теперь при звонке getStringForSize('asdfasdfasdfasdfasdfasdf', 110, '13px','OpenSans-Light') вы получите "asdfasdfasdfasd ..."

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...