我有一个 SVG 元素,我在页面滚动上制作动画。以下是此类动画的示例:
var path = document.querySelectorAll('path'),
percentScroll;
$(path).each(function(){
this.style.strokeDasharray = this.getTotalLength();
this.style.strokeDashoffset = this.getTotalLength();
});
window.onscroll = function(){
var viewportHeight = $(window).height();
var viewportTopX = $(window).scrollTop();
var viewportBottomX = viewportTopX + viewportHeight;
var elementHeight = $('#content').outerHeight();
var elementTopX = $('#content').offset().top;
var elementBottomX = elementTopX + elementHeight;
var percentScroll = (viewportBottomX - elementTopX) / ((viewportHeight + elementHeight) / 100);
//console.log('%', 1 - percentScroll);
foo = window.pageYOffset / (document.body.offsetHeight - window.innerHeight)
//console.log('window', foo)
$(path).each(function(){
//console.log('math', Math.floor(this.getTotalLength() * (1 - foo)))
this.style.strokeDashoffset = Math.floor(this.getTotalLength() * (1 - foo));
});
};
//прогресс
let x = $('.progress');
$(window).on('scroll',function(){
let st = $(window).scrollTop();
let sa = $(document).height();
let sb = $(window).height();
let dd = Math.ceil(100 * (st / (sa - sb)));
x.css({width : dd + '%'})
})
body {margin: 0; height: 3000px;}
.progress {position: fixed; top: 0; left: 0; width: 0%; height: 5px; background-color: red;}
.progress::after {content: "Крутим вниз"; white-space: nowrap; position: absolute; top: 15px; left: 15px;}
#svg {
position: fixed;
top: 10px;
left: 10px;
}
path {
fill: none;
stroke: black;
stroke-width: 100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="progress"></div><!--прогресс-->
<div id="content">
<svg id="svg" width="280px" height="280px" viewBox="0 0 1046 1280">
<g transform="translate(0,1280) scale(0.1,-0.1)" fill="none" stroke="black" stroke-width="100">
<path class="path" d="M6125 12741 c-387 -139 -597 -254 -908 -495 -233 -181 -331 -236 -422 -236 -17 0 -69 11 -115 24 -115 33 -387 82 -540 97 -236 22 -573 0 -849 -56 -161 -33 -227 -39 -285 -25 -32 7 -108 48 -220 117 -381 238 -783 418 -1165 522 l-74 20 7 -87 c47 -605 193 -1137 396 -1443 l40 -60 -25 -65 c-38 -101 -93 -307 -116 -439 -18 -97 -22 -161 -23 -330 0 -213 11 -317 49 -441 26 -86 51 -79 -277 -76 -331 4 -697 -10 -1025 -38 -215 -19 -564 -59 -572 -66 -2 -2 -1 -9 2 -17 4 -11 27 -10 138 4 476 63 1214 101 1600 84 l167 -7 36 -87 c20 -47 55 -121 80 -163 l43 -77 -36 -5 c-20 -3 -92 -13 -161 -21 -513 -65 -1082 -183 -1506 -315 -194 -59 -234 -76 -234 -95 0 -8 1 -15 3 -15 2 0 57 18 122 40 266 90 566 168 900 234 276 55 413 76 891 141 l41 6 58 -77 c31 -42 88 -109 126 -149 l69 -72 -118 -43 c-265 -97 -648 -277 -882 -415 -179 -105 -370 -235 -370 -251 0 -8 4 -14 9 -14 4 0 69 40 142 89 339 225 742 426 1156 577 l93 33 93 -94 c214 -215 287 -380 287 -652 0 -260 -53 -544 -204 -1093 -70 -254 -124 -480 -156 -652 -157 -835 -108 -1553 159 -2358 89 -266 155 -431 312 -782 274 -611 310 -727 354 -1146 22 -205 36 -683 33 -1072 l-3 -345 -88 -7 c-109 -8 -232 -32 -290 -57 -66 -28 -111 -73 -143 -143 -26 -56 -29 -74 -29 -158 0 -74 4 -103 19 -129 67 -123 257 -196 611 -235 1310 -143 2603 -163 3865 -61 684 56 1558 169 1680 218 349 141 670 737 925 1721 185 712 354 1713 371 2201 24 650 -166 1275 -569 1880 -207 310 -356 484 -807 940 -477 483 -631 662 -805 935 -143 224 -273 537 -311 747 -35 198 -28 460 18 673 47 221 145 445 262 601 203 269 554 486 916 565 66 15 125 19 260 18 157 0 185 -3 274 -27 228 -61 359 -160 386 -292 26 -124 -55 -283 -190 -373 -135 -91 -278 -109 -464 -59 -131 35 -183 41 -236 27 -75 -19 -115 -52 -150 -124 -30 -61 -32 -71 -28 -144 6 -97 36 -158 119 -238 71 -67 209 -135 321 -158 99 -20 253 -20 358 0 267 50 581 244 737 454 209 281 260 673 133 1013 -70 186 -311 431 -525 533 -206 98 -593 140 -925 99 -549 -68 -1041 -298 -1400 -654 -243 -242 -405 -492 -496 -769 l-37 -113 -56 6 c-135 13 -486 25 -753 25 -271 0 -289 1 -284 18 44 150 60 274 60 457 0 244 -33 410 -129 650 l-44 109 49 66 c252 342 406 715 456 1103 22 176 12 628 -15 627 -3 -1 -78 -27 -166 -59z m709 -3021 c88 -6 161 -11 162 -13 1 -1 -6 -42 -17 -92 -25 -119 -49 -305 -49 -377 0 -32 -3 -58 -6 -58 -3 0 -63 13 -132 29 -251 58 -593 119 -872 156 -69 9 -135 18 -147 21 -21 4 -20 8 32 117 29 61 61 138 71 169 18 53 21 57 54 62 57 7 732 -3 904 -14z m-604 -436 c173 -28 390 -71 666 -131 20 -5 21 -13 28 -166 27 -621 177 -1043 583 -1650 253 -378 580 -768 1023 -1222 273 -279 343 -357 438 -484 238 -315 387 -652 453 -1019 72 -406 36 -1045 -97 -1712 -160 -804 -476 -1596 -709 -1772 -91 -69 -196 -83 -285 -38 -126 65 -154 220 -111 605 12 105 37 318 56 475 62 523 75 690 75 955 0 641 -136 1169 -474 1844 -344 687 -592 1023 -1179 1597 -293 287 -426 407 -721 653 -143 120 -297 251 -340 292 -240 224 -359 512 -373 899 -4 114 -2 159 11 210 21 86 73 186 148 288 54 75 64 83 87 79 46 -10 341 -136 516 -222 207 -101 374 -196 564 -322 107 -71 146 -92 154 -84 8 8 8 14 2 19 -364 252 -809 488 -1172 621 -40 15 -60 27 -56 35 4 6 41 61 84 121 42 61 88 131 103 156 l26 46 143 -19 c78 -10 239 -34 357 -54z"/>
</g>
</svg>
</div>
在此示例中,SVG 元素包含一个补丁 ( path),但很明显,绘图不是从起点到其路径的终点,而是同时在不同的位置。为什么会发生这种情况,它取决于什么?是否可以将一个补丁的公式分解为多个部分并调整它们的绘制顺序?对在加载文档和滚动页面时执行此类动画感兴趣。还对两种实现的详细描述感兴趣。
如果仔细查看路径公式,您会注意到命令是重复的
zm,这意味着一个子补丁的结束z和第二个子补丁的开始m(moveto)。SVG 预处理器
moveto并行执行命令,就像一次用几支笔进行绘制一样。因此,会出现一些不愉快的细微差别。让我用另一个更典型的例子来解释:
假设时间已定
dur="10s",实际上动画仅持续4 сек。其余时间什么都没有发生。如果第一个动画应该跟在第二个动画之后,那么两个动画6сек之间会有一个相等的停顿。不提供应用程序开发人员的暂停,并且在画线结束后是非常不希望的。这是一个相当普遍的效果。用什么动画实现并不重要:Smil SVG 或 GSAP,或者在另一个 JS 框架中,到处都可以观察到停顿。在下面的示例中,如果您使用
getTotalLength(),则将显示所有子补丁的总长度 -4987px在上面的示例中,可以清楚地观察到这种效果 - 绘制线条之后,在第二个动画开始之前有一个暂停 - 绘画。
如果我们将每个子补丁转换为自制补丁并用 测量每个子补丁的长度
getTotalLength(),我们得到:总之
4987px,就像上面的片段一样10s因此,给定的动画时间与动画的实际持续时间之间存在差异的原因就很清楚了4s。绘制动画同时进行 4 行,整个动画在最长的补丁绘制完成后结束
1834px。只需 4 秒。此外,其余的6s都没有发生任何事情(暂停),因为所有内容都已绘制完毕。解决方案很明显:
选择最长的子补丁 -
1834px- 这是形状的外轮廓,并将其值代入动画命令stroke-dashoffset最长的子补丁将被绘制,颜色填充动画将不间断地开始:但是如果有很多补丁,那么选择其中最长的一个是非常不方便和费力的。
为了自动执行查找和打印最长路径的任务,@Grundy♦创建了一个非常有用的脚本: