Adding/removing css class breaks the js sometimes? - javascript

Alright, something strange is occurring here. First, I have these <span>'s set up, with svgs that have a gaussian blur filter - 7 of them:
<span name = "sunlight">
<div id = "svgContainer">
<div id = "inner">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 700 650">
<defs>
<filter id="Blur"><feGaussianBlur stdDeviation="25" /></filter>
<g id="" data-name="Layer 1"><rect class="cls-1" width="700" height="558"/></g><g id="Img" data-name="Layer 2"><path class="cls-2" d="M403.71,111.69q-47.58,19.77-94,42.26-45.18,22-89,46.69c-13.09,7.37-26.15,14.91-38.11,24A160,160,0,0,0,163.94,241a71.68,71.68,0,0,0-8.7,10.37,16.54,16.54,0,0,0,2.12,20.7c3.48,3.41,8.14,5,12.85,5.71l13,1.94,26,3.89,51.71,7.73L364.68,306.8l13,1.95-7.17-17.63A117.3,117.3,0,0,1,361.32,305l1.87-2.43c-10.79,14-24.25,25.51-37.89,36.59-13.79,11.19-28,22-40.41,34.74a151.85,151.85,0,0,0-20.2,25.28c-3.89,6.18-.36,16.17,7.17,17.62a91,91,0,0,1,18,5.5L287,421.08a93.25,93.25,0,0,1,20.12,11.77L304.72,431a90.48,90.48,0,0,1,14.91,14.56c1.82,2.24,5.73,3.51,8.49,3.51a12.22,12.22,0,0,0,8.48-3.51,12.1,12.1,0,0,0,3.52-8.49l-.43-3.19a11.93,11.93,0,0,0-3.09-5.29c-11.62-14.33-27.45-24.86-44.72-31.15a90.6,90.6,0,0,0-13.64-3.76l7.17,17.63q3.13-5,6.73-9.63l-1.88,2.43c11.28-14.54,25.42-26.48,39.66-38s28.95-22.83,41.52-36.31a139.45,139.45,0,0,0,19.8-26.54,11.88,11.88,0,0,0,.6-10.68c-1.31-3.1-4.21-6.41-7.78-6.95l-83.92-12.54-83.92-12.55L193,257l-11.77-1.76c-3.28-.49-6.76-.7-9.87-1.91l2.87,1.21a9.41,9.41,0,0,1-2-1.16l2.43,1.87a8.2,8.2,0,0,1-.78-.78l1.88,2.43a5.42,5.42,0,0,1-.55-.93l1.21,2.87a5.84,5.84,0,0,1-.29-1.09l.43,3.19a4.3,4.3,0,0,1,0-1l-.43,3.19a7.34,7.34,0,0,1,.38-1.37l-1.21,2.87a12.1,12.1,0,0,1,1.27-2.1l-1.87,2.43c6.15-7.92,13.78-14.75,21.68-20.88l-2.43,1.88c11.16-8.6,23.29-15.81,35.53-22.75q20.44-11.61,41.22-22.6,41.77-22.14,84.74-41.9,24.18-11.12,48.72-21.48l-2.86,1.21q4.41-1.86,8.83-3.69c3-1.26,5.45-2.58,7.17-5.52a12.3,12.3,0,0,0,1.21-9.25A12.15,12.15,0,0,0,413,112.9c-2.64-1.4-6.34-2.41-9.24-1.21Z"/>
</g>
</defs>
<use style="fill:pink;" filter="url(#Blur)" xlink:href="#Img"
transform="translate(0,0)"/>
<use style="fill:white;" xlink:href="#Img"/>
</svg>
</div>
</div>
<h4>[ sunlight ]</h4>
<h5>5.2</h5>
</span>
Next, I have this css that either sets the <span> to display:inline-block or display:none:
#center > span.active {
display: inline-block;
}
#center > span {
display: none;
margin-left: -35px;
margin-right: -35px;
}
With js, I then (onscroll) iterate through a list of arrays. I need to add or removing the active class from each <span> depending on whether its name is in the array at the current index.
$('#center').children().each(function(i, child) {
if(localThis.currentDataPt[0].includes($(child).attr('name')))
{
$(child).addClass('active');
} else {
$(child).removeClass('active');
}
This is fine. However, when we get past this down to the part where I set via js the "feGaussianBlur" attribute, on MOST of the arrays, the attribute is visually set to zero. This doesnt happen when I dont do the show/hide:
$(child).find("feGaussianBlur").attr("stdDeviation", ((localThis.currentDataPt[1]/10)*45).toString());
Why would this happen?

Related

SVG animation on scroll once

Hi everyone I can program, and I saw a few weeks ago, that SVG animations are pretty useful!
Now my question:
I want to animate text like this website: https://weaintplastic.com/ I do not want the other things, just the Animation! I tried a lot of things, Exported via Illustrator a svg but it did not worked out. I do not want to use, any tool from github!
My assumption is:
I have to animate any letter in a Word (like the website), such that I have to know the paths from the svg! But this makes problem! How can I get a animation like this? Lets assume I want the word for ABOUT ME for example, how can I achieve CSS and JS which does the job for any svg if I have the path, or do I have to do for every Letter an own CSS and JS?
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 315 45" style="enable-background:new 0 0 315 45;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;}
</style>
<g>
<path d="M78.55,26.83l-2,5.75h-2.57l6.53-18.3h2.99l6.56,18.3h-2.65l-2.05-5.75H78.55z M84.85,24.98l-1.88-5.27
c-0.43-1.19-0.71-2.28-1-3.34h-0.06c-0.29,1.09-0.6,2.2-0.97,3.31l-1.88,5.29H84.85z"/>
<path d="M92.61,32.58c0.06-0.9,0.11-2.23,0.11-3.39V13.31h2.48v8.25h0.06c0.88-1.47,2.48-2.42,4.71-2.42c3.42,0,5.85,2.71,5.82,6.7
c0,4.7-3.11,7.03-6.19,7.03c-2,0-3.59-0.73-4.62-2.47h-0.09l-0.11,2.17H92.61z M95.2,27.32c0,0.3,0.06,0.6,0.11,0.87
c0.48,1.66,1.94,2.8,3.76,2.8c2.62,0,4.19-2.04,4.19-5.05c0-2.63-1.43-4.89-4.11-4.89c-1.71,0-3.31,1.11-3.82,2.93
c-0.06,0.27-0.14,0.6-0.14,0.98V27.32z"/>
<path d="M121.44,25.9c0,4.86-3.54,6.98-6.87,6.98c-3.74,0-6.62-2.61-6.62-6.76c0-4.4,3.02-6.98,6.84-6.98
C118.75,19.15,121.44,21.89,121.44,25.9z M110.48,26.04c0,2.88,1.74,5.05,4.19,5.05c2.4,0,4.19-2.14,4.19-5.1
c0-2.23-1.17-5.05-4.14-5.05S110.48,23.54,110.48,26.04z"/>
<path d="M136.15,29c0,1.36,0.03,2.55,0.11,3.58h-2.22l-0.14-2.14h-0.06c-0.66,1.06-2.11,2.44-4.56,2.44
c-2.17,0-4.76-1.14-4.76-5.75v-7.68h2.51v7.27c0,2.5,0.8,4.18,3.08,4.18c1.68,0,2.85-1.11,3.31-2.17c0.14-0.35,0.23-0.79,0.23-1.22
v-8.06h2.51V29z"/>
<path d="M143.33,15.67v3.77h3.59v1.82h-3.59v7.09c0,1.63,0.48,2.55,1.88,2.55c0.66,0,1.14-0.08,1.45-0.16l0.11,1.79
c-0.48,0.19-1.25,0.33-2.22,0.33c-1.17,0-2.11-0.35-2.71-1c-0.71-0.71-0.97-1.87-0.97-3.42v-7.17h-2.14v-1.82h2.14v-3.15
L143.33,15.67z"/>
<path d="M172.08,24.55c-0.14-2.55-0.31-5.62-0.29-7.9h-0.09c-0.66,2.14-1.45,4.42-2.42,6.95l-3.39,8.88h-1.88l-3.11-8.71
c-0.91-2.58-1.68-4.94-2.22-7.11h-0.06c-0.06,2.28-0.2,5.35-0.37,8.09l-0.51,7.84h-2.37l1.34-18.3h3.17l3.28,8.85
c0.8,2.25,1.46,4.26,1.94,6.16h0.09c0.48-1.85,1.17-3.86,2.02-6.16l3.42-8.85h3.17l1.2,18.3h-2.42L172.08,24.55z"/>
<path d="M188.76,24h-7.47v6.6h8.33v1.98H178.8v-18.3h10.38v1.98h-7.9v5.78h7.47V24z"/>
</g>
<g>
<rect x="54.72" y="8.99" class="st0" width="69.62" height="7.96"/>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>
I tried figma and svgator, and so on, but this is not useful, since I want to DO the ANIMATION WHEN I SCROLL on the section. (Once like the website).
I am sorry if my question is not Perfect, I tried my best to be precise as possible, and searched first on the Forum before I asked.
The technique has to be a combination with SVGGeometryElement.getTotalLength, stroke-dasharray, stroke-dashoffset, and the Intersection Observer API.
The example you provided has a lot more complex SVG elements than your own example. If you inspect the SVG you'll see that each letter consists of 1 or more <polygon> elements that are being animated. Being that your own SVG is a bit simpler I've built the example below on it.
First thing that is important is that the animation in the example animates the stroke property of each polygon. They do that by calculating the entire length of each path and setting both the stroke-dasharray and stroke-dashoffset properties with that total calculated path length. This will push the stroke out of the svg to be invisible, setting up the animation. (Each path has a different length, so setting the properties manually is a tedious job, let JS do it).
Then use the Intersection Observer API to determine when certain elements come into view. In this case I've chosen to watch for whole sections to come into view. Whenever a section enters the viewport, it will add an animate class to the section. In CSS I've defined that the class will trigger an animation that will change the stroke-dashoffset property. This will cause the stroke to animate back into the SVG.
const paths = document.querySelectorAll('svg path');
const sections = document.querySelectorAll('section');
paths.forEach((path, index) => {
const length = path.getTotalLength();
path.style.strokeDashoffset = `${length}px`;
path.style.strokeDasharray = `${length}px`;
path.style.animationDelay = `${index * 250}ms`;
});
const onInterSection = (entries, observer) => {
for (const { isIntersecting, target } of entries) {
if (isIntersecting) {
target.classList.add('animate');
observer.unobserve(target);
}
}
};
const observer = new IntersectionObserver(onInterSection);
for (const section of sections) {
observer.observe(section);
}
.st0 {
fill: none;
}
section {
display: grid;
place-items: center;
height: 75vh;
}
section:first-of-type {
background-color: #f7f7f7;
}
section:nth-of-type(2) {
background-color: #d7d7d7;
}
section:nth-of-type(2) {
background-color: #e7e7e7;
}
path {
stroke: black;
stroke-width: 1px;
fill: none;
}
section.animate path {
animation: letter 2s 1s forwards ease-out;
}
#keyframes letter {
to {
stroke-dashoffset: 0;
}
}
<section>
<span>Scroll down to animation</span>
</section>
<section>
<span>A bit further</span>
</section>
<section>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 315 45" style="enable-background:new 0 0 315 45;" xml:space="preserve">
<path d="M78.55,26.83l-2,5.75h-2.57l6.53-18.3h2.99l6.56,18.3h-2.65l-2.05-5.75H78.55z M84.85,24.98l-1.88-5.27
c-0.43-1.19-0.71-2.28-1-3.34h-0.06c-0.29,1.09-0.6,2.2-0.97,3.31l-1.88,5.29H84.85z"/>
<path d="M92.61,32.58c0.06-0.9,0.11-2.23,0.11-3.39V13.31h2.48v8.25h0.06c0.88-1.47,2.48-2.42,4.71-2.42c3.42,0,5.85,2.71,5.82,6.7
c0,4.7-3.11,7.03-6.19,7.03c-2,0-3.59-0.73-4.62-2.47h-0.09l-0.11,2.17H92.61z M95.2,27.32c0,0.3,0.06,0.6,0.11,0.87
c0.48,1.66,1.94,2.8,3.76,2.8c2.62,0,4.19-2.04,4.19-5.05c0-2.63-1.43-4.89-4.11-4.89c-1.71,0-3.31,1.11-3.82,2.93
c-0.06,0.27-0.14,0.6-0.14,0.98V27.32z"/>
<path d="M121.44,25.9c0,4.86-3.54,6.98-6.87,6.98c-3.74,0-6.62-2.61-6.62-6.76c0-4.4,3.02-6.98,6.84-6.98
C118.75,19.15,121.44,21.89,121.44,25.9z M110.48,26.04c0,2.88,1.74,5.05,4.19,5.05c2.4,0,4.19-2.14,4.19-5.1
c0-2.23-1.17-5.05-4.14-5.05S110.48,23.54,110.48,26.04z"/>
<path d="M136.15,29c0,1.36,0.03,2.55,0.11,3.58h-2.22l-0.14-2.14h-0.06c-0.66,1.06-2.11,2.44-4.56,2.44
c-2.17,0-4.76-1.14-4.76-5.75v-7.68h2.51v7.27c0,2.5,0.8,4.18,3.08,4.18c1.68,0,2.85-1.11,3.31-2.17c0.14-0.35,0.23-0.79,0.23-1.22
v-8.06h2.51V29z"/>
<path d="M143.33,15.67v3.77h3.59v1.82h-3.59v7.09c0,1.63,0.48,2.55,1.88,2.55c0.66,0,1.14-0.08,1.45-0.16l0.11,1.79
c-0.48,0.19-1.25,0.33-2.22,0.33c-1.17,0-2.11-0.35-2.71-1c-0.71-0.71-0.97-1.87-0.97-3.42v-7.17h-2.14v-1.82h2.14v-3.15
L143.33,15.67z"/>
<path d="M172.08,24.55c-0.14-2.55-0.31-5.62-0.29-7.9h-0.09c-0.66,2.14-1.45,4.42-2.42,6.95l-3.39,8.88h-1.88l-3.11-8.71
c-0.91-2.58-1.68-4.94-2.22-7.11h-0.06c-0.06,2.28-0.2,5.35-0.37,8.09l-0.51,7.84h-2.37l1.34-18.3h3.17l3.28,8.85
c0.8,2.25,1.46,4.26,1.94,6.16h0.09c0.48-1.85,1.17-3.86,2.02-6.16l3.42-8.85h3.17l1.2,18.3h-2.42L172.08,24.55z"/>
<path d="M188.76,24h-7.47v6.6h8.33v1.98H178.8v-18.3h10.38v1.98h-7.9v5.78h7.47V24z"/>
<rect x="54.72" y="8.99" class="st0" width="69.62" height="7.96"/>
</svg>
</section>

Animate reused svg independently

I want some SVGs to animate on click. The SVG is defined once and has been reused multiple times with the <use> tag.
I wrote the following code:
svg {
border: 1px solid #0af;
stroke: black;
}
<svg display="none">
<symbol id="tick" viewBox="0 0 100 100">
<polyline points="15,50 40,75 85,25" style="stroke-width:10; fill:none; stroke-linecap:round; stroke-linejoin:round;" stroke-dasharray="120">
<animate attributeName="stroke-dashoffset" from="120" to="0" dur="0.5s" fill="freeze" repeatCount="1" begin="click" />
</polyline>
</symbol>
</svg>
<svg><use href="#tick"/></svg>
<svg><use href="#tick"/></svg>
<svg><use href="#tick"/></svg>
<svg><use href="#tick"/></svg>
The problem is, if I click on a single SVG, all the instances of that SVG are getting animated, which is not what I want. I want them to animate independently. What is the best way to do this other than embedding the complete SVG multiple times?
you can put your svg in a file and access it in document tree like this:
<object data="tick.svg"></object>
Your problem is duplicate ids
create a Web Component (supported in all modern Browsers) that injects your once defined SVG
<svg-tick id=ONE stroke="red"></svg-tick>
<svg-tick id=TWO></svg-tick>
<svg-tick id=THREE></svg-tick>
<svg-tick id=FOUR stroke="blue"></svg-tick>
You can add more Web Component goodies, like attributes and a single clickhandler...
I changed the polyline to path, makes it easier with a pathLength=100, no need for calculations
id not required, you can also generate a unique value with "ID"+new Date()/1
<style>
svg {
border: 1px solid #0af;
stroke: green;
width: 120px;
cursor:pointer;
}
#TWO svg { stroke: goldenrod; }
</style>
<svg-tick id=ONE stroke="red"></svg-tick>
<svg-tick id=TWO></svg-tick>
<svg-tick id=THREE></svg-tick>
<svg-tick id=FOUR stroke="blue"></svg-tick>
<script>
customElements.define('svg-tick', class extends HTMLElement {
connectedCallback() {
let id = this.id;
let stroke = this.hasAttribute("stroke")
? ` stroke=${this.getAttribute("stroke")} `
: "";
this.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<path id="${id}" d="M15,50 40,75 85,25" pathLength="100"
stroke-width="10" fill="none" stroke-linecap="round" stroke-linejoin="round"
stroke-dasharray="100" ${stroke}/>
<animate id="${id}" attributeName="stroke-dashoffset" from="100" to="0"
dur="0.5s" fill="freeze" repeatCount="1" begin="click" />
</svg>`;
this.onclick = (evt) => console.log('clicked',id);
}
});
</script>
svga

How to use and style (selector) nested symbols in SVG

I have something like the following:
<html>
<head>
<style>
html, body {
margin: 0;
padding: 0;
overflow: hidden;
}
grove > tree > triangle {
/* some triangle styles */
}
#grove1 > tree > triangle {
/* some triangle styles for grove 1 */
}
#grove2 > tree > triangle {
/* some triangle styles for grove 2 */
}
#grove3 > tree > triangle {
/* some triangle styles for grove 3 */
}
#grove3 > tree {
/* animate the tree */
}
</style>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 3000 3000">
<defs>
<symbol id="triangle" viewBox="0 0 100 100">
<polygon points="0,100 50,0 100,100" class="triangle" />
</symbol>
<symbol id="tree" viewBox="0 0 100 100">
<use href="#triangle" width="100" height="100" />
</symbol>
<symbol id="grove" viewBox="0 0 100 100">
<use href="#tree" width="10" height="10" />
<use href="#tree" width="10" height="10" x="20" />
<use href="#tree" width="10" height="10" x="40" />
<use href="#tree" width="10" height="10" x="60" />
<use href="#tree" width="10" height="10" x="80" />
</symbol>
</defs>
<use id="grove1" href="#grove" x="10" y="10" height="10"/>
<use id="grove2" href="#grove" x="30" y="100" height="100"/>
<use id="grove3" href="#grove" x="50" y="600" height="600"/>
</svg>
</body>
</html>
Notice that symbols are nested 3 levels deep. And the sizing definitions change at each symbol. For example, in the grove symbol, the viewBox is 100x100, but the trees which it contains also have their own view box of 100x100. The trees are sized to 10x10 in the grove, so they have a different scaling system.
Basically though, I compose these symbols into the grove symbol, then add those using use in 3 different places. Each one appears larger/closer than the one before. Or that's how it should work.
The question is how I can change the colors on these symbols efficiently and properly (best-practice). If I can do something like the example CSS above:
grove > tree > triangle {
/* some triangle styles */
}
Or if I have to use JavaScript somehow to change the styles in this situation, or otherwise not really use symbols at all, or create symbol for every color variation I want (somehow).
Please let me know how I should structure this SVG system so I can properly style each chunk of stuff (each "grove" for example, and its contents).
Another example I'd like for this to handle is, say each tree has branches. I want to have 5 rows of trees, as if it's parallax and each row is further in the distance than the one before, and as such they get lighter and lighter. So I would like to set the color of the branches and the "leaves" (main tree triangle) to be lighter and lighter as they move back. In addition, maybe I want to slightly change the color of the trees at a specific row. So I should be able to do something like this:
#grove1 > tree > branch { /* style */ }
#grove1 > #tree1 { /* style */ }
#grove1 > #tree2 { /* style */ }
#grove1 > #tree2 > #branch1 { /* style */ }
#grove1 > #tree2 > #branch2 { /* style */ }
#grove1 > etc...
Basically how to style the nested symbols individually. If it's not possible, then what the design pattern is I should be using instead.
Styles can inherit into the children of a <use> see below:
<html>
<head>
<style>
html, body {
margin: 0;
padding: 0;
overflow: hidden;
}
#grove {
/* some triangle styles */
}
#grove1 {
/* some triangle styles for grove 1 */
fill: red;
}
#grove2 {
/* some triangle styles for grove 2 */
fill: green;
}
#grove3 {
/* some triangle styles for grove 3 */
fill: gold;
}
#grove3 > tree {
/* animate the tree */
}
</style>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 3000 3000">
<defs>
<symbol id="triangle" viewBox="0 0 100 100">
<polygon points="0,100 50,0 100,100" class="triangle" />
</symbol>
<symbol id="tree" viewBox="0 0 100 100">
<use href="#triangle" width="100" height="100" />
</symbol>
<symbol id="grove" viewBox="0 0 100 100">
<use href="#tree" width="10" height="10" />
<use href="#tree" width="10" height="10" x="20" />
<use href="#tree" width="10" height="10" x="40" />
<use href="#tree" width="10" height="10" x="60" />
<use href="#tree" width="10" height="10" x="80" />
</symbol>
</defs>
<use id="grove1" href="#grove" x="10" y="10" height="10"/>
<use id="grove2" href="#grove" x="30" y="100" height="100"/>
<use id="grove3" href="#grove" x="50" y="600" height="600"/>
</svg>
</body>
</html>
You can style the <symbol> and it's children.
You can style the <use> element.
However you can't have selectors that cross the <use> "boundary".
#myuse > #mysymbol-child
will not work. You cannot use a selector to target a specific instance of that symbol. Except by inheritance from the <use> as I have done in my example.
A symbol is a definition. If you give it a direct style, then that symbol with whatever style it has, will be used everywhere. That includes things like animation. If you animate the symbol, all instances of it will be animated the same way.
If I remember correctly, the trick to do that is to set the properties you want to set differently for each instance of <use> to "inherit" or "currentColor" (or if they're inherited by default, don't set them, if you don't need to) and then place each <use> in a <g> and apply the style declarations to each <g>.
SVG - inherit multiple colors

Two different views of the same svg drawing

I want to make a fairly large diagram using SVG (I have been using Snap.svg in JavaScript). I'd like to display a zoomable portion of the diagram in an element, and also a smaller version of the whole thing in a different element, in which the user can navigate.
One strategy is this:
Make two identical SVGs, except that they have different viewBoxes, and every time I change one of the svg elements, make an identical change to the other copy. The viewBox attributes cause each view to show the right part of the diagram.
Is that a good strategy? Seems fragile and wasteful to me. Is there some other, smarter approach? Do I really have to draw everything twice?
Hoping for "D'oh!"
Yes it's possible to have a master SVG and then "thumbnail" and/or "zoomed" versions of the same image that update automatically.
document.getElementById("but").addEventListener("click", function() {
var svg = document.getElementById("mainsvg");
var c = document.createElementNS("http://www.w3.org/2000/svg", "circle");
c.setAttribute("cx", 1000*Math.random());
c.setAttribute("cy", 1000*Math.random());
c.setAttribute("r", 50);
c.setAttribute("fill", "red");
svg.appendChild(c);
});
#main {
width: 400px;
height: 400px;
}
#thumb,
#zoom {
display: inline-block;
width: 80px;
height: 80px;
}
svg {
border: solid 1px grey;
}
<div id="main">
<svg id="mainsvg" viewBox="0 0 1000 1000">
<rect x="100" y="100" width="500" height="500" fill="green"
transform="rotate(10,350,350)"/>
<rect x="400" y="400" width="500" height="500" fill="orange"
transform="rotate(-10,650,650)"/>
</svg>
</div>
<div id="thumb">
<svg xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1000 1000">
<use xlink:href="#mainsvg" />
</svg>
</div>
<div id="zoom">
<svg xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1000 1000">
<use xlink:href="#mainsvg"
x="-500" y="-1200"
width="3000" height="3000" />
<!-- control the zoom and position with x, y, width and height -->
</svg>
</div>
<div>
<button id="but">Click me</button>
</div>

Click events stop working after replacing attribute of <use> element in <svg> (Win7/IE11)

We are using multiple svg symbols for displaying icons.
<!-- defining them at the start of the page -->
<div id="icon-container">
<svg xmlns="http://www.w3.org/2000/svg">
<symbol xmlns="http://www.w3.org/2000/svg"
id="rect" ...>
<rect... />
</symbol>
<symbol xmlns="http://www.w3.org/2000/svg"
id="circle" ...>
<circle... />
</symbol>
</svg>
</div>
<!-- using them in the page somewhere -->
<svg>
<use xlink:href="#rect"></use>
</svg>
In some cases we need to replace them later on with another icon (like on a collapse control), therefore I created a little helper function to change the xlink:href to the new symbol name.
$.fn.replaceSVGIcon = function(id) {
$(this).find('svg')
.andSelf()
.filter('svg')
.find('use')
.attr('xlink:href', '#' + id);
}
This works in every browser except for IE10 + IE11 on Windows 7 (but weirdly enough it works with Windows 8).
When you open the snippet below in IE11 and click on the red box everything is fine, but as soon as you start clicking on the element within, it breaks the whole page after the icon is changed for the first time.
(function($){
$.fn.replaceSVGIcon = function(id) {
$(this).find('svg').andSelf().filter('svg').find('use').attr('xlink:href', '#' + id);
}
})(jQuery);
clickFunction = function() {
var $elem = $('#icon');
if ($elem.find('use').attr('xlink:href') == '#rect')
{
$elem.replaceSVGIcon('circle');
} else {
$elem.replaceSVGIcon('rect');
}
};
#icon-container {
visibility: collapse;
display: none;
}
#icon {
height: 40px;
width: 40px;
fill: #454545;
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="icon-container">
<svg xmlns="http://www.w3.org/2000/svg">
<symbol xmlns="http://www.w3.org/2000/svg" id="rect" viewBox="0 0 50 50">
<rect x="15" y="15" width="20" height="20"></rect>
</symbol>
<symbol xmlns="http://www.w3.org/2000/svg" id="circle" viewBox="0 0 50 50">
<circle cx="25" cy="25" r="10"></circle>
</symbol>
</svg>
</div>
<svg id="icon" onclick="clickFunction()">
<rect fill="red" height="40" width="40"></rect>
<use xlink:href="#rect"></use>
</svg>
Why is this happening and is this a known Internet Explorer bug? What are my options to work around this issue?
Yes, this is a known IE bug. https://connect.microsoft.com/IE/feedback/details/796745/mouse-events-are-not-delivered-at-all-anymore-when-inside-an-svg-a-use-is-removed-from-the-dom
If you can, you should set pointer-events: none; for the use tag in your CSS. It's crazy, but it should work.

Categories

Resources