'How to animate svg height with CSS upward?
I am working with a svg element and I want to animate the height increasing upwards of these elements. But they are growing downward from the top probably due to SVG coordinate system. How can I make it go upwards from the bottom?
window.onload = function () {
var x1 = document.querySelector('svg').viewBox.baseVal.height;
var a = document.getElementById('wrapper1');
var bgArray = [];
for (var i = 1; i < a.children.length; i++) {
bgArray.push((a.children[i].getBBox().height / x1) * 100);
};
bgArray.forEach((x, i) => a.children[i + 1].style.setProperty("--h1", x + '%'));
bgArray.forEach((x, i) => a.children[i + 1].style.setProperty("--del", (i + 1) + 's')); //for staggered
}
.r1,
.r2 {
visibility: hidden;
animation: moveHeight 2s ease-in var(--del) 1 forwards;
}
@keyframes moveHeight {
0% {
visibility: visible;
height: 0%;
}
100% {
visibility: visible;
height: var(--h1);
}
}
<!DOCTYPE html>
<html>
<body>
<link rel="stylesheet" href="style.css">
</link>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
<g class="wrapper1" id="wrapper1" >
<rect x="10" y="20" width="120" height="120" stroke="black" fill="none"></rect>
<rect class="r1" id="r1" x="10" y="80" width="20" height="60" stroke="none" fill="orange"></rect>
<rect class="r2" id="r2" x="31" y="100" width="20" height="40" stroke="none" fill="green"></rect>
<!---->
</g>
</svg>
<script src="index.js"></script>
</body>
</html>
Solution 1:[1]
You could draw the bars but cover them and then gradually uncover them.
This covers them by adding white bars and shrinking those.
window.onload = function() {
var x1 = document.querySelector('svg').viewBox.baseVal.height;
var a = document.getElementById('wrapper1');
var bgArray = [];
for (var i = 1; i < a.children.length; i++) {
bgArray.push((a.children[i].getBBox().height / x1) * 100);
};
bgArray.forEach((x, i) => a.children[i + 1].style.setProperty("--h1", x + '%'));
bgArray.forEach((x, i) => a.children[i + 1].style.setProperty("--del", (i + 1) + 's')); //for staggered
}
.shrink {
animation: moveHeight 2s ease-in var(--del) 1 forwards;
}
@keyframes moveHeight {
0% {
height: var(--h1);
}
100% {
height: 0;
}
}
<!DOCTYPE html>
<html>
<body>
<link rel="stylesheet" href="style.css">
</link>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
<g class="wrapper1" id="wrapper1" >
<rect x="10" y="20" width="120" height="120" stroke="black" fill="none"></rect>
<rect class="r1" id="r1" x="10" y="80" width="20" height="60" stroke="none" fill="orange"></rect>
<rect class="r1 shrink" x="10" y="80" width="20" height="60" stroke="none" fill="white"></rect>
<rect class="r2" id="r2" x="31" y="100" width="20" height="40" stroke="none" fill="green"></rect>
<rect class="r2 shrink" x="30" y="99" width="22" height="41" stroke="none" fill="white"></rect>
<!---->
</g>
</svg>
<script src="index.js"></script>
</body>
</html>
Note, at some zoom levels a screen pixel of the underneath bars can be left showing (giving a faint vertical line at the start). To get round that the second white bar has been moved one left and made one wider (and similarly for height). Somewhat hacky so I hope someone can come up with a more straightforward solution.
Solution 2:[2]
Pure svg solution
The idea is to first hide the rectangles behind a masking strip.
Then raise them to the top by animating the y attribute of the rectangle
<animate id="anR1" xlink:href="#r1" attributeName="y" begin="Layer_1.click"
dur="1s" from="140" to="80" repeatCount="1" fill="freeze" />
<!DOCTYPE html>
<html>
<body>
<link rel="stylesheet" href="style.css">
</link>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
<g class="wrapper1" id="wrapper1" >
<rect x="10" y="20" width="120" height="120" stroke="black" fill="none"></rect>
<rect class="r1" id="r1" x="10" y="140" width="20" height="60" stroke="none" fill="orange"></rect>
<rect class="r2" id="r2" x="31" y="140" width="20" height="40" stroke="none" fill="green"></rect>
<rect class="r3" id="r3" x="52" y="140" width="20" height="80" stroke="none" fill="dodgerblue"></rect>
<!-- masking strip -->
<rect x="10" y="140" width="120" height="120" fill="white"></rect>
</g>
<animate id="anR1" xlink:href="#r1" attributeName="y" begin="Layer_1.click" dur="0.5s" from="140" to="80" repeatCount="1" fill="freeze" />
<animate id="anR2" xlink:href="#r2" attributeName="y" begin="anR1.end+0.25s" dur="0.5s" from="140" to="100" repeatCount="1" fill="freeze" />
<animate id="anR3" xlink:href="#r3" attributeName="y" begin="anR2.end+0.25s" dur="0.5s" from="140" to="60" repeatCount="1" fill="freeze" />
</svg>
<script src="index.js"></script>
</body>
</html>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | A Haworth |
| Solution 2 |
