Reputation: 4333
I'm trying to create a text based SVG fill pattern that is dynamic (any text could be used). I want the text to repeat horizontally and vertically, without having to define width/height of the text object in the pattern definition. This Answer provided a lot of info regarding patternUnits, but it wasn't enough to answer my specific question. The pattern seems to require either absolute width/height (doesn't work with dynamic content) or relative % values that are based on the SVG canvas.
Is it possible for a pattern definition to be sized dynamically to fit its children's bounding box (supporting arbitrary text), while using userSpaceOnUse
for the pattern's children to set pixel values?
The usecase is consuming user-provided text, so predefined widths/sizes do not work; the solution needs to be agnostic to the text content.
svg{width:100%;height:100%;}
body{height: 100vh;}
body, html{padding:0;margin:0;}
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<pattern id="GPattern" x="0" y="0" width="100%" height="100%" patternUnits="userSpaceOnUse">
<text id="text" x="0" y="34" width="100%" height="100%"
style="font-family: Arial;
font-size : 34;
font-weight: 800;
stroke : #000000;
fill : #00ff00;
"
>This Text Should Be Dynamic</text>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#GPattern)"/>
</svg>
Right now the solution I am considering would be to use JS to calculate an absolute width based on content string.length
and manually edit the pattern's width attribute, but would prefer if SVG can calculate this automagically.
Upvotes: 1
Views: 342
Reputation: 348
Leveraging the answer in https://stackoverflow.com/a/13873631/1577447, you can use Javascript to adjust the size of your pattern.
You can trigger adjustPatternSize()
every time your code changes. I’ve baked in the default values in case you want to run this in a context where JS isn’t available.
svg{width:100%;height:100%;}
body{height: 100vh;}
body, html{padding:0;margin:0;}
input { position: absolute; left: 10%; bottom: 10%; }
<input id="textInput" type="text" value="This Text Is Dynamic">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<pattern id="GPattern" x="-4" y="-1" width="483" height="46" patternUnits="userSpaceOnUse">
<text id="text" x="0" y="34" width="100%" height="100%"
style="font-family: Arial;
font-size : 34;
font-weight: 800;
stroke : #000000;
fill : #00ff00;
"
></text>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#GPattern)"/>
<script type="text/javascript">
const padding = 4
const text = document.getElementById("text");
const rect = document.getElementById("GPattern");
const input = document.getElementById("textInput");
input.oninput = handleInput;
function handleInput(e) {
adjustPatternSize(e.target.value)
}
function adjustPatternSize(string) {
text.textContent = string;
const bbox = text.getBBox();
rect.setAttribute("x",bbox.x - padding);
rect.setAttribute("y",bbox.y - padding );
rect.setAttribute("width",bbox.width + 2*padding);
rect.setAttribute("height",bbox.height + 2*padding);
}
adjustPatternSize("This Text Is Dynamic");
</script>
</svg>
Upvotes: 1