Pytanie Jak umieścić i wyśrodkować tekst w prostokącie SVG


Mam następujący prostokąt ...

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

Chciałbym umieścić w środku słowo "Fiction". W przypadku innych prostokątów, czy słowo zawijanie svg pozostaje w nich? Nie mogę znaleźć niczego konkretnego na temat wstawiania tekstu w kształtach, które są wyśrodkowane zarówno w poziomie, jak iw pionie i zawijaniu słów. Ponadto tekst nie może opuścić prostokąta.

Patrząc na http://www.w3.org/TR/SVG/text.html#TextElement przykład nie pomaga, ponieważ x i y elementu tekstowego różnią się od x i y prostokąta. Wygląda na to, że elementy tekstowe nie mają szerokości ani wysokości. Nie jestem pewien matematyki tutaj.

(Mój tabelka html po prostu nie zadziała.)


76
2018-04-05 02:00


pochodzenie




Odpowiedzi:


SVG 1.2 Niewielkie dodatkowe zawijanie tekstu, ale większość implementacji SVG, które znajdziesz w przeglądarce (z wyjątkiem Opery), nie zaimplementowała tej funkcji. Zwykle od Ciebie zależy, czy programista ręcznie umieści tekst.

Specyfikacja SVG 1.1 zapewnia dobry przegląd tego ograniczenia i możliwych rozwiązań w celu jego pokonania:

Każdy element "tekstowy" powoduje singiel   ciąg tekstu do renderowania. SVG   nie wykonuje automatycznego łamania linii lub   zawijanie słów. Aby osiągnąć efekt   wielu linii tekstu, użyj jednego z nich   następujące metody:

  • Autor lub pakiet autorski   aby wstępnie obliczyć podziały linii i użyć   wiele elementów "tekstowych" (po jednym dla każdego   linia tekstu).
  • Autor lub autor   pakiet wymaga wstępnego obliczenia linii   łamie i używa pojedynczego elementu "tekstowego"   z jednym lub więcej dzieckiem "tspan"   elementy z odpowiednimi wartościami dla   atrybuty "x", "y", "dx" i "dy" do   ustawić dla nich nowe pozycje początkowe   znaki, które rozpoczynają nowe linie.   (Takie podejście umożliwia tekst użytkownika   wybór w wielu liniach   tekst - patrz Wybór tekstu i   operacje schowka.)
  • Wyraź to   tekst do wyrenderowania w innym formacie XML   przestrzeń nazw, taka jak XHTML [XHTML]   wbudowane wewnątrz w   Element "foreignObject". (Zanotuj   Dokładna semantyka tego podejścia to   nie do końca zdefiniowane w tej chwili.)

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

Jako prymitywny, można symulować zawijanie tekstu za pomocą elementów dy i tspan, i jak wspomniano w specyfikacji, niektóre narzędzia mogą zautomatyzować to. Na przykład w programie Inkscape wybierz żądany kształt i żądany tekst, a następnie użyj polecenia Tekst -> Przeprowadź klatkę. Umożliwi to napisanie tekstu z zawijaniem, który będzie zawijany w oparciu o granice kształtu. Ponadto postępuj zgodnie z tymi instrukcjami, aby poinformować Inkscape o zachowaniu zgodności z SVG 1.1: http://wiki.inkscape.org/wiki/index.php/FAQ#What_about_flowed_text.3F

Ponadto istnieje kilka bibliotek JavaScript, które mogą być używane do dynamicznej automatyzacji zawijania tekstu: http://www.carto.net/papers/svg/textFlow/

Warto zauważyć, że rozwiązanie CSVG do zawijania kształtu do elementu tekstowego (np. Patrz ich przykład "przycisk"), chociaż ważne jest, aby wspomnieć, że ich implementacja jest nie użyteczny w przeglądarce: http://www.csse.monash.edu.au/~clm/csvg/about.html

Wspominam o tym, ponieważ stworzyłem bibliotekę inspirowaną CSVG, która pozwala robić podobne rzeczy i działa w przeglądarkach internetowych, chociaż jeszcze jej nie opublikowałem.


34
2018-04-05 04:10



I nawet nie zaczynaj mnie od tego, co jest zaangażowane w tworzenie edytowalny tekst... - jbeard4
Dzięki za odpowiedź ... ale ACK! Wygląda na to, że będę musiał wtedy przesłać svg. Jedną z pierwszych rzeczy, o których pomyśleli programiści, było dołączanie tekstów (sformatowanych według życzeń użytkowników) do kształtów! Będę czekać, aż oni zaczną działać razem, zanim ja już to zrobię. Spróbuję przerysować go w Windows Paint i zobaczyć, czy to zrobi. (Gdybym tylko mógł sprawić, by przeglądarki poprawnie wyświetlały tabelę.) - Lady Aleena
O edytowalnym tekście w svg, Opera obsługuje edytowalny atrybut z SVG 1.2 Tiny, dzięki czemu można uzyskać tekst edytowalny, po prostu dodając atrybut editable="true" do elementu text lub textArea. - Erik Dahlström
@Erik, po raz kolejny Opera wyprzedza zakręt. - jbeard4
@Lady Aleena, może po prostu skorzystasz z rozwiązania Inkscape, o którym wspomniałem? Jeśli jest to tylko statyczny obraz (np. Bez dynamicznego zachowania, bez dynamicznej aktualizacji zawartości tekstu), to powinno działać dobrze. Dodatkowo będzie skalowalny, a Paint nie, ponieważ Paint tworzy grafiki rastrowe. Wreszcie, nie wierzę, że Paint obsługuje zawijanie tekstu na dowolnym poziomie. - jbeard4


Proste rozwiązanie do wyśrodkowywania tekstu poziomo i pionowo w SVG:

  1. Ustaw pozycję tekstu na absolutne centrum elementu, w którym chcesz go wyśrodkować:

    • Jeśli to rodzic, możesz po prostu zrobić x="50%" y ="50%".
    • Jeśli to kolejny element, x byłby x tego elementu + połowa jego szerokości (i podobne dla y ale z wysokością).
  2. Użyj text-anchor Właściwość do wyśrodkowania tekstu w poziomie z wartością middle:

    środkowy

    Wyrenderowane znaki są wyrównane w taki sposób, że środkowa część wynikowego renderowanego tekstu znajduje się w początkowej bieżącej pozycji tekstowej.

  3. Użyj alignment-baseline Właściwość do wyśrodkowania tekstu w pionie z wartością middle (lub w zależności od tego jak chcesz wyglądać, możesz chcieć to zrobić central)

Oto prosta prezentacja:

<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%" alignment-baseline="middle" text-anchor="middle">TEXT</text>    
</svg>


103
2017-07-20 16:50



Szukałem wszędzie rozwiązania tak prostego - nic więcej nie działało dla mnie Użyłem tego do centrowania liczby wewnątrz paska radialnego postępu - anthonytherockjohnson
W moim przypadku jest to dominant-baseline własność, która wykonuje pracę, a nie alignment-baseline. - pintoch
Niestety, to rozwiązanie przycina prostokątny skok. Zobacz mój przykład poniżej dla rozwiązania, które unika obcinania: stackoverflow.com/a/44857272/3795219 - Austin D
Jeśli zamierzasz to robić regularnie, możesz również dodać: <style type="text/css"><![CDATA[ text { alignment-baseline: middle; text-anchor:middle; } ]]></style>. Dzięki za rozwiązanie. - Manngo


Poprzednie odpowiedzi dawały słabe wyniki przy użyciu zaokrąglonych narożników lub stroke-width to> 1. Na przykład można oczekiwać, że poniższy kod wygeneruje zaokrąglony prostokąt, ale rogi zostaną obcięte przez element nadrzędny svg składnik:

<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>

Zamiast tego zalecam zawijanie pliku text w svg a następnie zagnieżdżanie tego nowego svg i rect razem wewnątrz g element, jak w poniższym przykładzie:

<!--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>

To rozwiązuje problem z obcinaniem, który występuje w powyższych odpowiedziach. Przetłumaczyłem również grupę rect / text za pomocą transform="translate(x,y)" atrybut wykazujący, że zapewnia to bardziej intuicyjne podejście do ustawiania prostokąta / tekstu na ekranie.


7
2017-07-01 04:16





Możesz bezpośrednio użyć text-anchor = "middle" własność. Radzę stworzyć element svg opakowania nad twoim prostokątem i tekstem. W ten sposób możesz użyć całego elementu za pomocą jednego selektora css. Upewnij się, że wartość "x" i "y" tekstu wynosi 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>

4
2017-08-11 21:10



edytowane. Dzięki. - Nalin Agrawal


Pełny blog: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>


4
2017-11-15 23:50



Nie koncentruje się na firefox, podczas gdy inne rozwiązania są. codepen.io/anon/pen/oEByYr - tgf
Testowałem na Firefox 58.0.1 (64-bit), działa. Czy możesz wymienić wersję, dla której nie działa? - Sahil Gupta
Firefox 58.0.2 64bit. Tekst jest nieco wyższy niż powinien. Z początku może nie być łatwo zauważalne, ale jeśli twoje pudełko jest bardzo blisko, to jest bardziej oczywiste; spróbuj zmniejszyć wysokość. - tgf


Miałem kłopot z czasem, gdy cokolwiek wyśrodkowałem używając SVG, więc wyrzuciłem swoją własną małą funkcję. mam nadzieję, że to powinno ci pomóc. Zauważ, że działa tylko w przypadku elementów 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);
}

1
2017-11-02 04:02





Jednym ze sposobów wstawienia tekstu wewnątrz prostokąta jest wstawienie obcego obiektu, którym jest DIV, wewnątrz prostego obiektu.

W ten sposób tekst będzie respektował granice 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
2018-06-20 14:52



Witamy w Stack Overflow! Proszę wziąć wycieczka strony i jeśli potrzebujesz dodatkowej pomocy na stronie, sprawdź to na zewnątrz. Aha, i jeśli kiedykolwiek napotkasz problemy, których strona pomocy nie dotyczy, możesz poprosić o pomoc meta. - Isiah Meadows