SVG的`<path>` JavaScript动画不按预期工作

13

我所取得的成就:

// Get the id of the <path> element and the length of <path>
var myline = document.getElementById("myline");
var length = myline.getTotalLength();
circle = document.getElementById("circle");
// The start position of the drawing
myline.style.strokeDasharray = length;

// Hide the triangle by offsetting dash. Remove this line to show the triangle before scroll draw
myline.style.strokeDashoffset = length;

// Find scroll percentage on scroll (using cross-browser properties), and offset dash same amount as percentage scrolled
window.addEventListener("scroll", myFunction);

function myFunction() {
  // What % down is it?
  var scrollpercent = (document.body.scrollTop + document.documentElement.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight);
  // Length to offset the dashes
  var draw = length * scrollpercent;

  // Reverse the drawing (when scrolling upwards)
  myline.style.strokeDashoffset = length - draw;

  //get point at length
  endPoint = myline.getPointAtLength(draw);
  circle.setAttribute("cx", endPoint.x);
  circle.setAttribute("cy", endPoint.y);

}
body {
  height: 2000px;
  background: #f1f1f1;
}

#circle {
  fill: red;
}

#mySVG {
  position: absolute;
  top: 15%;
  width: 100%;
  height: 1000px;
  
}

.st1 {
  fill: none;
  stroke-dashoffset: 3px;
  stroke: grey;
  stroke-width: 4;
  stroke-miterlimit: 10;
  stroke-dasharray: 20;
}
.st0 {
  fill: none;
  stroke-dashoffset: 3px;
  stroke: red;
  stroke-width: 5;
  stroke-miterlimit: 10;
  stroke-dasharray: 20;
}
<svg id="mySVG" viewBox="0 0 60 55" preserveAspectRatio="xMidYMin slice" style="width: 6%; padding-bottom: 42%; height: 1px; overflow: visible">
  <path  class="st1" stroke-dasharray="10,9" d="M 20 0 v 20 a 30 30 0 0 0 30 30 h 600 a 40 40 0 0 1 0 80 h -140 a 30 30 0 0 0 0 60 h 200 a 40 40 0 0 1 0 80 h -100 a 30 30 0 0 0 -30 30 v 20" /> Sorry, your browser does not support inline SVG.
</svg>

<svg id="mySVG" viewBox="0 0 60 55" preserveAspectRatio="xMidYMin slice" style="width: 6%; padding-bottom: 42%; height: 1px; overflow: visible">
  <circle id="circle" cx="10" cy="10" r="10"/>
  <path id="myline" class="st0" stroke-dasharray="10,9" d="M 20 0 v 20 a 30 30 0 0 0 30 30 h 600 a 40 40 0 0 1 0 80 h -140 a 30 30 0 0 0 0 60 h 200 a 40 40 0 0 1 0 80 h -100 a 30 30 0 0 0 -30 30 v 20" /> Sorry, your browser does not support inline SVG.
</svg>

我想要的是无论SVG <path>大小形状如何,增长的线应该在屏幕中央。

我尝试更改myline.style.strokeDashoffset = length //+newvalue - draw;的值,但这只会破坏一致性。有人可以帮我解决这个问题吗?

非常感谢任何帮助。


我知道使用固定位置可以在一定程度上解决这个问题,但我需要使用“绝对”定位,因为我需要它相对于页面上的某些其他元素的“相对”位置。 - Jithin Raj P R
大家可以在这个链接中看到 - https://dev59.com/xKTia4cB1Zd3GeqP8xwC ,我知道这会起作用,但是我有许多其他UI,其中我希望路径相对于另一个元素。 - Jithin Raj P R
4个回答

8

(更新/新答案)

我认为这正是你想要的...

更新(根据 OP 的要求添加了缓动效果):

通过在 #body 上添加 transition: stroke-dashoffset ease-in-out 0.2s;,使 #body 的长度增加平滑。

不能通过在 #head 上添加 transition: cx ease-in-out 0.2s, cy ease-in-out 0.2s; 来使 #head 移动平滑,因为这会使其跳跃而不是沿着路径移动。

如果你希望 #head 沿着轨道平滑移动,你将不得不手动使用 js 实现缓动,这是很多工作。所以跳过了这部分。

let roadmapSvg = document.getElementById("roadmap-svg");
let track = document.getElementById("track");
let body = document.getElementById("body");
let head = document.getElementById("head");

let totalLength = track.getTotalLength();
let trackPoints = [];
let getTrackBounds = () => track.getBoundingClientRect();
let scaleFactor;

body.style.strokeDasharray = totalLength;
body.style.strokeDashoffset = totalLength;

function setScaleFactor(){
  scaleFactor = roadmapSvg.getBoundingClientRect().width / roadmapSvg.viewBox.baseVal.width;
}   
setScaleFactor();

function setTrackPoints(){
  let divisions = 1000;
  let unitLength = totalLength / divisions;
  trackPoints = [];
  for(let i=0; i < divisions; i++){
    let length = unitLength * i;
    let {x,y} = track.getPointAtLength(length);
    trackPoints.push({x: x*scaleFactor, y: y*scaleFactor, length});
  }
}
setTrackPoints();


function draw(){
  let currentLength = getCurrentLength();
  body.style.strokeDashoffset = totalLength - currentLength;
  headPos = track.getPointAtLength(currentLength);
  head.setAttribute("cx", headPos.x);
  head.setAttribute("cy", headPos.y);
}

function getCurrentLength(){
  let centreY = window.innerHeight / 2;
  let trackBounds = getTrackBounds();
  let currentY = centreY - trackBounds.y;
  if(currentY < 0) return 0;
  
  // if currentY is greater that track height, that means the user has scrolled pass the track (and the whole svg) in such case the animation should be completed i.e. the head should be at the final position i.e. at totalLength 
  if(currentY > trackBounds.height) return totalLength;
  
  for(let point of trackPoints){
    if(point.y >= currentY){
      return point.length;
    }
  }
  
  // (For safety) Sometimes none of the conditions match bcoz of low precision... Such situation only occurs a point very close to total length... Thus...
  return totalLength;
}

document.addEventListener("scroll", draw);

window.addEventListener("resize", () => {
  setScaleFactor();
  setTrackPoints();
  draw();
});
body {
  background: #f1f1f1;
  margin: 0;
  padding: 0 20%;
  font-family: sans-serif;
}

#roadmap-svg{
  display: block;
  max-width: 600px;
  margin: 20px auto;
  overflow: visible;
}

#roadmap-svg #head{
  fill: red;
}

#roadmap-svg #track{
  fill: none;
  stroke-dashoffset: 3px;
  stroke: grey;
  stroke-width: 4;
  stroke-miterlimit: 10;
  stroke-dasharray: 20;
}
#roadmap-svg #body{
  fill: none;
  stroke-dashoffset: 3px;
  stroke: red;
  stroke-width: 5;
  stroke-miterlimit: 10;
  stroke-dasharray: 20;
  transition: stroke-dashoffset ease-in-out 0.2s;
}

.center-line{
  position: fixed;
  left: 0;
  right: 0;
  top: 50%;
  border-top: 1px solid red;
  background-color: rgba(255,255,255,0.9);
}
<div>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempora in eaque rem eligendi corrupti voluptate, maxime cum cumque, eius delectus minus neque, dolorem optio cupiditate ratione! Excepturi fugit culpa quo?
Cum optio error ex voluptatem rerum eius sunt, nemo necessitatibus, exercitationem voluptatum illum, rem quibusdam accusamus deserunt sed. Iste odio obcaecati enim voluptate temporibus ab illo maxime et sit minima.
Odio ut dignissimos sed dicta recusandae esse, at molestiae quibusdam, consequatur aspernatur facilis, perferendis voluptatum adipisci. Dolores molestiae quos, doloribus excepturi officiis laborum ex officia reprehenderit esse perspiciatis alias itaque.
Delectus illum, asperiores at a ab quibusdam corporis necessitatibus. Libero eos vero blanditiis modi cum rem maxime delectus quisquam, facilis saepe sed eius corrupti nobis sunt, unde obcaecati commodi velit.
Saepe adipisci consectetur blanditiis quos enim praesentium, at magnam quibusdam nisi! Dolore, esse beatae! Enim, quam cum, qui voluptates fugiat, nihil mollitia possimus doloremque porro aspernatur nesciunt velit. Cum, adipisci?
Dolores doloribus nihil delectus consequuntur id assumenda tempora, illum, earum ab quasi quaerat sequi et hic veniam excepturi eligendi quod perspiciatis voluptatem ratione reprehenderit! Corrupti minima facilis soluta adipisci animi!
Iure, sed exercitationem. Quidem assumenda omnis dicta ducimus sunt, quibusdam excepturi molestias cumque! Illum ipsum perferendis dicta optio eum consequuntur soluta, corrupti nostrum est sed quaerat voluptates dolores perspiciatis? Ex!
Consequatur corporis ratione beatae. Magni amet doloribus deserunt, accusamus suscipit earum accusantium perferendis adipisci inventore, ab commodi odio necessitatibus aut omnis. Et quisquam esse deleniti, reprehenderit nihil optio aperiam fugit.
Aliquid error voluptatibus, quis quo eveniet nulla corrupti veniam culpa voluptas possimus tenetur nisi recusandae quae modi, animi dolores. Provident saepe nobis quos tenetur, veritatis laborum cupiditate molestias fugit consectetur.
A, perspiciatis illo sequi non eos facere temporibus dignissimos blanditiis ipsum harum eius culpa adipisci est ab nobis saepe mollitia quis laboriosam tenetur, repellat molestias. Quos ipsa magni dolores rerum.</div>
<svg id="roadmap-svg" viewBox="0 0 760 300">
  <path  id="track" stroke-dasharray="10,9" d="M 20 0 v 20 a 30 30 0 0 0 30 30 h 600 a 40 40 0 0 1 0 80 h -140 a 30 30 0 0 0 0 60 h 200 a 40 40 0 0 1 0 80 h -100 a 30 30 0 0 0 -30 30 v 20" />
  <path id="body" stroke-dasharray="10,9" d="M 20 0 v 20 a 30 30 0 0 0 30 30 h 600 a 40 40 0 0 1 0 80 h -140 a 30 30 0 0 0 0 60 h 200 a 40 40 0 0 1 0 80 h -100 a 30 30 0 0 0 -30 30 v 20" />
  <circle id="head" cx="10" cy="10" r="10"/>
</svg>
<div class="center-line">Center Line</div>
<div>Lorem ipsum dolor sit amet consectetur adipisicing elit. Sapiente officia saepe facilis? Cupiditate rem vel, quaerat ratione ipsam magnam fugiat praesentium incidunt! Eveniet cum officia impedit obcaecati id animi rerum?
Non beatae inventore quos optio temporibus ratione doloremque ullam animi dolore reiciendis sint, esse consequatur asperiores assumenda repudiandae obcaecati ab quas molestias harum eveniet amet natus ea? Ipsum, dolore suscipit.
Explicabo assumenda minus, reprehenderit modi, laboriosam placeat saepe at repudiandae perferendis fugit asperiores itaque. Vero fugiat voluptas asperiores dolores dolorum quis ipsa sapiente deleniti odio, deserunt, iure voluptates. Error, tempore.
Doloribus nesciunt praesentium ad aut minus aliquam aspernatur quas qui incidunt sunt, maxime tempora facilis, cum assumenda. Dolorum a tempore itaque impedit, ad, corporis tenetur enim nulla quas, harum fuga!
Quae repellat, obcaecati voluptate inventore quidem, labore quo corporis repudiandae, vel doloremque perferendis numquam aliquam nisi? Vel architecto ullam fugiat error corrupti? Cumque amet illo, possimus assumenda eos unde deleniti.
Enim tenetur possimus a neque, voluptatum reprehenderit, cum magni blanditiis quam atque dolorum veniam eveniet repellendus. Modi quibusdam maxime corrupti harum! Ullam vitae assumenda laboriosam nam officia eaque. Totam, dolorem.
Ad sapiente itaque blanditiis, sint iusto nemo laborum corrupti cupiditate obcaecati quam ipsa quis perferendis vitae enim atque ex a ratione. Doloribus aspernatur id ipsa recusandae labore aliquid, totam aperiam?
Recusandae delectus quidem, aspernatur nulla expedita accusantium quod praesentium inventore qui, pariatur ullam maxime! Numquam, sed sequi rem voluptates asperiores qui, culpa nesciunt magnam, quas doloribus praesentium et adipisci tempora.
Veniam, placeat vel nesciunt recusandae voluptates laboriosam totam doloremque saepe. Nam quo similique vero esse possimus architecto officiis harum ratione perspiciatis dolor ut, molestias odit consequatur quam asperiores? Id, quasi!
Ex expedita impedit aliquam et commodi voluptatibus, consequatur voluptate ea explicabo deserunt. Sapiente quo consequuntur enim dolores ea officia. Inventore ipsa dignissimos iste qui magnam reiciendis eveniet optio laudantium fugiat!</div>


@weBBer,你是否可以通过更改completeOn而不是speed来实现你想要的效果?基本上,在这种情况下,completeOnspeed值对你有什么作用,这样我就能直观地了解你想要什么了。(速度从来没有意味着成为我的解决方案的一部分...它只是一个添加项,理想情况下永远不应该被使用,因为正如你所说,它会带入任意值...) - Devansh J
很高兴看到你的回答,解释得很清楚,并用一个很好的示例进行了证明。你证明了你是SO的一员。很高兴为你提供赏金,还有一件事情,如果你能对曲线进行一些平滑处理会更好。 - Jithin Raj P R
@weBBer 谢谢你,欢迎加入! :) 我也按照你的要求添加了缓动效果... - Devansh J
@weBBer 欢迎,我故意没有给点缓动效果...我在答案中已经解释了原因... - Devansh J
@weBBer,我猜你想让我解释一下 if(currentY > trackBounds.height) return totalLength; ... 我已经添加了一个注释来解释它... 此外,你所提到的错误只会在用户进行跳跃滚动时才会出现... 我不认为它与你所评论的代码有任何关系。但你已经成功解决了这个问题,这真是太好了。 - Devansh J
显示剩余11条评论

7

我尝试了几种方法来移动点:

  • 在框内
  • 直到结束不滑动
  • 对原始内容进行最小更改。

我做出了以下更改(下面是一个可工作的示例):

  • 我将百分比的分界线设为2000(等于2000像素,包含body高度)
  • 我将从顶部滚动的量乘以18(适当的值是折衷,无论顶部还是底部变得奇怪)
  • 最后,我检查百分比值是否不大于1(它开始从另一端吃掉“蠕虫”)。

就这样!也许不是最花哨的,但是有效。

问题在于SVG线不是从上到下的线性,因此无法选择直接元素相关的值,或者至少我没有找到。因此,我最终采用了简单的解决方案并调整了参数。

// Get the id of the <path> element and the length of <path>
var myline = document.getElementById("myline");
var length = myline.getTotalLength();
circle = document.getElementById("circle");
// The start position of the drawing
myline.style.strokeDasharray = length;

// Hide the triangle by offsetting dash. Remove this line to show the triangle before scroll draw
myline.style.strokeDashoffset = length;

// Find scroll percentage on scroll (using cross-browser properties), and offset dash same amount as percentage scrolled
window.addEventListener("scroll", myFunction);

function myFunction() {
  // What % down is it?
  var scrollpercent = (document.documentElement.scrollTop * 18) / 2000;
  if (scrollpercent > 1) scrollpercent = 1;
  var draw = length * scrollpercent;

  // Reverse the drawing (when scrolling upwards)
  myline.style.strokeDashoffset = length - draw;

  //get point at length
  endPoint = myline.getPointAtLength(draw);
  circle.setAttribute("cx", endPoint.x);
  circle.setAttribute("cy", endPoint.y);
}
body {
  height: 2000px;
  background: #f1f1f1;
}

#circle {
  fill: red;
}

#mySVG {
  position: absolute;
  top: 15%;
  width: 100%;
  height: 1000px;
  
}

.st1 {
  fill: none;
  stroke-dashoffset: 3px;
  stroke: grey;
  stroke-width: 4;
  stroke-miterlimit: 10;
  stroke-dasharray: 20;
}
.st0 {
  fill: none;
  stroke-dashoffset: 3px;
  stroke: red;
  stroke-width: 5;
  stroke-miterlimit: 10;
  stroke-dasharray: 20;
}
<svg id="mySVG" viewBox="0 0 60 55" preserveAspectRatio="xMidYMin slice" style="width: 6%; padding-bottom: 42%; height: 1px; overflow: visible">
  <path  class="st1" stroke-dasharray="10,9" d="M 20 0 v 20 a 30 30 0 0 0 30 30 h 600 a 40 40 0 0 1 0 80 h -140 a 30 30 0 0 0 0 60 h 200 a 40 40 0 0 1 0 80 h -100 a 30 30 0 0 0 -30 30 v 20" /> Sorry, your browser does not support inline SVG.
</svg>

<svg id="mySVG" viewBox="0 0 60 55" preserveAspectRatio="xMidYMin slice" style="width: 6%; padding-bottom: 42%; height: 1px; overflow: visible">
  <circle id="circle" cx="10" cy="10" r="10"/>
  <path id="myline" class="st0" stroke-dasharray="10,9" d="M 20 0 v 20 a 30 30 0 0 0 30 30 h 600 a 40 40 0 0 1 0 80 h -140 a 30 30 0 0 0 0 60 h 200 a 40 40 0 0 1 0 80 h -100 a 30 30 0 0 0 -30 30 v 20" /> Sorry, your browser does not support inline SVG.
</svg>


在这种情况下,点并不总是居中的。这只是针对我吗? - Jithin Raj P R
不,对我来说也是一样的。我引用了自己的答案:“问题在于svg线条从上到下不是线性的”。这意味着曲率是非线性扩展的(不是始终相同的速度),但您以相同的速度垂直滚动,并且依赖于点位置和线条在滚动条百分比上的绘制(我也是如此),它们实际上不能直接进行比较,因此采用这种方法点不会停留在中心。应该使用其他东西来控制屏幕上的线条和点位置,但我还没有想到会是什么。 - mico
1
我尝试调整偏移量,但最终得到的是静态图像,根本无法滚动:/ - mico
你的回答是我在这里得到的最好的之一。但是,这只是一个SVG“路径”,我的网站上有许多不同形状和长度的“路径”。因此,每次调整这个JS对我来说都不是一个好主意。在你的看法中,还有其他方法吗? - Jithin Raj P R
很抱歉,这就是我对这个主题的全部了解。Ccprog的答案,虽然已被删除,但对我来说仍是下一个最好的选择,当然也可以在新方向上进行扩展。 - mico
1
谢谢你的时间,兄弟。每天都有新东西可以学习,请查看Devansh的答案,我认为那是一个更好的解决方案! - Jithin Raj P R

3

根据评论以及对CSS和SVG代码进行的一些修改,我设法将线条置于页面中心,请查看下面的工作示例:

// Get the id of the <path> element and the length of <path>
var myline = document.getElementById("myline");
var length = myline.getTotalLength();
circle = document.getElementById("circle");
// The start position of the drawing
myline.style.strokeDasharray = length;

// Hide the triangle by offsetting dash. Remove this line to show the triangle before scroll draw
myline.style.strokeDashoffset = length;

// Find scroll percentage on scroll (using cross-browser properties), and offset dash same amount as percentage scrolled
window.addEventListener("scroll", myFunction);

function myFunction() {
  // What % down is it?
  var scrollpercent = (document.body.scrollTop + document.documentElement.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight);
  // Length to offset the dashes
  var draw = length * scrollpercent;

  // Reverse the drawing (when scrolling upwards)
  myline.style.strokeDashoffset = length - draw;

  //get point at length
  endPoint = myline.getPointAtLength(draw);
  circle.setAttribute("cx", endPoint.x);
  circle.setAttribute("cy", endPoint.y);
}
body {
  margin: 0;
  height: 1000px;
  background: #f1f1f1;
}
#circle {
  fill: red;
}
#mySVG {
  top: 15%;
  position: absolute;
  width: 100%;
}
.st1 {
  fill: none;
  stroke-dashoffset: 1;
  stroke: grey;
  stroke-width: .5;
  stroke-miterlimit: 1;
  stroke-dasharray: 2;
}
.st0 {
  fill: none;
  stroke-dashoffset: 3px;
  stroke: red;
  stroke-width: 1;
  stroke-miterlimit: 1;
  stroke-dasharray: 2;
}
.grid {
  position: fixed;
  width: 1px;
  height: 100%;
  background: blue;
  left: 50%;
  top: 0;
}
<div class="grid"></div>
<svg id="mySVG" viewBox="0 0 200 72" preserveAspectRatio="xMidYMin slice">
  <path class="st1" stroke-dasharray="10,9" d="m 0,5 0,4 c 0,3 2,6 5,6 l 108,0 c 4,0 7,4 7,8 0,4 -3,7 -7,7 l -25,0 c -3,0 -6,3 -6,6 0,3 3,6 6,6 l 35,0 c 4,0 7,4 7,8 0,4 -3,7 -7,7 l -18,0 c -3,0 -5,3 -5,6 l 0,4" />
</svg>

<svg id="mySVG" viewBox="0 0 200 72" preserveAspectRatio="xMidYMin slice">
  <circle id="circle" cx="0" cy="3" r="2" />
  <path id="myline" class="st0" stroke-dasharray="10,9" d="m 0,5 0,4 c 0,3 2,6 5,6 l 108,0 c 4,0 7,4 7,8 0,4 -3,7 -7,7 l -25,0 c -3,0 -6,3 -6,6 0,3 3,6 6,6 l 35,0 c 4,0 7,4 7,8 0,4 -3,7 -7,7 l -18,0 c -3,0 -5,3 -5,6 l 0,4" />
</svg>


兄弟,请阅读“问题”中的注释。我知道可以使用position: fixed来修复它,但我需要它能够与position: absolute一起工作,并且我不需要完整的SVG居中于页面,我只需要红线指示在页面中间。 - Jithin Raj P R
@weBBer,请在完整页面模式下检查更新的代码片段,谢谢 :) - Girisha C

-3

我会选择不同的方法。我理解你想要找到路径上距离屏幕中心最近的点。我们来实现一下:

  1. 找到屏幕中心的坐标并将其转换为路径的坐标系。SVG API 有两个函数可以做到这一点:.getScreenCTM()SVGPoint.matrixTransform()
  2. 找到距离这些坐标最近的路径上的点(以及它沿路径的距离)。这需要一些数学和搜索算法。Mike Bostock 已经 展示了这样一个算法,并且在这里使用。请注意,他的函数可以进行一些微调(precision 参数)。
  3. 使用这些数据绘制圆形和虚线偏移量。

引入滚动事件的节流器(第二种变体)可能是一个不错的主意,然后设置CSS过渡以避免可见跳跃。

仅对圆形定位进行的过渡只能使用CSS transform属性。(我的解决方案不一定在过渡时沿路径移动圆形。虽然可以实现,但超出了本答案的范围。)

var mySVG = document.getElementById("mySVG");
// Get the id of the <path> element and the length of <path>
var myline = document.getElementById("myline");
var pathLength = myline.getTotalLength();
circle = document.getElementById("circle");
// The start position of the drawing
myline.style.strokeDasharray = pathLength;

// Hide the triangle by offsetting dash. Remove this line to show the triangle before scroll draw
myline.style.strokeDashoffset = pathLength;

// throttled scroll event listener
function throttle(ms, callback) {
    var timer, lastCall=0;

    return function() {
        var now = new Date().getTime(),
            diff = now - lastCall;
        if (diff >= ms) {
            lastCall = now;
            callback();
        }
    };
}

window.addEventListener("scroll", throttle(100, myFunction));

// one initial execution
myFunction();

function myFunction() {
  var center = mySVG.createSVGPoint();
  // middle of browser viewport
  center.x = window.innerWidth / 2;
  center.y = window.innerHeight / 2;
  // transform to path coordinate system
  var matrix = myline.getScreenCTM().inverse();
  center = center.matrixTransform(matrix);

  //find nearest length on path
  var draw = getNearestLength(center);

  // Reverse the drawing (when scrolling upwards)
  myline.style.strokeDashoffset = -draw - pathLength;

  //get point at length
  endPoint = myline.getPointAtLength(draw);
  circle.style.transform = "translate(" + endPoint.x + "px, " + endPoint.y + "px)";
}

function getNearestLength(point) {
  var precision = 8,
      best,
      bestLength,
      bestDistance = Infinity;
  // linear scan for coarse approximation
  for (var scan, scanLength = 0, scanDistance; scanLength <= pathLength; scanLength += precision) {
    if ((scanDistance = distance2(scan = myline.getPointAtLength(scanLength))) < bestDistance) {
      best = scan, bestLength = scanLength, bestDistance = scanDistance;
    }
  }
  // binary search for precise estimate
  precision /= 2;
  while (precision > 0.5) {
    var before,
        after,
        beforeLength,
        afterLength,
        beforeDistance,
        afterDistance;
    if ((beforeLength = bestLength - precision) >= 0 && (beforeDistance = distance2(before = myline.getPointAtLength(beforeLength))) < bestDistance) {
      best = before, bestLength = beforeLength, bestDistance = beforeDistance;
    } else if ((afterLength = bestLength + precision) <= pathLength && (afterDistance = distance2(after = myline.getPointAtLength(afterLength))) < bestDistance) {
      best = after, bestLength = afterLength, bestDistance = afterDistance;
    } else {
      precision /= 2;
    }
  }
  return bestLength;

  function distance2(p) {
    var dx = p.x - point.x,
        dy = p.y - point.y;
    return dx * dx + dy * dy;
  }
}
body {
  height: 2000px;
  background: #f1f1f1;
}

#circle {
  fill: red;
}

#mySVG {
  position: absolute;
  top: 15%;
  width: 100%;
  height: 1000px;
  
}

.st1 {
  fill: none;
  stroke-dashoffset: 3px;
  stroke: grey;
  stroke-width: 4;
  stroke-miterlimit: 10;
  stroke-dasharray: 20;
}
.st0 {
  fill: none;
  stroke-dashoffset: 3px;
  stroke: red;
  stroke-width: 5;
  stroke-miterlimit: 10;
  stroke-dasharray: 20;
  transition: stroke-dashoffset 0.2s;
}

#circle {
   transform: translate(10px, 10px);
   transition: transform 0.2s;
   }
<svg id="mySVG" viewBox="0 0 60 55" preserveAspectRatio="xMidYMin slice" style="width: 6%; padding-bottom: 42%; height: 1px; overflow: visible">
  <path  class="st1" stroke-dasharray="10,9" d="M 20 0 v 20 a 30 30 0 0 0 30 30 h 600 a 40 40 0 0 1 0 80 h -140 a 30 30 0 0 0 0 60 h 200 a 40 40 0 0 1 0 80 h -100 a 30 30 0 0 0 -30 30 v 20" /> Sorry, your browser does not support inline SVG.
</svg>

<svg id="mySVG" viewBox="0 0 60 55" preserveAspectRatio="xMidYMin slice" style="width: 6%; padding-bottom: 42%; height: 1px; overflow: visible">
  <circle id="circle" cx="0" cy="0" r="10"/>
  <path id="myline" class="st0" stroke-dasharray="10,9" d="M 20 0 v 20 a 30 30 0 0 0 30 30 h 600 a 40 40 0 0 1 0 80 h -140 a 30 30 0 0 0 0 60 h 200 a 40 40 0 0 1 0 80 h -100 a 30 30 0 0 0 -30 30 v 20" /> Sorry, your browser does not support inline SVG.
</svg>


我们能否以某种方式缓解滚动或使其平滑,因为在浏览器滚动时感觉非常卡顿?现在在<path>的曲线处,动画只是跳出来了! - Jithin Raj P R
我已经加入了一些想法来扩展答案。 - ccprog
正如我所说,我的解决方案并不一定在过渡时沿着路径移动圆圈。解决这个问题是一个独立的问题。 - ccprog
1
很抱歉,我无法将此标记为答案,因为这不是我正在寻找的结果或答案。该行与滚动不同步,而是从这里跳到那里。 - Jithin Raj P R
1
@ccprog "现在你试图给我施加压力",我猜你自己正在给自己施加压力,他并没有这样做。我必须说,他的问题从一开始就很清楚,而你没有提供他一直在寻找的答案。如果你必须编辑三次才能得到实际结果,那就取决于你了。我不明白为什么你会对此感到冒犯... - Ivan
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接