如何使用 CSS 向上设置 svg 高度的动画?
How to animate svg height with CSS upward?
我正在使用 svg 元素,我想为这些元素向上增加的高度设置动画。但它们从顶部向下生长可能是由于 SVG 坐标系。我怎样才能让它从底部向上移动?
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>
你可以画条,但先盖住它们,然后逐渐揭开它们。
这通过添加白色条并缩小它们来覆盖它们。
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>
请注意,在某些缩放级别下,下方栏的屏幕像素可以保留显示(在开始时给出一条微弱的垂直线)。为了解决这个问题,第二个白色条已向左移动一格并变宽一格(高度也类似)。有点hacky所以我希望有人能想出一个更直接的解决方案。
我研究了这个精彩的 ,但我无法想象它并使其适应我的场景。所以弄明白之后,我就是在尝试形象化的解释和展示如何适配不同的场景。
基本标记如下
<!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">
<rect class="wrapper1" id="wrapper1" x="10" y="345" width="120" height="180" stroke="teal" fill="none"></rect>
<line class="upper clone" x1="10" y1="80" x2="220" y2="80" style="stroke:rgb(110, 31, 194);stroke-width:1" />
<g class="elements">
<line class="upper" x1="10" y1="80" x2="220" y2="80" style="stroke:rgb(87, 202, 91);stroke-width:1"/>
<rect class="r0" id="r0" x="10" y="80" width="83" height="180" stroke="brown" 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="80" width="20" height="10" stroke="none" fill="green"></rect>
<rect class="r3" id="r3" x="52" y="80" width="20" height="100" stroke="none" fill="blue"></rect>
<rect class="r4" id="r4" x="73" y="80" width="20" height="140" stroke="none" fill="magenta"></rect>
<line class="lower" x1="10" y1="260" x2="220" y2="260" style="stroke:rgb(87, 202, 91);stroke-width:1"/>
</g>
<line class="lower clone" x1="10" y1="260" x2="220" y2="260" style="stroke:rgb(218, 149, 22);stroke-width:1" />
<g class="wrapper2" id="wrapper2">
<rect x="140" y="0" width="50" height="700" stroke="red" fill="none"></rect>
</g>
</svg>
<script src="index2.js"></script>
</body>
</html>
为了便于理解,我创建了名为upper and lower
的两行,它们是所有rects
的开始和结束。我还克隆了那些 transform
不适用的行。
将svg坐标系转换为笛卡尔坐标系的经验法则是
使用这个 transform="translate(0, maxY) scale(1, -1)".
maxY
实际上是max total of (y+height)
。在本例中为 260。现在可以操纵此值以在动画之前正确放置矩形
<g class="elements" transform="translate(0,260) scale(1, -1)">
职位
<g class="elements" transform="translate(0,340) scale(1, -1)"> 260+rectY(80)=340
职位
<g class="elements" transform="translate(0,425) scale(1, -1)"> 260+rectY(80)+(wrapperY 345 -260)
职位
最后定位在包装纸的底部
<g class="elements" transform="translate(0,605) scale(1, -1)"> 260+rectY(80)+(wrapperY 345 -260)+wrapperHeight 180 = 605
将所有内容与 javascript 和 css
放在一起
//converting svg coordinates to cartesian coordinates
// transform="translate(0, maxY) scale(1, -1)".
// or transform="scale(1, -1) translate(0, -maxY)".
window.onload = function app() {
var bgArray1 = []; //to collect only height
var bgArray2 = []; //to collect height + y
var wrapperElement = document.getElementById('wrapper1');
var wrapperY = wrapperElement.getBBox().y //what is the y coordinate of wrapper rect
var wrapperHeight = wrapperElement.getBBox().height;
var getRect = document.querySelectorAll('[class^="r"]');
for (var i = 0; i < getRect.length; i++) {
var _bBox = getRect[i].getBBox(); // getting the bBox for each rect
var _height = _bBox.height + _bBox.y //getting each rect's height
var _y = _bBox.y // getting each rect's y coordinate
var _heightAndY = _height + _y //total of Y+height of each rect
bgArray1.push(_height);
bgArray2.push(_heightAndY);
}
var _maxHeight = Math.max(...bgArray1); // use this if you want to position the rect at (y=0)
var _maxTotal = Math.max(...bgArray2); // use this if you want to position the rect at (y=0)
var _wrapperTop = _maxTotal + (wrapperY - _maxHeight); //use this if you want to postion the rect at the the
//top of the wrapper
var _wrapperBottom = _wrapperTop + wrapperHeight //use this if you wantto position the rects at the
//bottom of the wrapper
bgArray1.forEach((x, i) => getRect[i].setAttribute("transform", `translate(0,${_wrapperBottom}) scale(1,-1)`));
bgArray1.forEach((x, i) => getRect[i].style.setProperty("--del", (i + 1) + 's'))
}
[class^="r"] {
visibility: hidden;
animation: moveHeight 2s ease-out var(--del) 1 forwards;
}
@keyframes moveHeight {
0% {
visibility: visible;
height: 0
}
100% {
visibility: visible;
height: 100;
}
}
<!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">
<rect class="wrapper1" id="wrapper1" x="10" y="345" width="120" height="180" stroke="teal" fill="none"></rect>
<line class="upper clone" x1="10" y1="80" x2="220" y2="80" style="stroke:rgb(110, 31, 194);stroke-width:1" />
<g>
<line class="upper" x1="10" y1="80" x2="220" y2="80" style="stroke:rgb(87, 202, 91);stroke-width:1"/>
<rect class="r0" id="r0" x="10" y="80" width="83" height="180" stroke="brown" 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="80" width="20" height="10" stroke="none" fill="green"></rect>
<rect class="r3" id="r3" x="52" y="80" width="20" height="100" stroke="none" fill="blue"></rect>
<rect class="r4" id="r4" x="73" y="80" width="20" height="140" stroke="none" fill="magenta"></rect>
<line class="lower" x1="10" y1="260" x2="220" y2="260" style="stroke:rgb(87, 202, 91);stroke-width:1"/>
</g>
<line class="lower clone" x1="10" y1="260" x2="220" y2="260" style="stroke:rgb(218, 149, 22);stroke-width:1" />
<g class="wrapper2" id="wrapper2">
<rect x="140" y="0" width="50" height="700" stroke="red" fill="none"></rect>
</g>
</svg>
<!--<script src="index.js"></script>-->
<script src="index2.js"></script>
</body>
</html>
纯svg解决方案
想法是先将矩形隐藏在遮蔽条后面。
然后通过动画矩形的 y
属性将它们提升到顶部
<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>
我正在使用 svg 元素,我想为这些元素向上增加的高度设置动画。但它们从顶部向下生长可能是由于 SVG 坐标系。我怎样才能让它从底部向上移动?
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>
你可以画条,但先盖住它们,然后逐渐揭开它们。
这通过添加白色条并缩小它们来覆盖它们。
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>
请注意,在某些缩放级别下,下方栏的屏幕像素可以保留显示(在开始时给出一条微弱的垂直线)。为了解决这个问题,第二个白色条已向左移动一格并变宽一格(高度也类似)。有点hacky所以我希望有人能想出一个更直接的解决方案。
我研究了这个精彩的
基本标记如下
<!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">
<rect class="wrapper1" id="wrapper1" x="10" y="345" width="120" height="180" stroke="teal" fill="none"></rect>
<line class="upper clone" x1="10" y1="80" x2="220" y2="80" style="stroke:rgb(110, 31, 194);stroke-width:1" />
<g class="elements">
<line class="upper" x1="10" y1="80" x2="220" y2="80" style="stroke:rgb(87, 202, 91);stroke-width:1"/>
<rect class="r0" id="r0" x="10" y="80" width="83" height="180" stroke="brown" 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="80" width="20" height="10" stroke="none" fill="green"></rect>
<rect class="r3" id="r3" x="52" y="80" width="20" height="100" stroke="none" fill="blue"></rect>
<rect class="r4" id="r4" x="73" y="80" width="20" height="140" stroke="none" fill="magenta"></rect>
<line class="lower" x1="10" y1="260" x2="220" y2="260" style="stroke:rgb(87, 202, 91);stroke-width:1"/>
</g>
<line class="lower clone" x1="10" y1="260" x2="220" y2="260" style="stroke:rgb(218, 149, 22);stroke-width:1" />
<g class="wrapper2" id="wrapper2">
<rect x="140" y="0" width="50" height="700" stroke="red" fill="none"></rect>
</g>
</svg>
<script src="index2.js"></script>
</body>
</html>
为了便于理解,我创建了名为upper and lower
的两行,它们是所有rects
的开始和结束。我还克隆了那些 transform
不适用的行。
将svg坐标系转换为笛卡尔坐标系的经验法则是
使用这个 transform="translate(0, maxY) scale(1, -1)".
maxY
实际上是max total of (y+height)
。在本例中为 260。现在可以操纵此值以在动画之前正确放置矩形
<g class="elements" transform="translate(0,260) scale(1, -1)">
职位
<g class="elements" transform="translate(0,340) scale(1, -1)"> 260+rectY(80)=340
职位
<g class="elements" transform="translate(0,425) scale(1, -1)"> 260+rectY(80)+(wrapperY 345 -260)
职位
最后定位在包装纸的底部
<g class="elements" transform="translate(0,605) scale(1, -1)"> 260+rectY(80)+(wrapperY 345 -260)+wrapperHeight 180 = 605
将所有内容与 javascript 和 css
放在一起//converting svg coordinates to cartesian coordinates
// transform="translate(0, maxY) scale(1, -1)".
// or transform="scale(1, -1) translate(0, -maxY)".
window.onload = function app() {
var bgArray1 = []; //to collect only height
var bgArray2 = []; //to collect height + y
var wrapperElement = document.getElementById('wrapper1');
var wrapperY = wrapperElement.getBBox().y //what is the y coordinate of wrapper rect
var wrapperHeight = wrapperElement.getBBox().height;
var getRect = document.querySelectorAll('[class^="r"]');
for (var i = 0; i < getRect.length; i++) {
var _bBox = getRect[i].getBBox(); // getting the bBox for each rect
var _height = _bBox.height + _bBox.y //getting each rect's height
var _y = _bBox.y // getting each rect's y coordinate
var _heightAndY = _height + _y //total of Y+height of each rect
bgArray1.push(_height);
bgArray2.push(_heightAndY);
}
var _maxHeight = Math.max(...bgArray1); // use this if you want to position the rect at (y=0)
var _maxTotal = Math.max(...bgArray2); // use this if you want to position the rect at (y=0)
var _wrapperTop = _maxTotal + (wrapperY - _maxHeight); //use this if you want to postion the rect at the the
//top of the wrapper
var _wrapperBottom = _wrapperTop + wrapperHeight //use this if you wantto position the rects at the
//bottom of the wrapper
bgArray1.forEach((x, i) => getRect[i].setAttribute("transform", `translate(0,${_wrapperBottom}) scale(1,-1)`));
bgArray1.forEach((x, i) => getRect[i].style.setProperty("--del", (i + 1) + 's'))
}
[class^="r"] {
visibility: hidden;
animation: moveHeight 2s ease-out var(--del) 1 forwards;
}
@keyframes moveHeight {
0% {
visibility: visible;
height: 0
}
100% {
visibility: visible;
height: 100;
}
}
<!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">
<rect class="wrapper1" id="wrapper1" x="10" y="345" width="120" height="180" stroke="teal" fill="none"></rect>
<line class="upper clone" x1="10" y1="80" x2="220" y2="80" style="stroke:rgb(110, 31, 194);stroke-width:1" />
<g>
<line class="upper" x1="10" y1="80" x2="220" y2="80" style="stroke:rgb(87, 202, 91);stroke-width:1"/>
<rect class="r0" id="r0" x="10" y="80" width="83" height="180" stroke="brown" 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="80" width="20" height="10" stroke="none" fill="green"></rect>
<rect class="r3" id="r3" x="52" y="80" width="20" height="100" stroke="none" fill="blue"></rect>
<rect class="r4" id="r4" x="73" y="80" width="20" height="140" stroke="none" fill="magenta"></rect>
<line class="lower" x1="10" y1="260" x2="220" y2="260" style="stroke:rgb(87, 202, 91);stroke-width:1"/>
</g>
<line class="lower clone" x1="10" y1="260" x2="220" y2="260" style="stroke:rgb(218, 149, 22);stroke-width:1" />
<g class="wrapper2" id="wrapper2">
<rect x="140" y="0" width="50" height="700" stroke="red" fill="none"></rect>
</g>
</svg>
<!--<script src="index.js"></script>-->
<script src="index2.js"></script>
</body>
</html>
纯svg解决方案
想法是先将矩形隐藏在遮蔽条后面。
然后通过动画矩形的 y
属性将它们提升到顶部
<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>