Taille de la boîte connue. Longueur de chaîne de texte inconnue. Ajuster le texte à la boîte sans ruiner ses proportions.
Après une soirée passée à googler et à lire les spécifications SVG, je suis quasiment sûr que ce n’est pas possible sans JavaScript. Le plus proche que j'ai pu obtenir a été d'utiliser les attributs de texte textLength et lengthAdjust, mais cela étend le texte le long d'un axe uniquement.
<svg width="436" height="180"
style="border:solid 6px"
xmlns="http://www.w3.org/2000/svg">
<text y="50%" textLength="436" lengthAdjust="spacingAndGlyphs">UGLY TEXT</text>
</svg>
Je connais SVG Scaling Text pour adapter le texte du conteneur et au texte
Je n'ai pas trouvé le moyen de le faire directement sans Javascript, mais j'ai trouvé une solution assez simple pour JS, sans boucles for et sans modifier la taille de la police, et s'intègre ainsi dans toutes les dimensions le côté le plus court.
Fondamentalement, j'utilise la propriété transform
, en calculant la bonne proportion entre la taille souhaitée et celle actuelle.
C'est le code:
<?xml version="1.0" encoding="UTF-8" ?>
<svg version="1.2" viewBox="0 0 1000 1000" width="1000" height="1000" xmlns="http://www.w3.org/2000/svg" >
<text id="t1" y="50" >MY UGLY TEXT</text>
<script type="application/ecmascript">
var width=500, height=500;
var textNode = document.getElementById("t1");
var bb = textNode.getBBox();
var widthTransform = width / bb.width;
var heightTransform = height / bb.height;
var value = widthTransform < heightTransform ? widthTransform : heightTransform;
textNode.setAttribute("transform", "matrix("+value+", 0, 0, "+value+", 0,0)");
</script>
</svg>
Dans l'exemple précédent, le texte grossit jusqu'au width == 500
, mais si j'utilise une taille de boîte de width = 500
et height = 30
, le texte s'agrandit jusqu'au height == 30
.
tout d'abord: je viens de voir que la réponse ne répond pas précisément à votre besoin - cela pourrait encore être une option, alors allons-y:
vous constatez à juste titre que svg ne prend pas directement en charge le wrapping Word. Toutefois, vous pourriez tirer profit des éléments foreignObject
servant de wrapper pour les fragments xhtml où le wrapping Word est disponible.
jetez un coup d’œil à cette démo indépendante (disponible en ligne ):
<?xml version="1.0" encoding="utf-8"?>
<!-- SO: http://stackoverflow.com/questions/15430189/pure-svg-way-to-fit-text-to-a-box -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1"
width="20cm" height="20cm"
viewBox="0 0 500 500"
preserveAspectRatio="xMinYMin"
style="background-color:white; border: solid 1px black;"
>
<title>simulated wrapping in svg</title>
<desc>A foreignObject container</desc>
<!-- Text-Elemente -->
<foreignObject
x="100" y="100" width="200" height="150"
transform="translate(0,0)"
>
<xhtml:div style="display: table; height: 150px; overflow: hidden;">
<xhtml:div style="display: table-cell; vertical-align: middle;">
<xhtml:div style="color:black; text-align:center;">Demo test that is supposed to be Word-wrapped somewhere along the line to show that it is indeed possible to simulate ordinary text containers in svg.</xhtml:div>
</xhtml:div>
</xhtml:div>
</foreignObject>
<rect x="100" y="100" width="200" height="150" fill="transparent" stroke="red" stroke-width="3"/>
</svg>
J'ai développé @Roberto answer, mais au lieu de transformer (mettre à l'échelle) le textNode, nous avons simplement:
font-size
de 1em
pour commencergetBBox
font-size
à cette échelle(Vous pouvez également utiliser 1px
etc.)
Voici le réactif HOC qui fait cela:
import React from 'react';
import TextBox from './TextBox';
const AutoFitTextBox = TextBoxComponent =>
class extends React.Component {
constructor(props) {
super(props);
this.svgTextNode = React.createRef();
this.state = { scale: 1 };
}
componentDidMount() {
const { width, height } = this.props;
const textBBox = this.getTextBBox();
const widthScale = width / textBBox.width;
const heightScale = height / textBBox.height;
const scale = Math.min(widthScale, heightScale);
this.setState({ scale });
}
getTextBBox() {
const svgTextNode = this.svgTextNode.current;
return svgTextNode.getBBox();
}
render() {
const { scale } = this.state;
return (
<TextBoxComponent
forwardRef={this.svgTextNode}
fontSize={`${scale}em`}
{...this.props}
/>
);
}
};
export default AutoFitTextBox(TextBox);
Je ne pense pas que ce soit la solution pour ce que vous voulez faire, mais vous pouvez utiliser textlenght
Avec pourcentage ="100%"
pour la largeur totale.
<svg width="436" height="180"
style="border:solid 6px"
xmlns="http://www.w3.org/2000/svg">
<text x="0%" y="50%" textLength="100%">blabla</text>
</svg>
vous pouvez également ajouter textanchor="middle"
et changer la position x
pour centrer parfaitement votre texte
cela ne changera pas la taille de la police et vous aurez un espacement bizarre des lettres ...