滚动侦听器描边 dashoffset 在像素范围之间绘制 SVG?
Scroll listener stroke dashoffset draw SVG between range of pixels?
我真的很难过,所以我想看看这里是否有人能够帮助我考虑一下。
我正在尝试将滚动侦听器附加到特定像素范围之间的 SVG 路径,因此当您上下滚动时它会来回绘制。
我这几天一直在研究这个问题,我发现了关于将笔画 dashoffset 进度转换为基于 window 顶部或文档高度的百分比的主题作为单个数字,但我似乎无法理解如何将相同的逻辑应用于指定的像素范围。
我如何让 svg 路径的 stroke-dasharray 处于像素范围开始处的起始值 (3000)(比如从文档顶部开始的 2500px 到 3000px。)和结束值笔划 dasharray 的像素范围末尾为 6000(它的最终值)?我真的希望这不是一个我盯着看太久的愚蠢简单的问题。这是我拥有的:
var path = document.querySelector('path');
var length = path.getTotalLength();
var triggerPadding = 600;
var startLocation = document.querySelector('.scroll-container').getBoundingClientRect()
var bodyRect = document.body.getBoundingClientRect();
var elemRect = document.querySelector('.scroll-container').getBoundingClientRect();
var elementYLocation = elemRect.top - bodyRect.top;
var elementBottomYLocation = Math.round((elemRect.bottom - bodyRect.top) - triggerPadding);
var startTrigger = Math.round(elementYLocation - triggerPadding);
path.style.strokeDasharray = length + ' ' + length;
path.style.strokeDashoffset = length;
//
function animationScroll(currentY, startY, endY) {
console.log({ currentY, startY, endY })
if (currentY >= startY) {
//do animation
}
}
window.addEventListener('scroll', function () {
const currentY = window.pageYOffset || window.scrollY;
animationScroll(currentY, startTrigger, elementBottomYLocation);
}, false);
对于我需要执行此操作的方程式的任何帮助,我们将不胜感激。提前谢谢你。
用户@CBroe 回答并provides/walks通过所需的公式计算两个数字范围的线性变换。
f(t) = c + ( (d - c) / (b - a) ) * (t - a);
您需要计算 scrollRatio
,然后将其乘以您想要制作动画的 svg 属性 的所需范围。
下面,我举例说明了等待某个元素进入视口,然后开始动画,执行与滚动同步的动画关键帧,并在元素离开视口后停止动画。
const triggerEl = document.getElementById('trigger');
const animateSvg = () => {
const rect = triggerEl.getBoundingClientRect();
const scrollPosition = window.scrollY;
let scrollRatio = (rect.top / window.innerHeight);
scrollRatio = Math.max(scrollRatio, 0);
scrollRatio = Math.min(scrollRatio, 1);
triggerEl.innerHTML = `Trigger Element ${(scrollRatio * 100).toFixed(2)}%`;
for (const path of document.querySelectorAll('svg path')) {
// Min & Max can be hardcoded to fit your use-case
const dashOffsetMin = 0;
const dashOffsetMax = path.getTotalLength();
const dashOffsetRange = dashOffsetMax
- dashOffsetMin;
// Set stroke-dashoffset
path.style.strokeDashoffset = dashOffsetMin
+ dashOffsetRange * scrollRatio;
}
}
animateSvg();
document.addEventListener('scroll', animateSvg)
body {
position: relative;
background:linear-gradient(135deg, #5b247a 0%,#1bcedf 100%);
min-height: 300vh;
}
h1 {
font-family: arial;
font-weight: 900;
color: white;
width: 100%;
text-align: center;
}
svg {
position: fixed;
top: 0;
color: white;
}
svg path {
transition: stroke-dashoffset 250ms linear;
box-shadow: 0px 0px 15px white;
}
#trigger {
position: absolute;
z-index: 2;
top: 100vh;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-family: arial;
font-weight: 900;
height: 20vh;
background: linear-gradient(to bottom right, rgba(0,0,25,0.2), rgba(0,0,25,0.5));
border-radius: 5px;
backdrop-filter: blur(5px);
box-shadow: 0px 15px 10px -10px rgba(0,0,0,0.4);
}
<div id='trigger'>
Trigger Element
</div>
<h1>Scroll!</h1>
<svg viewBox="0 0 280 100">
<g fill="none" fill-rule="evenodd" stroke="currentColor" stroke-width="1" class="lines">
<path class="el" d="M58 80V50.12C57.7 41.6 51.14 35 43 35a15 15 0 0 0 0 30h7.5v15H43a30 30 0 1 1 0-60c16.42 0 29.5 13.23 30 29.89V80H58z" style="stroke-dashoffset: 0px;" stroke-dasharray="316.85528564453125"></path>
<path class="el" d="M73 80V20H58v60h15z" style="stroke-dashoffset: 0px;" stroke-dasharray="150"></path>
<path class="el" d="M58 80V49.77C58.5 33.23 71.58 20 88 20a30 30 0 0 1 30 30v30h-15V50a15 15 0 0 0-15-15c-8.14 0-14.7 6.6-15 15.12V80H58zm75 0V20h-15v60h15z" style="stroke-dashoffset: 0px;" stroke-dasharray="441.1739501953125"></path>
<path class="el" d="M118 80V49.77C118.5 33.23 131.58 20 148 20a30 30 0 0 1 30 30v30h-15V50a15 15 0 0 0-15-15c-8.14 0-14.7 6.6-15 15.12V80h-15zm-7.5-60a7.5 7.5 0 1 1-7.48 8v-1c.25-3.9 3.5-7 7.48-7z" style="stroke-dashoffset: 0px;" stroke-dasharray="338.3053894042969"></path>
<path class="el" d="M133 65a15 15 0 0 1-15-15v-7.5h-15V50a30 30 0 0 0 30 30V65zm30 15V49.77C163.5 33.23 176.58 20 193 20a30 30 0 0 1 30 30v30h-15V50a15 15 0 0 0-15-15c-8.14 0-14.7 6.6-15 15.12V80h-15z" style="stroke-dashoffset: 0px;" stroke-dasharray="406.8699035644531"></path>
<path class="el" d="M238 65a15 15 0 0 1 0-30c8.1 0 14.63 6.53 15 15h-15v15h30V49.89C267.5 33.23 254.42 20 238 20a30 30 0 0 0 0 60V65z" style="stroke-dashoffset: 4.49556px;" stroke-dasharray="301.8561706542969"></path>
<path class="el" d="M260.48 65a7.5 7.5 0 1 1-7.48 8v-1c.26-3.9 3.5-7 7.48-7z" style="stroke-dashoffset: 6.61913px;" stroke-dasharray="47.128875732421875"></path>
</g>
</svg>
我真的很难过,所以我想看看这里是否有人能够帮助我考虑一下。
我正在尝试将滚动侦听器附加到特定像素范围之间的 SVG 路径,因此当您上下滚动时它会来回绘制。
我这几天一直在研究这个问题,我发现了关于将笔画 dashoffset 进度转换为基于 window 顶部或文档高度的百分比的主题作为单个数字,但我似乎无法理解如何将相同的逻辑应用于指定的像素范围。
我如何让 svg 路径的 stroke-dasharray 处于像素范围开始处的起始值 (3000)(比如从文档顶部开始的 2500px 到 3000px。)和结束值笔划 dasharray 的像素范围末尾为 6000(它的最终值)?我真的希望这不是一个我盯着看太久的愚蠢简单的问题。这是我拥有的:
var path = document.querySelector('path');
var length = path.getTotalLength();
var triggerPadding = 600;
var startLocation = document.querySelector('.scroll-container').getBoundingClientRect()
var bodyRect = document.body.getBoundingClientRect();
var elemRect = document.querySelector('.scroll-container').getBoundingClientRect();
var elementYLocation = elemRect.top - bodyRect.top;
var elementBottomYLocation = Math.round((elemRect.bottom - bodyRect.top) - triggerPadding);
var startTrigger = Math.round(elementYLocation - triggerPadding);
path.style.strokeDasharray = length + ' ' + length;
path.style.strokeDashoffset = length;
//
function animationScroll(currentY, startY, endY) {
console.log({ currentY, startY, endY })
if (currentY >= startY) {
//do animation
}
}
window.addEventListener('scroll', function () {
const currentY = window.pageYOffset || window.scrollY;
animationScroll(currentY, startTrigger, elementBottomYLocation);
}, false);
对于我需要执行此操作的方程式的任何帮助,我们将不胜感激。提前谢谢你。
用户@CBroe 回答并provides/walks通过所需的公式计算两个数字范围的线性变换。
f(t) = c + ( (d - c) / (b - a) ) * (t - a);
您需要计算 scrollRatio
,然后将其乘以您想要制作动画的 svg 属性 的所需范围。
下面,我举例说明了等待某个元素进入视口,然后开始动画,执行与滚动同步的动画关键帧,并在元素离开视口后停止动画。
const triggerEl = document.getElementById('trigger');
const animateSvg = () => {
const rect = triggerEl.getBoundingClientRect();
const scrollPosition = window.scrollY;
let scrollRatio = (rect.top / window.innerHeight);
scrollRatio = Math.max(scrollRatio, 0);
scrollRatio = Math.min(scrollRatio, 1);
triggerEl.innerHTML = `Trigger Element ${(scrollRatio * 100).toFixed(2)}%`;
for (const path of document.querySelectorAll('svg path')) {
// Min & Max can be hardcoded to fit your use-case
const dashOffsetMin = 0;
const dashOffsetMax = path.getTotalLength();
const dashOffsetRange = dashOffsetMax
- dashOffsetMin;
// Set stroke-dashoffset
path.style.strokeDashoffset = dashOffsetMin
+ dashOffsetRange * scrollRatio;
}
}
animateSvg();
document.addEventListener('scroll', animateSvg)
body {
position: relative;
background:linear-gradient(135deg, #5b247a 0%,#1bcedf 100%);
min-height: 300vh;
}
h1 {
font-family: arial;
font-weight: 900;
color: white;
width: 100%;
text-align: center;
}
svg {
position: fixed;
top: 0;
color: white;
}
svg path {
transition: stroke-dashoffset 250ms linear;
box-shadow: 0px 0px 15px white;
}
#trigger {
position: absolute;
z-index: 2;
top: 100vh;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-family: arial;
font-weight: 900;
height: 20vh;
background: linear-gradient(to bottom right, rgba(0,0,25,0.2), rgba(0,0,25,0.5));
border-radius: 5px;
backdrop-filter: blur(5px);
box-shadow: 0px 15px 10px -10px rgba(0,0,0,0.4);
}
<div id='trigger'>
Trigger Element
</div>
<h1>Scroll!</h1>
<svg viewBox="0 0 280 100">
<g fill="none" fill-rule="evenodd" stroke="currentColor" stroke-width="1" class="lines">
<path class="el" d="M58 80V50.12C57.7 41.6 51.14 35 43 35a15 15 0 0 0 0 30h7.5v15H43a30 30 0 1 1 0-60c16.42 0 29.5 13.23 30 29.89V80H58z" style="stroke-dashoffset: 0px;" stroke-dasharray="316.85528564453125"></path>
<path class="el" d="M73 80V20H58v60h15z" style="stroke-dashoffset: 0px;" stroke-dasharray="150"></path>
<path class="el" d="M58 80V49.77C58.5 33.23 71.58 20 88 20a30 30 0 0 1 30 30v30h-15V50a15 15 0 0 0-15-15c-8.14 0-14.7 6.6-15 15.12V80H58zm75 0V20h-15v60h15z" style="stroke-dashoffset: 0px;" stroke-dasharray="441.1739501953125"></path>
<path class="el" d="M118 80V49.77C118.5 33.23 131.58 20 148 20a30 30 0 0 1 30 30v30h-15V50a15 15 0 0 0-15-15c-8.14 0-14.7 6.6-15 15.12V80h-15zm-7.5-60a7.5 7.5 0 1 1-7.48 8v-1c.25-3.9 3.5-7 7.48-7z" style="stroke-dashoffset: 0px;" stroke-dasharray="338.3053894042969"></path>
<path class="el" d="M133 65a15 15 0 0 1-15-15v-7.5h-15V50a30 30 0 0 0 30 30V65zm30 15V49.77C163.5 33.23 176.58 20 193 20a30 30 0 0 1 30 30v30h-15V50a15 15 0 0 0-15-15c-8.14 0-14.7 6.6-15 15.12V80h-15z" style="stroke-dashoffset: 0px;" stroke-dasharray="406.8699035644531"></path>
<path class="el" d="M238 65a15 15 0 0 1 0-30c8.1 0 14.63 6.53 15 15h-15v15h30V49.89C267.5 33.23 254.42 20 238 20a30 30 0 0 0 0 60V65z" style="stroke-dashoffset: 4.49556px;" stroke-dasharray="301.8561706542969"></path>
<path class="el" d="M260.48 65a7.5 7.5 0 1 1-7.48 8v-1c.26-3.9 3.5-7 7.48-7z" style="stroke-dashoffset: 6.61913px;" stroke-dasharray="47.128875732421875"></path>
</g>
</svg>