Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
237 views
in Technique[技术] by (71.8m points)

javascript - How to scroll draw each SVG path one at a time (chronologically)?

This is related to a previous post here. However, I think it was a bit of a momentous task. So I am breaking it down to smaller chunks.

I have made a simple SVG image that includes one "path" and one "rect" element. The user can draw the lines on and off the window by scrolling up and down the page (scroll down the page for on and up the page for off/"undraw). However, both elements "draw"/animate at the same time. What I want to do is as the user scrolls down the page, the line path draws on, then the "rect" element draws (after), so it's more fluid and chronological.

 <!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>the single line</title>
<link rel="stylesheet" type="text/css" href="line.css">

<style>
svg {
  position: fixed;
  margin: auto;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  width: 50%;
}
/*.line{
  stroke-dashoffset:850;
  stroke-dasharray: 850;
}
.box {
 stroke-dashoffset:1852;
 stroke-dasharray: 1852;
}*/
.all{
 stroke-dashoffset:2702;
 stroke-dasharray: 2702;
}

.straightLine {
  height: 3000px;
  position: relative;
  width: 360px;    
  margin: 40vh auto 0 auto;

}
</style>
</head>

<body>

<main role="article" title="line">
<div class="straightLine">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"

     viewBox="0 0 1280 800" style="enable-background:new 0 0 1280 800;" xml:space="preserve">

<style type="text/css">

    .st0{fill:none;stroke:#000000;stroke-width:8;stroke-miterlimit:10;}

</style>
<g class="all">

<path class="st0" d="M54,178h509.6c49.9,0,90.4,40.5,90.4,90.4V428"/>


<rect x="498" y="428" class="st0" width="308" height="162"/>

</g>
</svg>



</div>
</main>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="line.js"></script>
<script>
$(document).ready(function() {
  //variable for the 'stroke-dashoffset' unit
  var $dashOffset = $(".all").css("stroke-dashoffset");
  //on a scroll event - execute function
  $(window).scroll(function() {
    //calculate how far down the page the user is 
    var $percentageComplete = (($(window).scrollTop() / ($("html").height() - $(window).height())) * 100);
    //convert dashoffset pixel value to interger
    var $newUnit = parseInt($dashOffset, 10);
    //get the value to be subtracted from the 'stroke-dashoffset'
    var $offsetUnit = $percentageComplete * ($newUnit / 100);
    //set the new value of the dashoffset to create the drawing effect
    $(".all").css("stroke-dashoffset", $newUnit - $offsetUnit);
  });
});
</script>
</body>
</html>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

How is this? You can control when each path starts and finishes drawing by setting the startPct and endPct percentage values in the scrollBehaviour array.

Note: this code assumes you are only using paths and rects. If you start using other elements, the calcPathLength() function will have to be updated.

var scrollBehaviour = [
     {id: 'line1', startPct: 0, endPct: 30},
     {id: 'rect1', startPct: 30, endPct: 60},
     {id: 'line2', startPct: 60, endPct: 80},
     {id: 'circ1', startPct: 80, endPct: 100}
  ];

$(document).ready(function() {

  // On a scroll event - execute function
  $(window).scroll(scrollEventHandler);

  // Call the scroll event handler once at the start to initialise the dash offsets
  scrollEventHandler();

});



function scrollEventHandler()
{
  // Calculate how far down the page the user is 
  var percentOfScroll = (($(window).scrollTop() / ($("html").height() - $(window).height())) * 100);

  // For each lement that is getting drawn...
  for (var i=0; i<scrollBehaviour.length; i++)
  {
    var data = scrollBehaviour[i];
    var elem = document.getElementById(data.id);

    // Get the length of this elements path
    var dashLen = calcPathLength(elem);

    // Calculate where the current scroll position falls relative to our path
    var fractionThroughThisElem = (percentOfScroll - data.startPct) / (data.endPct - data.startPct);
    // Clamp the fraction value to within this path (0 .. 1)
    fractionThroughThisElem = Math.max(fractionThroughThisElem, 0);
    fractionThroughThisElem = Math.min(fractionThroughThisElem, 1);

    var dashOffset = dashLen * (1 - fractionThroughThisElem);

    elem.setAttribute("stroke-dasharray", dashLen);
    elem.setAttribute("stroke-dashoffset", dashOffset);
  }
}



function calcPathLength(elem)
{
  if (elem.getTotalLength)
  {
    // It's a path
    return elem.getTotalLength();
  }
  else if (elem.tagName === "rect")
  {
    // Handle rect elements: perimeter length = w + w + h + h
    return (elem.width.baseVal.value + elem.height.baseVal.value) * 2;
  }
  else if (elem.tagName === "circle")
  {
    // Handle circle elements: perimeter length = 2 * r * PI
    return elem.r.baseVal.value * 2 * Math.PI;
  }
  else if (elem.tagName === "line")
  {
    // Handle line elements: use pythagoras' theorem
    var dx = elem.x2.baseVal.value - elem.x1.baseVal.value;
    var dy = elem.y2.baseVal.value - elem.y1.baseVal.value;
    return Math.sqrt(dx * dx + dy * dy);
  }
  // If you use other elem types, you will have to add support for them here.
}
svg {
  position: fixed;
  margin: auto;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  width: 50%;
}
/*.line{
  stroke-dashoffset:850;
  stroke-dasharray: 850;
}
.box {
 stroke-dashoffset:1852;
 stroke-dasharray: 1852;
}
.all{
 stroke-dashoffset:2702;
 stroke-dasharray: 2702;
}*/

.straightLine {
  height: 3000px;
  position: relative;
  width: 360px;    
  margin: 40vh auto 0 auto;

}
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>

<main role="article" title="line">
<div class="straightLine">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"

     viewBox="0 0 1280 1000" style="enable-background:new 0 0 1280 800;" xml:space="preserve">

<style type="text/css">

    .st0{fill:none;stroke:#000000;stroke-width:8;stroke-miterlimit:10;}

</style>
  <g class="all">

    <path id="line1" class="st0" d="M54,178h509.6c49.9,0,90.4,40.5,90.4,90.4V428"/>

    <rect id="rect1" x="498" y="428" class="st0" width="308" height="162"/>

    <line id="line2" x1="652" y1="590" x2="652" y2="790" class="st0"/>

    <circle id="circ1" cx="652" cy="890" r="100" class="st0"/>

  </g>
</svg>



</div>
</main>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...