ScrollMagic, reverse z-index order - javascript

I'm using scrollmagic to tween svg clippaths as you scroll. Usually with svgs(or divs or sections or whatever) the last thing you specify in your html is on top in terms of z-index, but you change that in css. I tried to do this with my svgs, so that while the first svg tweens, the other one scrolls up behind it. It seems like scrollmagic is preventing my z-indexing from working though. Any ideas?
http://codepen.io/kathryncrawford/pen/BoXOMJ
<div id="scene">
<svg id="svg1" height="500" width="800">
<image id="img1" xlink:href="http://placecage.com/800/500" x="0" y="0" width="800" height="500"/>
<defs>
<clipPath id="clip1">
<circle id="circle1" stroke="#000000" stroke-miterlimit="10" cx="400" cy="300" r="300" />
</clipPath>
</defs>
</svg>
</div>
<div id="scene2">
<svg id="svg2" height="500" width="800">
<image id="img2" xlink:href="http://fillmurray.com/800/500" x="0" y="0" width="800" height="500"/>
<defs>
<clipPath id="clip2">
<circle id="circle2" stroke="#000000" stroke-miterlimit="10" cx="400" cy="300" r="300" />
</clipPath>
</defs>
</svg>
</div>
CSS
#img1 {
clip-path: url(#clip1);
}
#img2 {
clip-path: url(#clip2);
}
#svg1, #circle1{
z-index: 2;
}
#svg2, #circle2{
z-index: 1;
}

Crap, I literally just figured it out after posting this. I changed the z-index css declaration to the z-index on the scene divs that wrap the svgs. That worked.
http://codepen.io/kathryncrawford/pen/BoXOMJ
#scene{
z-index: 2;
}
#scene2{
z-index: 1;
}

Related

How to change CSS class to an <use> children inside a SVG?

I am making and animation the objetive is change the xlink:href inside a SVG. (this is for change a shape), and change class respect to their position inside.
This is my SVG
<svg viewBox="-20 -20 600 200" id="main">
<defs id="test">
<rect width="80" height="80" id="circle" fill="red" class="first" />
<rect width="80" height="80" id="square" fill="pink" class="second" />
<rect width="80" height="80" id="cross" fill="blue" class="third" />
</defs>
<g id="load-area">
<use x="0" xlink:href="#circle" />
<use x="100" xlink:href="#square" />
<use x="200" xlink:href="#cross" />
</g>
</svg>
The class in every rectelement, has a different animation-delay according to position (first execute at 0s, second at 2s, third at 4s and so on).
With JS I change every <use> at #load-area
main.children['load-area'].children[0].setAttribute("xlink:href", getFigure(random()));
And it works, the shape changes but, suppose when it gets three times the id #cross then all elements have third CSS class.
I need change CSS class inside every children of <use>, How can I do that?
Below an element tree :
I get all <use> with: main.children['load-area'].children but it does not have child element, as I show u below:
You can solve this using CSS variables that you combine with nth-child selector and you no more need the classes.
Here is a basic example
rect {
animation:change 3s var(--d,0s) infinite;
}
#keyframes change {
0% {
opacity:1;
}
33%,100% {
opacity:0;
}
}
#load-area > use:nth-child(1) {--d:0s}
#load-area > use:nth-child(2) {--d:1s}
#load-area > use:nth-child(3) {--d:2s}
/*#load-area > use:nth-child(N) {--d:Xs}*/
<svg viewBox="-20 -20 600 200" id="main">
<defs id="test">
<rect width="80" height="80" id="circle" fill="red" />
<rect width="80" height="80" id="square" fill="pink" />
<rect width="80" height="80" id="cross" fill="blue" />
</defs>
<g id="load-area">
<use x="0" xlink:href="#circle" />
<use x="100" xlink:href="#square" />
<use x="200" xlink:href="#cross" />
</g>
</svg>
<svg viewBox="-20 -20 600 200" id="main">
<g id="load-area">
<use x="0" xlink:href="#square" />
<use x="100" xlink:href="#circle" />
<use x="200" xlink:href="#cross" />
</g>
</svg>
If the number is unknown or very big you can easily use a JS loop:
var e = document.querySelectorAll('#load-area use');
for(var i=0;i<e.length;i++) {
e[i].style.setProperty('--d',i+"s");
}
rect {
animation:change 3s var(--d,0s) infinite;
}
#keyframes change {
0% {
opacity:1;
}
33%,100% {
opacity:0;
}
}
<svg viewBox="-20 -20 600 200" id="main">
<defs id="test">
<rect width="80" height="80" id="circle" fill="red" />
<rect width="80" height="80" id="square" fill="pink" />
<rect width="80" height="80" id="cross" fill="blue" />
</defs>
<g id="load-area">
<use x="0" xlink:href="#circle" />
<use x="100" xlink:href="#square" />
<use x="200" xlink:href="#cross" />
</g>
</svg>
document.getElementsByTagName("use")[0].setAttribute("xlink:href", "#circle");
element.setAttribute(attributename, attributevalue)
Here is how you can change element attributes

Center elements inside SVG relative to each other-

Couldn't find it anywhere else to I might ask here :
I have svg rectangle which inside has other rectangles.
What I want to achieve is to center each of these rectangles in the centre of it's parent and in relation to each other.
If I drag rectangle 1 down I want the other one to move up to keep both of them centered - and same thing happening if I drag the other element down (should push upper one up).
Problem here is that I might have different width/heights and there would be 2 or more elements. Is there any mathematical equationfor that? Or a name that I can look for?
I would put the 3 rects inside a group and use the group as in the following example
svg{
border:1px solid;
width: 30vh;
}
<svg viewBox="0 0 100 280">
<defs>
<g id="rects">
<rect width="80" height="80" />
<rect width="60" height="25" x="10" y="10" />
<rect width="60" height="25" x="10" y="45" />
</g>
</defs>
<use xlink:href="#rects" x="10" y="10" stroke="black" fill="none" />
<use xlink:href="#rects" x="10" y="100" stroke="black" fill="none" />
<use xlink:href="#rects" x="10" y="190" stroke="black" fill="none" />
</svg>

Making inline SVG responsive in browsers without using javascript?

I've been reviewing articles like this one which are really good, but possibly dated, and I'm wondering if any progress has been made on a simple way to make inline svg responsive while maintaining the aspect ratio?
In other words if we have svg with a 1:1 aspect ratio inside a div container, and the container shrinks from 400x400px to 200x200 px, then the view box width and height parameters double.
I am confused about what you want. I don't know what you mean, in your question, when you talk about "view box width and height parameters double". Perhaps you are confused about how viewBox works.
As long as the SVG has a viewBox it should be responsive.
In the following example, I've put the SVG in a div container and animated the container size to simulate the page size changing.
#container {
width: 200px;
background: linen;
animation: scale 1s alternate infinite;
}
#keyframes scale {
from { width: 200px; }
to { width: 100px; }
}
<div id="container">
<svg viewBox="0 0 100 100">
<circle cx="50" cy="50" r="40" fill="gold"/>
<rect x="10" y="50" width="20" height="50" fill="gold"/>
<rect x="70" y="50" width="20" height="50" fill="gold"/>
<circle cx="35" cy="45" r="5"/>
<circle cx="65" cy="45" r="5"/>
</svg>
</div>
But it could just as easily be a container that is the width of the page. Try running the following snippet. Then click "Fullpage" and resize the browser window.:
#container {
width: 100%;
background: linen;
}
<div id="container">
<svg viewBox="0 0 100 100">
<circle cx="50" cy="50" r="40" fill="gold"/>
<rect x="10" y="50" width="20" height="50" fill="gold"/>
<rect x="70" y="50" width="20" height="50" fill="gold"/>
<circle cx="35" cy="45" r="5"/>
<circle cx="65" cy="45" r="5"/>
</svg>
</div>
If you don't need to change svg with css or modify it, I suggest you to use it as an img element. You create an img and put the path to your svg in the src. Here's what I mean: https://codepen.io/tlemaitre/pen/PBKGOo
I've recently had a similar problem, I have a container that needs to be preserveAspectRatio="none" to keep the shape fluid on different window sizes but the image inside gets gets distorted. I've not seen any solution to this problem with or without JS, so I don't think it's possible.

Hover events for a dashed line in an SVG

An SVG with a line (or path) which uses stroke-dasharray only seems to trigger CSS and JS hover events when the user hovers over the solid parts of the dashed line: https://codepen.io/anon/pen/YeXoZy
Is there a simple way to make both the JS and CSS events trigger when the solid or invisible parts of the line are hovered?
My current plan is to draw a second, invisible line following the same path and use it to detect mouse events. https://codepen.io/anon/pen/BYNgRR This seems heavy handed and I'm hoping there's a cleaner way I'm missing.
I'm not sure how to do it without the second "detector" line, but a less heavy handed way is at least possible without the JS.
Switch the order of the lines, then you can use the hover selector as usual for the dashed line, then use + in a selector for the detector line to change the properties of the line immediately following it:
https://codepen.io/RyanGoree/pen/LQVKBV
This can be solved somewhat by using a rect instead of line and using SVG transforms with patterns.
An example can be seen at this CodePen.
It essentially bubbles down to:
<svg height="210" width="500">
<defs>
<pattern id="pattern1"
width="10" height="10"
patternUnits="userSpaceOnUse"
patternTransform="rotate(0 60 60)">
<line stroke="green" stroke-width="12px" y2="10"/>
</pattern>
<pattern id="pattern2"
width="10" height="10"
patternUnits="userSpaceOnUse"
patternTransform="rotate(0 60 60)">
<line stroke="red" stroke-width="12px" y2="10" stroke="transparent"/>
</pattern>
</defs>
<g transform="rotate(45 60 60)">
<rect x="0" y="0" width="500" height="5"/>
</g>
</svg>
And the following CSS:
rect {
fill: url(#pattern1)
}
rect:hover {
fill: url(#pattern2)
}
This is an old topic I know. But found the answer on Css hover sometimes doesn't work on svg paths
If you want to trigger the event only on stroke/visible, use pointer-events: stroke; or pointer-events: visible; (only the stroke) and pointer-events: all; (on both)
Here is a code example:
<body>
<div id="donut-score" class="svg-item" style="display: block;">
<svg width="100%" height="100%" viewBox="0 0 40 40" class="donut">
<circle class="donut-hole" cx="20" cy="20" r="15.91549430918954" fill="#fff"></circle>
<circle class="donut-ring" cx="20" cy="20" r="15.91549430918954" fill="transparent" stroke-width="3.5"></circle>
<circle id="donut-score-part-1" class="donut-segment donut-segment-1" onmousemove="this.style.stroke ='orange';" onmouseout="this.style.stroke = '#ff8197';" cx="20" cy="20" r="15.91549430918954" fill="transparent" stroke-width="3.5" stroke-dasharray="20 80" stroke-dashoffset="25"></circle>
<g class="donut-text-item donut-text-item">
<text y="50%" transform="translate(0, 2)">
<tspan id="donut-score-text" x="50%" text-anchor="middle" class="donut-text">Score </tspan>
<tspan id="donut-score-aantal" x="50%" Y="65%" text-anchor="middle" class="donut-text">0 </tspan>
</text>
</g>
</svg>
</div>
</body>
ccs:
.donut-segment {
stroke: #ff8197;
}
.svg-item {
width:200px;
font-size: 16px;
margin: 0 auto;
}
.donut-text {
font-size: 0.35em;
line-height: 1;
transform: translateY(0.5em);
font-weight: bold;
}
If you add pointer-events: stroke; to the class .donut-segment then it only works on the stroke. If you use non or pointer-events: all it works on both. I tested it in codepen.

Can't change SVG rect properties in three containers

After several tries, and code changes, I am unable to make rectangle inside SVG to change his position - don't even ask for animating. Obviously using jQuery SVG plugin plus animation extension.
The problem: A SVGs wrapped inside three <div>, an inside y have a rectangle that need to be at y:0 after the document loads. And this is the code:
var rect = jQuery('div.post-image').children('svg').svg().svg('get');
jQuery(rect).each(function(){
jQuery(this).change('.b1', {y:0});
});
Well, nothing happens with the rectangle, it keeps the original coordinate. Chrome console doesn't says anything either.
Added: the HTML in question
<a href="#" class="post-image" title="title">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="250" height="140" viewBox="0,0,250,140" overflow="hidden">
<switch>
<g>
<defs>
<filter id="innershadow">
<feOffset dx="0" dy="0"></feOffset>
<feGaussianBlur stdDeviation="7" result="offset-blur"></feGaussianBlur>
<feComposite operator="out" in="SourceGraphic" in2="offset-blur" result="inverse"></feComposite>
<feFlood flood-color="#000" flood-opacity="0.3" result="color"></feFlood>
<feComposite operator="in" in="color" in2="inverse" result="shadow"></feComposite>
<feComposite operator="over" in="shadow" in2="SourceGraphic"></feComposite>
</filter>
<pattern xmlns="http://www.w3.org/2000/svg" id="image-771" patternUnits="userSpaceOnUse" width="250" height="202">
<image href="example-310x250.jpg" xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="250" height="202"></image>
</pattern>
<clipPath id="clip">
<polygon points="0,0 235,0 250,70 235,140 0,140 15,70"></polygon>
</clipPath>
</defs>
<polygon points="0,0 235,0 250,70 235,140 0,140 15,70" style="fill: url(#image-771); filter:url(#innershadow);"></polygon>
<rect class="b1" width="100%" height="100%" style="fill:rgb(0,92,148); opacity: 0.9;" clip-path="url(#clip)" x="0" y="98"></rect>
<rect class="b2" width="60" height="25" style="fill:rgb(0,92,148); opacity: 0.9;" clip-path="url(#clip)" x="190" y="0"></rect>
<rect class="b3" width="100" height="25" style="fill:rgb(0,0,0); opacity: 0.75;" clip-path="url(#clip)" x="0" y="0"></rect>
</g>
<foreignObject width="250" height="140">
<img width="250" height="125" src="example-fallback.jpg" alt="example" title="title"> </foreignObject>
</switch>
</svg>
</a>
I'm willing to use <canvas> for this, but I don't know what are the outcomes.
Found out what wast the problem:
var rect = jQuery('a.post-image').children('svg').find('.b2, .b3');
jQuery(rect).each(function(){
jQuery(this).attr('y','-25');
});
Done, and without a plugin. Okey, not the best way (find instead of most direct selector), but it will cut it.

Categories