Setting SVG preserveAspectRatio attribute dynamically - javascript

If you have an Angular component that uses svg files by referring to symbols from one packed file:
svg instance
<svg>
<use xlink:href="#my-symbol"></use>
</svg>
symbols as they appear in the imported file
<symbol id="my-symbol" viewBox="0 0 24 24">
<title>my-symbol</title>
<path class="path1" d=" ... data here ..."></path>
</symbol>
in order to get control over scaling behavior, every symbol element should apparently have preserveAspectRatio="..." set accordingly.
What if I want to do that dynamically, taking the values for preserveAspectRatio from component instance HTML input?
Something like:
imaginary my-icon template
<my-icon preserveAR="alignMeetOrSlice">
<svg preserveAspectRatio="{{preserveAR}}">
<use xlink:href="#my-symbol"></use>
</svg>
</my-icon>
desired render:
<svg>
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://somedomain.com/my.svg#my-symbol"></use>
#shadow-root (user agent)
<svg id="my-symbol" viewBox="0 0 24 24"> <!-- attribute should go to this svg -->
...
</svg>
</svg>
I tried querySelector('symbol') on the container - but it returned null results.
Is there a method to get into the shadow root and modify the symbol element?

In JS you can use direct assignment for svg.preserveAspectRatio.baseVal.align.
Instead a preserveAspectRatio="none" in HTML
you can write svg.preserveAspectRatio.baseVal.align=1 or svg.setAttribute('preserveAspectRatio', 'none'); in an JS script.
The examples are presented here:
with code-generation
alternatively with HTML-injection
and available values for aspectRatio can be seen here

Related

How to create a fallback placeholder for <use xlink:href /> in SVG/HTML?

Our team use SVG's <use xlink:href /> for shared SVG assets in our web pages. Here is a minimal example:
<div id="page-content">
<span>This is a blue square, isn't it?</span> <br />
<svg width="28" height="28">
<use
xlink:href="#our-team-shared-square"
style="color: blue;"
/>
</svg>
</div>
<!-- this svg can be inlined or loaded and inserted into the DOM dynamically -->
<svg xmlns="http://www.w3.org/2000/svg" style="display: none">
<symbol id="our-team-shared-square" viewBox="0 0 28 28">
<path d="M 4 4 H 24 V 24 H 4 Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd" />
</symbol>
<symbol id="our-team-shared-something-else" viewBox="0 0 28 28">
<!-- ... -->
</symbol>
<!-- and more others -->
</svg>
It is a powerful technique, but it has some pitfalls too: the ID in the xlink:href attribute could be misprinted or the big svg with shared symbols could be failed to load. In both cases there will no symbol on a page corresponding to the specified ID, and the <use /> will be rendered as an empty block.
In order to mitigate the problem we want to provide fallback placeholders for shared SVG assets.
<!-- something like this -->
<svg width="28" height="28">
<text>�</text> <!-- your fonts are okay, this is U+FFFD character :) -->
<use xlink:href="#our-team-shared-symbol" style="..." />
</svg>
<!-- or like this -->
<div class="our-svg-asset">
<svg width="28" height="28">
<use xlink:href="#our-team-shared-symbol" style="..." />
</svg>
<span>�</span>
</div>
But we need a way to detect whether the ID in the xlink:href attribute matches to some symbol on a page.
What do we think it might look like?
Some tricky CSS-selector, which matches with the svg tag, only if there is some visual content inside it (or opposite, only if there is an ID matching error inside the svg tag).
Some SVG layout magic, which make the successfully matched use tag to shift the placeholder and make it effectively invisible.
Some JS DOM API (the least desirable way), which allow to check if the <use xlink:href /> inside the given SVG tag is successfully matched to some SVG symbol.
It is quite likely there may exist another unimaginable for us ways to toggle such a fallback placeholder. :)
We hope to find a JS-less solution, but look forward to any suitable solution.
Thank you.

React and SVG sprite

I am using React, and I am trying to load a svg icon from a sprite. My sprite is like this:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<symbol viewBox="0 0 28.3 28.3" id="square">
<path d="M.3 30.7h27L13.8 3.8zM126.3-51.7c-8.8 0-16 7.2-16 16s7.2 16 16 16 16-7.2 16-16-7.2-16-16-16z" />
<path d="M0 28.3h28.3L14.2 0 0 28.3zm5.3-3.2l8.9-17.7L23 25.1H5.3z" />
</symbol>
<symbol viewBox="0 0 28.3 28.3" id="circle">
<circle cx="14.2" cy="14.2" r="14.2" />
</symbol>
</defs>
</svg>
And I load it with:
<svg viewBox="0 0 28.3 28.3" className="App-icon">
<use xlinkHref="./sprite#square" />
</svg>
With no results. I made a sandbox as an example: https://codesandbox.io/s/l711v6j7v7
If you want to reference it as external resource you need to use the proper URL to the svg file and it needs to be publicly accessible. So in the codesandbox you need to move it to the public folder, so that you can access it in the browser via
https://codesandbox.io/s/l711v6j7v7/sprite.svg
Then you can reference it like this:
<use href="/sprite.svg#square" />
See this fork of your codesandbox.
For those where the SVG file is an existing/external svg file.
You probably have an existing SVG webpack loader which is not working with the concept of SVG sprites. Why? It generally needs a file reference/url to the sprite file or the SVG (nodes) must exist in the DOM (Solution below)
This works:
Transform the plain SVG to JSX (google html to jsx)
Create a new pure react component and simply return the transformed JSX in render() method
Import and include the created react sprite component
Now use the sprite symbol via <use><svg href="#symbolnameorid"></svg></use> You can use it without the file prefix now

Keeping parts of an SVG at fixed size

Essentially I needed to make the center "cut-out" keep a fixed shape and size regardless of vector scale. Is there a way to achieve this?
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" preserveAspectRatio="none" style="fill-rule:evenodd;" viewBox="0 0 2802 2657">
<path d="M290 4c-95,733 -191,1466 -286,2200 760,150 1520,300 2279,450 172,-223 343,-446 515,-669 -114,-572 -229,-1144 -343,-1716 -722,-88 -1444,-176 -2165,-264zm696 1027c-103,111 -205,222 -308,333 94,111 188,222 282,333 342,-205 684,-410 1026,-616 -333,-17 -667,-34 -1000,-51z"/>
</svg>
So I managed to do something after some editing to your SVG.
To achieve what you're asking you'll need to use / have :
- the SVG mask attribute
- A very large shape for the mask ( as much large as the max scale you want to use on the visible shape )
- The shape that you want to resize
- Resize the shape with transforms
Your SVG should looks like the following
<svg>
<defs>
<mask id="theMask">
<path fill="#ffffff" d=""/>
</mask>
</defs>
<g mask="url(#theMask)">
<path fill="#ffffff" id="shapetoresize" d=""/>
</g>
</svg>
I posted a pen as a "Proof of concept"
Feel free to fork it and use it to achieve what you're trying to do.
Codepen
note: as pointed out by #thioutp , The JS is only for demo purposes, you don't need GSAP to achieve this.

Grouping elements in inline SVG disables getElementById() on group children

I have a simple SVG written directly in my HTML document. It contains one path with unique ID, originalPath. I can access that path directly by getElementById() like this:
HTML:
<svg id="previewImage" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path id="originalPath" d="" fill="none" stroke="black" stroke-width="1"></path>
</svg>
JS:
var svg = document.getElementById("previewImage");
var svgPath = svg.getElementById("originalPath");
// var svgPath = $("#originalPath")[0]; // Also working
However, if I wrap my originalPath in a group (directly in the HTML), the getElementById() function suddenly stops working, svgPath is undefined. The jQuery line doesn't work either.
<svg id="previewImage" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g>
<path id="originalPath" d=""></path>
</g>
</svg>
I can't see what I'm doing wrong. I even tried accessing the group first and then its child, but without any success. Could someone point me in the right direction?

JavaScript - Is there a way how to draw SVG path UNDER the content?

I need a path that goes UNDER the content (text) - is there a way how to do that?
(as already been answered somewhere else, z-index doesnt affect svg paths)
You can declare PATH and TEXT in different SVG layers, and put one layer onto another like this
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" style="position:absolute;z-index:1">
<text x="100" y="15" fill="red">I love SVG</text>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" style="position:absolute;z-index:0">
<path d="M150 0 L75 200 L225 200 Z" />
</svg>
http://jsfiddle.net/WJZrU/

Categories

Resources