Pregunta Cómo colocar y centrar texto en un rectángulo SVG


Tengo el siguiente rectángulo ...

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

Me gustaría centrar la palabra "Ficción" dentro de ella. Para otros rectángulos, ¿svg word wrap se queda dentro de ellos? Parece que no puedo encontrar nada específicamente sobre cómo insertar texto dentro de las formas que están centradas tanto horizontal como verticalmente y en el ajuste de la palabra. Además, el texto no puede salir del rectángulo.

Mirando a la http://www.w3.org/TR/SVG/text.html#TextElement el ejemplo no ayuda, ya que las xey del elemento de texto son diferentes de las xey del rectángulo. No parece haber ancho y alto para los elementos de texto. No estoy seguro de las matemáticas aquí.

(Mi tabla html simplemente no va a funcionar.)


76
2018-04-05 02:00


origen


Respuestas:


SVG 1.2 Complemento de texto agregado, pero la mayoría de las implementaciones de SVG que encontrará en el navegador (a excepción de Opera) no han implementado esta característica. Normalmente, depende de usted, el desarrollador, colocar el texto manualmente.

La especificación SVG 1.1 proporciona una buena visión general de esta limitación y las posibles soluciones para superarla:

Cada elemento de 'texto' causa un solo   cadena de texto para ser renderizado. SVG   no realiza ninguna interrupción automática de línea o   envoltura de palabras. Para lograr el efecto   de múltiples líneas de texto, use una de   los siguientes métodos:

  • El autor o el paquete de autor necesita   para calcular previamente los saltos de línea y el uso   múltiples elementos de "texto" (uno para cada   línea de texto).
  • El autor o autor   el paquete necesita pre-calcular la línea   se rompe y usa un solo elemento de 'texto'   con uno o más niños 'tspan'   elementos con valores apropiados para   atributos 'x', 'y', 'dx' y 'dy' a   establecer nuevas posiciones de inicio para aquellos   personajes que comienzan nuevas líneas.   (Este enfoque permite el texto del usuario   selección a través de múltiples líneas de   texto - ver Selección de texto y   operaciones del portapapeles).
  • Expresa el   texto para ser procesado en otro XML   espacio de nombres como XHTML [XHTML]   incrustado en línea dentro de un   Elemento 'foreignObject'. (Nota la   semántica exacta de este enfoque son   no completamente definido en este momento)

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

Como primitivo, el ajuste de texto se puede simular mediante el uso del atributo dy los elementos tspan y, como se menciona en la especificación, algunas herramientas pueden automatizarlo. Por ejemplo, en Inkscape, seleccione la forma que desee y el texto que desee y utilice Texto -> Fluir en marco. Esto le permitirá escribir su texto, con envoltura, que se ajustará según los límites de la forma. Además, asegúrese de seguir estas instrucciones para decirle a Inkscape que mantenga la compatibilidad con SVG 1.1: http://wiki.inkscape.org/wiki/index.php/FAQ#What_about_flowed_text.3F

Además, hay algunas bibliotecas de JavaScript que se pueden usar para automatizar automáticamente el ajuste de texto: http://www.carto.net/papers/svg/textFlow/

Es interesante notar la solución de CSVG para envolver una forma en un elemento de texto (por ejemplo, ver su ejemplo de "botón"), aunque es importante mencionar que su implementación es no utilizable en un navegador: http://www.csse.monash.edu.au/~clm/csvg/about.html

Menciono esto porque he desarrollado una biblioteca inspirada en CSVG que te permite hacer cosas similares y funciona en los navegadores web, aunque aún no la he lanzado.


33
2018-04-05 04:10



Una solución fácil para centrar texto horizontal y verticalmente en SVG:

  1. Establezca la posición del texto en centro absoluto del elemento en el que quieres centrarlo:

    • Si es el padre, podrías simplemente hacer x="50%" y ="50%".
    • Si es otro elemento, x sería el x de ese elemento + la mitad de su ancho (y similar para y pero con la altura).
  2. Utilizar el text-anchor propiedad para centrar el texto horizontalmente con el valor middle:

    medio

    Los caracteres renderizados están alineados de manera que el centro geométrico del texto renderizado resultante está en la posición de texto actual inicial.

  3. Utilizar el alignment-baseline propiedad para centrar el texto verticalmente con el valor middle (o según cómo quiera que se vea, es posible que desee hacer central)

Aquí hay una demostración simple:

<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



Las respuestas anteriores dieron resultados pobres al usar esquinas redondeadas o stroke-width eso es> 1. Por ejemplo, esperaría que el siguiente código produjera un rectángulo redondeado, pero las esquinas están recortadas por el padre svg componente:

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

En cambio, recomiendo envolver el text en un svg y luego anidar esa nueva svg y el rect juntos dentro de una g elemento, como en el siguiente ejemplo:

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

Esto soluciona el problema de recorte que ocurre en las respuestas anteriores. También traduje el grupo rect / text usando el transform="translate(x,y)" atributo para demostrar que esto proporciona un enfoque más intuitivo para colocar el rect / texto en la pantalla.


7
2017-07-01 04:16



Puedes usar directamente text-anchor = "middle" propiedad. Aconsejo crear un elemento contenedor SVG sobre su rectángulo y texto. De esa forma puedes usar todo el elemento usando un selector css. Asegúrese de colocar la propiedad 'x' e 'y' del texto como 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



Blog de detalles completos: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>


3
2017-11-15 23:50



Tuve un problema de tiempo consiguiendo algo centrado usando SVG, por lo que rodé mi propia pequeña función. espero que te ayude Tenga en cuenta que solo funciona para elementos 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



Una forma de insertar texto dentro de un rectángulo es insertar un objeto extraño, que es un DIV, dentro del objeto rect.

De esta manera, el texto rebasará los límites del 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