Как разместить и отцентрировать текст в прямоугольнике SVG - PullRequest
106 голосов
/ 05 апреля 2011

У меня есть следующий прямоугольник ...

<rect x="0px" y="0px" width="60px" height="20px"/>

Я бы хотел сосредоточить слово "Беллетристика" внутри него.Для других прямоугольников svg word wrap остается в них?Кажется, я не могу найти что-то конкретное о вставке текста в фигуры, которые центрированы как по горизонтали, так и по вертикали, и перенос слов.Кроме того, текст не может покинуть прямоугольник.

Просмотр примера http://www.w3.org/TR/SVG/text.html#TextElement не помогает, поскольку x и y текстового элемента отличаются от x и y прямоугольника.Кажется, нет ширины и высоты для текстовых элементов.Я не уверен в математике здесь.

(Моя HTML-таблица просто не будет работать.)

Ответы [ 10 ]

181 голосов
/ 20 июля 2015

Простое решение для центрирования текста по горизонтали и вертикали в SVG:

  1. Установите положение текста в абсолютный центр элемента, в котором вы хотите центрировать его:

    • Если это родитель, вы можете просто сделать x="50%" y ="50%".
    • Если это другой элемент, x будет x этого элемента + половина его ширины (и аналогично для y, но с высотой).
  2. Используйте свойство text-anchor, чтобы центрировать текст по горизонтали со значением middle:

    средний

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

  3. Используйте свойство dominant-baseline для центрирования текста по вертикали со значением middle (или в зависимости от того, как вы хотите, чтобы он выглядел, вы можете захотеть сделать central)

Вот простая демонстрация:

<svg width="200" height="100">
  <rect x="0" y="0" width="200" height="100" stroke="red" stroke-width="3px" fill="white"/>
  <text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle">TEXT</text>    
</svg>
37 голосов
/ 05 апреля 2011

SVG 1.2. Крошечное добавление переноса текста, но большинство реализаций SVG, которые вы найдете в браузере (за исключением Opera), не реализовали эту функцию.Как правило, вам, разработчику, нужно размещать текст вручную.

Спецификация SVG 1.1 дает хороший обзор этого ограничения и возможных решений для его преодоления:

Каждый элемент 'text' приводит к отображению одной строки текста.SVG не выполняет автоматического разрыва строки или переноса слов.Чтобы добиться эффекта нескольких строк текста, используйте один из следующих методов:

  • Авторский или авторский пакет должен предварительно рассчитать разрывы строк и использовать несколько текстовых элементов (по одному для каждогострока текста).
  • Авторский или авторский пакет должен предварительно вычислить разрывы строк и использовать один элемент 'text' с одним или несколькими дочерними элементами 'tspan' с соответствующими значениями для атрибутов 'x', 'y', 'dx 'и' dy ', чтобы установить новые стартовые позиции для тех персонажей, которые начинают новые строки.(Этот подход позволяет пользователю выбирать текст из нескольких строк текста - см. Выбор текста и операции с буфером обмена.)
  • Выражение текста, который будет отображаться в другом пространстве имен XML, таком как XHTML [XHTML], встроенное в строку в ForeignObject.элемент.(Примечание: точная семантика этого подхода не полностью определена в настоящее время.)

http://www.w3.org/TR/SVG11/text.html#Introduction

В качестве примитива, перенос текста может быть смоделирован с использованиематрибут dy и элементы tspan, и, как уже упоминалось в спецификации, некоторые инструменты могут автоматизировать это.Например, в Inkscape выберите нужную фигуру и текст, который вам нужен, и используйте «Текст» -> «Переместить в рамку».Это позволит вам написать текст с переносом, который будет переноситься на основе границ фигуры.Кроме того, обязательно следуйте этим инструкциям, чтобы сообщить Inkscape о совместимости с SVG 1.1: http://wiki.inkscape.org/wiki/index.php/FAQ#What_about_flowed_text.3F

Кроме того, существует несколько библиотек JavaScript, которые можно использовать для динамической автоматизации переноса текста: http://www.carto.net/papers/svg/textFlow/

Интересно отметить решение CSVG для обтекания фигуры текстовым элементом (например, см. Пример «кнопки»), хотя важно отметить, что их реализация не может использоваться в браузере: http://www.csse.monash.edu.au/~clm/csvg/about.html

Я упоминаю об этом, потому что я разработал библиотеку, вдохновленную CSVG, которая позволяет вам делать подобные вещи и работает в веб-браузерах, хотя я еще не выпустил ее.

18 голосов
/ 01 июля 2017

Предыдущие ответы дали плохие результаты при использовании закругленных углов или stroke-width, что> 1. Например, вы могли бы ожидать, что следующий код создаст скругленный прямоугольник, но углы обрезаются родительским компонентом svg:

<svg width="200" height="100">
  <!--this rect should have rounded corners-->
  <rect x="0" y="0" rx="5" ry="5" width="200" height="100" stroke="red" stroke-width="10px" fill="white"/>
  <text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">CLIPPED BORDER</text>    
</svg>

Вместо этого я рекомендую обернуть text в svg и затем вставить новые svg и rect вместе в элемент g, как в следующем примере:

<!--the outer svg here-->
<svg width="400px" height="300px">

  <!--the rect/text group-->
  <g transform="translate(50,50)">
    <rect rx="5" ry="5" width="200" height="100" stroke="green" fill="none" stroke-width="10"/>
    <svg width="200px" height="100px">
      <text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">CORRECT BORDER</text>      
    </svg>
  </g>

  <!--rest of the image's code-->
</svg>

Это исправляет проблему отсечения, возникающую в ответах выше. Я также перевел группу rect / text с помощью атрибута transform="translate(x,y)", чтобы продемонстрировать, что это обеспечивает более интуитивный подход к размещению прямоугольника / текста на экране.

9 голосов
/ 12 августа 2016

Вы можете напрямую использовать text-anchor = "middle" свойство. Я советую создать элемент обертки SVG над вашим прямоугольником и текстом. Таким образом, вы можете использовать весь элемент, используя один селектор CSS. Убедитесь, что для свойства 'x' и 'y' текста указано 50%.

    <svg class="svg-rect" width="50" height="40">
        <rect x="0" y="0" rx="3" ry="3" width="50" height="40" fill="#e7e7e7"></rect>
        <text x="50%" y="50%" text-anchor="middle" stroke="black" stroke-width="1px" dy=".3em">N/A</text>
    </svg>
6 голосов
/ 04 февраля 2019

Если вы создаете SVG программно, вы можете упростить его и сделать что-то вроде этого:

  <g>
      <rect x={x} y={y} width={width} height={height} />
      <text
          x={x + width / 2}
          y={y + height / 2}
          dominantBaseline="middle"
          textAnchor="middle"
      >
          {label}
      </text>
  </g>
5 голосов
/ 16 ноября 2017

Полная информация Блог: http://blog.techhysahil.com/svg/how-to-center-text-in-svg-shapes/

<svg width="600" height="600">
  <!--   Circle -->
  <g transform="translate(50,40)">
    <circle cx="0" cy="0" r="35" stroke="#aaa" stroke-width="2" fill="#fff"></circle>
    <text x="0" y="0" alignment-baseline="middle" font-size="12" stroke-width="0" stroke="#000" text-anchor="middle">HueLink</text>
  </g>
  
  <!--   In Rectangle text position needs to be given half of width and height of rectangle respectively -->
  <!--   Rectangle -->
  <g transform="translate(150,20)">
    <rect width="150" height="40" stroke="#aaa" stroke-width="2" fill="#fff"></rect>
    <text x="75" y="20" alignment-baseline="middle" font-size="12" stroke-width="0" stroke="#000" text-anchor="middle">HueLink</text>
  </g>
  
  <!--   Rectangle -->
  <g transform="translate(120,140)">
    <ellipse cx="0" cy="0" rx="100" ry="50" stroke="#aaa" stroke-width="2" fill="#fff"></ellipse>
    <text x="0" y="0" alignment-baseline="middle" font-size="12" stroke-width="0" stroke="#000" text-anchor="middle">HueLink</text>
  </g>
  
  
</svg>

2 голосов
/ 14 ноября 2018

alignment-baseline не подходит для использования здесь.Правильный ответ - использовать комбинацию dominant-baseline="central" и text-anchor="middle":

<svg width="200" height="100">
    <g>
        <rect x="0" y="0" width="200" height="100" style="stroke:red; stroke-width:3px; fill:white;"/>
        <text x="50%" y="50%" style="dominant-baseline:central; text-anchor:middle; font-size:40px;">TEXT</text>
    </g>
</svg>
2 голосов
/ 20 июня 2017

Одним из способов вставки текста внутри прямоугольника является вставка постороннего объекта, который является DIV, внутри прямоугольного объекта.

Таким образом, текст будет изменять пределы DIV.

var g = d3.select("svg");
					
g.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width","100%")
.attr("height","100%")
.attr("fill","#000");


var fo = g.append("foreignObject")
 .attr("width","100%");

fo.append("xhtml:div")
  .attr("style","width:80%;color:#FFF;margin-right: auto;margin-left: auto;margin-top:40px")
  .text("Mussum Ipsum, cacilds vidis litro abertis Mussum Ipsum, cacilds vidis litro abertis Mussum Ipsum, cacilds vidis litro abertis");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.js"></script>
<svg width="200" height="200"></svg>
1 голос
/ 02 ноября 2014

У меня было много времени, когда все центрировалось с помощью SVG, поэтому я развернул свою маленькую функцию.надеюсь, это должно помочь вам.Обратите внимание, что это работает только для элементов SVG.

function centerinparent(element) { //only works for SVG elements
    var bbox = element.getBBox();
    var parentwidth = element.parentNode.width.baseVal.value;
    var parentheight = element.parentNode.height.baseVal.value;
    var newwidth = ((parentwidth / 2) - (bbox.width / 2)) - 2; //i start everything off by 2 to account for line thickness
    var newheight = ((parentheight / 2) - (bbox.height / 2)) - 2;
    //need to adjust for line thickness??

    if (element.classList.contains("textclass")) { //text is origined from bottom left, whereas everything else origin is top left
        newheight += bbox.height; //move it down by its height
    }

    element.setAttributeNS(null, "transform", "translate(" + newwidth + "," + newheight + ")");
    // console.log("centering BOXES:  between width:"+element.parentNode.width.baseVal.value + "   height:"+parentheight);
    // console.log(bbox);
}
0 голосов
/ 13 мая 2019

Для горизонтального и вертикального выравнивания текста в графике, Вы можете использовать следующие стили CSS. В частности, обратите внимание, что dominant-baseline:middle, вероятно, неправильно, так как это (обычно) на полпути между вершиной и базовой линией, а не на полпути между верхом и низом. Кроме того, некоторые некоторые источники (например, Mozilla ) используют dominant-baseline:hanging вместо dominant-baseline:text-before-edge. Это также, вероятно, неправильно, так как hanging предназначен для индийских скриптов. Конечно, если вы используете смесь латинского, индийского, иероглифов или что-то еще, вам, вероятно, нужно прочитать документацию .

/* Horizontal alignment */
text.goesleft{text-anchor:end}
text.equalleftright{text-anchor:middle}
text.goesright{text-anchor:start}
/* Vertical alignment */
text.goesup{dominant-baseline:text-after-edge}
text.equalupdown{dominant-baseline:central}
text.goesdown{dominant-baseline:text-before-edge}
text.ruledpaper{dominant-baseline:alphabetic}

Редактировать: Я только что заметил, что Mozilla также использует dominant-baseline:baseline, что определенно неправильно: это даже не признанное значение! Я предполагаю, что по умолчанию используется шрифт по умолчанию alphabetic, поэтому им повезло.

Подробнее: Safari (11.1.2) понимает text-before-edge, но не text-after-edge. Это также не на ideographic. Отличная штука, Apple. Таким образом, вы можете быть вынуждены использовать alphabetic и в конце концов разрешить спуск. К сожалению.

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