SVG is not render on IOS (render empty space) - javascript

I check my site in browserstack and on same IOS or MacOs device in
different times SVG can work or can render empty space
//SVG USAGE
<svg>
<use xlinkHref={`#${id}`} />
</svg>
//SVG
<svg
onClick={onClick}
className="top-controls-panel__icon top-controls-panel__icon--points"
x="0px"
y="0px"
viewBox="0 0 47.1 12.1"
xmlSpace="preserve"
data-ieadjustwidth="40%"
>
<path d="M0.4,6.1c0,3.1,2.5,5.6,5.6,5.6s5.6-2.5,5.6-5.6S9.1,0.5,6,0.5S0.4,3,0.4,6.1" />
<path d="M17.4,6.1c0,3.1,2.5,5.6,5.6,5.6s5.6-2.5,5.6-5.6c0,0,0,0,0,0c0-3.1-2.5-5.6-5.6-5.6S17.4,3,17.4,6.1L17.4,6.1" />
<path d="M35.4,6.1c0,3.1,2.5,5.6,5.6,5.6c3.1,0,5.6-2.5,5.6-5.6S44.1,0.5,41,0.5C37.9,0.5,35.4,3,35.4,6.1L35.4,6.1" />
</svg>
I use JavaScript and React, problem that sometimes on IOS or MacOS
an empty space is rendered instead of svg.
I dont have apple device and testing site on browserStack service
In other questions I found that size of SVG can influence for that SVG is not render, but I dont undestand how that sizes should calculate, if sizes indicated in CSS in percent?
Also I change <use href... to <use xlinkHref... it is not work for me.
Now I won't try use
img src="your-svg-image.svg" alt="Your Logo Alt" onerror="this.src='your-alternative-image.png'"
instead of SVG, or I should use another variant?

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

Chrome prevents angular setting dynamic offsets in svg

Premise: This code (although it may be considered a hack) has been working for about 2 years, but all of a sudden this has stopped working in google chrome (the rendering of the gradient colors in svgs) and I don't know when exactly that has stopped, but still works in Safari! (see the 2 attached screenshots at the bottom).
I have an ng-repeat in which I render items with timeseries data and a different svg icon per item that I render dynamically via ng-include based on the item property that coincides with the name of the icon like "icon.type.svg".
<div ng-repeat="item in items">
<div class="pull-right">
<ng-include src="'img/icons/items/'+ item.type + '.svg'"></ng-include>
<h4><a>{{item.name}}</a></h4>
.....
</div>
</div>
All the svg follow the same strategy and a sample code can be seen below:
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 40.6 60.2" style="enable-background:new 0 0 40.6 60.2;" xml:space="preserve" ng-attr-height="{{myIcon.height || '60px'}}">
<style type="text/css">
</style>
<defs>
<linearGradient id="grad" gradientTransform="rotate(90)">
<stop ng-attr-offset="{{getOffset(item.level)}}" stop-color="#34495e">
</stop>
<stop offset="0%" stop-color="{{itemFillColor}}">
</stop>
</linearGradient>
</defs>
<path class="st0" d="M40.6,0H0v39v0.6c0,1.2-0.1,13.3,8.1,18.3c4,2.4,8.7,2.3,12.5,2.3c3.5,0,7.4-0.1,10.9-2
c8.5-4.6,9.1-17.1,9.1-18.5v-0.6V0z"/>
<path class="st1" d="M5.4,53.4"/>
<path d="M39,1.7H1.5v36.8v0.6c0,1.1-0.1,12.6,7.5,17.3c3.7,2.3,8,2.2,11.5,2.2c3.2,0,6.8-0.1,10.1-1.9c7.8-4.3,8.4-16.1,8.4-17.5
v-0.6V1.7z" fill="url(#grad)"/>
</svg>
Then in my controller I have a simple method (getOffset) as follows:
$scope.getOffset = function(level) {
if (!level) return '100%';
return (100 - level) + '%';
};
The way the icon work is kind of backward. They are 100% green (variable itemFillColor), and then the navy blue color, which is the actual body of the item, is then lowered from the top down to render the actual level.
Chrome Rendering
Safari Rendering
With Chrome it seems like that whatever "level" the first container has (in this case is actually 0 (null)), is applied to all subsequent items in the ng-repeat.
Can someone advise me on how to solve this or know why this started to happen all of a sudden?
Is there a better way otherwise to do this or go around the issue?
Would love to hear why this happened.
Edit: To "prove" that my hunch is that is nothing wrong with the svg per se, I use the same svg and do the exact same approach in a page with a single item selected (no ng-repeat, but a single ng-include) and the result is correct:
Single Page view

Setting SVG preserveAspectRatio attribute dynamically

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

Debugging! SVG logo & tooltip bug

I am pretty new at editing and embedding SVG to webpages. My client is a graphic designer so he created an svg logo for his website and wanted me embed it to his nav bar.
I am also using Bootstrap and as part of the development I am using bootstrap tooltips. However, once i embed the svg and edit the co-ordinates via viewbox, I encountered a problem with one of my tooltips.
The tooltip seems to be buggy with this particular logo. The rest of them are okay but for some reason I cannot figure out how to fix this one.
I have uploaded the website today for testing purposes and you can see the issue on http://edizorac.com/
The problematic logo is the second one on the navigation bar and you can also see my code through web inspector.
Any help/recommendation is appreciated!!
Thanks in advance :)
Update:
Sorry for any inconveniences. The svg code is as follows:
<li>
<a href="#projects">
<span>
<svg version="1.2" baseProfile="tiny" x="0px" y="0px" width="70px" height="60px" viewBox="50 40 90 120" data-toggle="tooltip" title="Projects">
<polygon fill="none" stroke="#ffffff" stroke-miterlimit="10" points="33.493,81.046 96.934,46.112 88.647,82.874 57.203,117.371 52.946,86.674 99.573,74.629 81.325,117.276 37.909,101.254"/>
<polyline fill="none" stroke="#ffffff" stroke-miterlimit="10" points="96.451,81.928 114.361,106.172 112.365,112.871 82.791,113.852 "/>
<line fill="none" stroke="#ffffff" stroke-miterlimit="10" x1="95.854" y1="47.473" x2="37.909" y2="101.254"/>
</svg>
</span>
</a>
</li>
May I suggest you have a read over this and also have a look at this to help you with SVG's
Change the first line of your SVG block to:
<svg version="1.2" baseProfile="tiny" x="0px" y="0px" width="40px" height="40px" viewBox="30 47 85 70" data-toggle="tooltip" title="" data-original-title="Projects">
You made the following mistakes:
You had the height and width set incorrectly compared to the other SVG's (Height you had defined: 60px & Width you had defined 70px)
Your viewBox property was set incorrectly so the elements didn't align properly

Categories

Resources