滚动侦听器描边 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>