SVG` <path>`javascript动画无法按预期工作

weB*_*Ber 13 javascript css html5 svg css3

我取得了什么:

// 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);

}
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

我要的是无论哪个大小形状SVG <path>是不断增长的线应该是在屏幕的中间.

我尝试改变myline.style.strokeDashoffset = length //+newvalue - draw;所有的值,但它所做的只是破坏了一致性.那么有谁可以帮我解决这个问题.

任何帮助都将是非常值得赞赏的.

Dev*_*h J 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();
});
Run Code Online (Sandbox Code Playgroud)
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);
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)


mic*_*ico 7

我尝试了几种方法让点移动

  • 在盒子里面
  • 直到结束才滑开
  • 对原始版本的改动很小.

我做了以下更改(下面的工作示例):

  • 分配器为百分比我把2000(等于2000px,包含身高)
  • 我将滚动量从顶部乘以18(无论顶部或底部是否表现得很好,合适的值都是妥协)
  • 然后最后我检查了百分比值不大于一(它开始从另一端吃'蠕虫').

而已!也许不是最高级的,但有效.

这里有问题的是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);
}
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)