CSS动画将页面上的图标滚动到路径

xe55xuns  于 2023-05-30  发布在  其他
关注(0)|答案(2)|浏览(155)

回答此问题可获得+50声望bounty。赏金宽限期已经结束。Kunal Vijan正在寻找来自可靠来源的**答案 *:
如果你能分享解决方案的要求,这将是有帮助的。
我想创建一个页面滚动CSS动画。箭头将移动到页面滚动条上的蛇形路径,如果可能的话,还可以在每个新部分上更改图标。
我举几个例子:
codepen.io/yesvin/pen/XymwvX
codepen.io/gkando/pen/LYEvjOv
但无法根据设计创建路径,并在每个部分更改图标 *1-2箭头,2-3圆圈,3-4另一个图标等 *
我也附上路径以供参考。

我的代码到目前为止:

window.addEventListener('scroll', function() {
  let l = Path_440.getTotalLength();
  let dasharray = l;
  let dashoffset = l;
  e = document.documentElement;
  theFill.setAttributeNS(null, "stroke-dasharray", l);
  theFill.setAttributeNS(null, "stroke-dashoffset", l);
  dashoffset = l - window.scrollY * l / (e.scrollHeight - e.clientHeight);
  //console.log('window.scrollY', window.scrollY, 'scrollTop', e.scrollTop, 'scrollHeight', e.scrollHeight, 'clientHeight', e.clientHeight, 'dash-offset', dashoffset);
  theFill.setAttributeNS(null, "stroke-dashoffset", dashoffset);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<svg width="246" height="2990" viewBox="0 0 246 2990" fill="none" xmlns="http://www.w3.org/2000/svg">
                <defs>
                <path id="Path_440" d="M210.001 1.5C210.001 1.5 41.0015 324.5 6.50082 617.5C-27.004 902.042 182.501 1032.5 240.001 1313C275.095 1484.2 29.8527 1661 41.0008 1914.5C50.4751 2129.94 230.431 2237.5 235.001 2431.5C240.42 2661.59 41.0008 2988 41.0008 2988" stroke="#F39029" stroke-width="4" stroke-dasharray="20 10"/>
                </defs>
                <use xlink:href="#Path_440" stroke="#000" stroke-width="4" stroke-dasharray="1"/>
                <use id="theFill" xlink:href="#Path_440" stroke="#000" stroke-width="1"/>
            </svg>
disbfnqx

disbfnqx1#

因为你有一种计算scrollPercent的方法,也就是window.scrollY / (docElt.scrollHeight - docElt.clientHeight),你可以用它来 * 粗略地 * 计算到目前为止沿着路径的距离scrollPercent * Path_440.getTotalLength()。然后使用该距离,使用getPointAtLength(distance)在路径上获得DOMPoint,可用于更新箭头图标的位置和旋转,如下所示。您还可以在事件处理程序中添加逻辑以基于scrollPercent更新图标。

const pathLength = Path_440.getTotalLength();
const docElt = document.documentElement;

function clamp(min, val, max) {
  return Math.min(Math.max(min, val), max);
}

updatePath();
window.addEventListener("scroll", () => updatePath());

function updatePath() {
  const scrollPercent =
    window.scrollY / (docElt.scrollHeight - docElt.clientHeight);
  const drawLength = clamp(0, pathLength * scrollPercent, pathLength);

  // use if you want the dashes to 'fill in' on scroll
  const rest = pathLength - drawLength;
  theFill.style.strokeDasharray = `${drawLength} ${rest}`;

  // update icon position and rotation
  const [l1, l2] =
  drawLength < pathLength ?
    [drawLength, drawLength + 0.1] :
    [drawLength - 0.1, drawLength];
  const p1 = Path_440.getPointAtLength(l1);
  const p2 = Path_440.getPointAtLength(l2);
  const angle = Math.atan2(p2.y - p1.y, p2.x - p1.x);
  arrow.style.left = `${p1.x}px`;
  arrow.style.top = `${p1.y}px`;
  arrow.style.rotate = `${angle}rad`;

  // update icon image (here I just change the fill)
  if (scrollPercent < 0.2) {
    arrow.style.fill = "black";
  } else if (scrollPercent < 0.4) {
    arrow.style.fill = "red";
  } else if (scrollPercent < 0.6) {
    arrow.style.fill = "blue";
  } else if (scrollPercent < 0.8) {
    arrow.style.fill = "magenta";
  } else if (scrollPercent < 1) {
    arrow.style.fill = "goldenrod";
  }
  if (scrollPercent >= 1) {
    // reached end
    arrow.style.fill = "lime";
  }
}
<svg width="246" height="2990" viewBox="0 0 246 2990" fill="none" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <path id="Path_440" d="M210.001 1.5C210.001 1.5 41.0015 324.5 6.50082 617.5C-27.004 902.042 182.501 1032.5 240.001 1313C275.095 1484.2 29.8527 1661 41.0008 1914.5C50.4751 2129.94 230.431 2237.5 235.001 2431.5C240.42 2661.59 41.0008 2988 41.0008 2988" stroke-width="4" stroke="#F39029" />
  </defs>
  <use xlink:href="#Path_440" stroke-dasharray="20 10" />
  <!-- use if you want the dashes to 'fill in' on scroll -->
  <use id="theFill" xlink:href="#Path_440" />
</svg>
<svg id="arrow" style="position: absolute; left: 0; top: 0;" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill-rule="evenodd" clip-rule="evenodd">
  <path d="M21.883 12l-7.527 6.235.644.765 9-7.521-9-7.479-.645.764 7.529 6.236h-21.884v1h21.883z" />
</svg>

***在不久的将来(希望如此)...***我们将在浏览器中获得Scroll-driven Animations,这将使单独使用CSS沿着路径动画元素变得更加简单。例如,如果你在Chrome Canary 115+上启用了experimental-web-platform-features标志,下面的CSS即使不能更好,也能工作得很好。不需要JS:

#arrow {
  offset-path: url(#Path_440);
  offset-anchor: left;
  animation: offsetDistance linear;
  animation-timeline: scroll();
}

@keyframes offsetDistance {
  from {
    offset-distance: 0%;
  }
  to {
    offset-distance: 100%;
  }
}
<svg width="246" height="2990" viewBox="0 0 246 2990" fill="none" xmlns="http://www.w3.org/2000/svg">
    <defs>
        <path id="Path_440"
            d="M210.001 1.5C210.001 1.5 41.0015 324.5 6.50082 617.5C-27.004 902.042 182.501 1032.5 240.001 1313C275.095 1484.2 29.8527 1661 41.0008 1914.5C50.4751 2129.94 230.431 2237.5 235.001 2431.5C240.42 2661.59 41.0008 2988 41.0008 2988"
            stroke-width="4" stroke="#F39029" />
    </defs>
    <use xlink:href="#Path_440" stroke-dasharray="20 10" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" id="arrow" style="position: absolute; left: 0; top: 0;" fill-rule="evenodd" clip-rule="evenodd">
    <path d="M21.883 12l-7.527 6.235.644.765 9-7.521-9-7.479-.645.764 7.529 6.236h-21.884v1h21.883z" />
</svg>

您可以了解有关如何在this article中使用滚动驱动动画的更多信息。

2admgd59

2admgd592#

这不是完全的CSS动画,但产生类似的效果。如果你对这样的东西持开放态度,这可以进一步完善。
我只是使用HTML画布来绘制一条正弦曲线。现在,你必须知道一些高中水平的三角学...

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Path</title>
    <style>
      body,
      html,
      canvas {
        height: 99.6%;
        width: 99.6%;
      }
      canvas {
        background-color: black;
      }
    </style>
  </head>
  <body>
    <canvas id="c"></canvas>
  </body>
  <script src="canvas.js"></script>
</html>

canvas.js

let canvas = document.getElementById('c');
canvas.width = document.body.clientWidth;
canvas.height = document.body.clientHeight;
let ctx = canvas.getContext('2d');
ctx.fillStyle = '#FF0000';
let delta = 100;
let n = 100;
addEventListener('wheel', (e) => {
  let c = 150;
  for (let i = n; i <= n; i++) {
    let x = (i * c * 2 * Math.PI) / (300*delta);
    let y = -c * Math.sin(x / c) + 600;
    ctx.fillRect(y, x, 3, 3);
  }
  n += delta;
});

看起来是这样的

相关问题