【问题标题】:How to scroll draw each SVG path one at a time (chronologically)?如何一次滚动绘制每个 SVG 路径(按时间顺序)?
【发布时间】:2016-01-04 02:42:37
【问题描述】:

这与之前的帖子here 有关。但是,我认为这是一项艰巨的任务。所以我把它分解成更小的块。

我制作了一个简单的 SVG 图像,其中包含一个“路径”和一个“矩形”元素。用户可以通过向上和向下滚动页面(向下滚动页面以打开页面,向上滚动页面以关闭/“取消绘制”)来在窗口上和窗口外绘制线条。但是,两个元素同时“绘制”/动画。我想要做的是当用户向下滚动页面时,线条路径绘制,然后“rect”元素绘制(之后),所以它更加流畅和按时间顺序排列。

 <!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>

【问题讨论】:

    标签: javascript jquery css svg scroll


    【解决方案1】:

    这是怎么回事?您可以通过在scrollBehaviour 数组中设置startPctendPct 百分比值来控制每条路径何时开始和结束绘制。

    注意:此代码假定您只使用路径和矩形。如果您开始使用其他元素,则必须更新 calcPathLength() 函数。

    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>

    【讨论】:

    • 嘿,保罗。一些伟大的标记。对不起,我还没有感谢你。我一直在玩它并更多地理解它。我无法理解的一部分是更新代码以包含其他形状元素,例如“圆形”、“椭圆”和“文本”。我可以更新这个.... var scrollBehaviour = [ {id: 'line1', startPct: 0, endPct: 40}, {id: 'rect1', startPct: 40, endPct: 100}, ];但不是这个.... // 假设它是一个矩形。 // 如果你使用其他元素类型,你必须在这里添加对它们的支持。返回 (elem.width.baseVal.value + elem.height.baseVal.value) * 2; } }
    • 您将需要对其他元素类型使用不同的计算(基于不同的属性)。例如,对于一个圆圈,您需要查看r 属性。我更新了示例以展示如何确定元素类型。
    • 老实说,我应该付钱给你。很抱歉再次打扰你,保罗。你似乎是万维网上唯一一个愿意帮助我的人,不管我变得多么烦人。只是为了看看我是否正确理解了这一点(温柔,我是 JS 新手)我是否需要为每个属性添加 else if (elem.tagName === "rect") 。此示例适用于矩形 svg 元素。 tagName==="xy" 将用于线 svg 属性的长度?
    • 您将检查每个 SVG 元素(“line”、“circle”等)的tagName,然后使用特定于该形状的属性计算正确的形状长度。所以对于circle,它将是r 属性等。我会为你添加一些额外的例子。
    • 不要对.baseVal.value 的东西感到困惑。这就是您访问 SVG DOM 中属性值的方式。 DOM 只是文档的内部 JS 表示。因此,如果elem 指向&lt;rect&gt; 元素的内部JS 版本,则可以使用elem.width. However the width value is not stored directly in elem.width` 获取width 属性,因为宽度(可能)是可动画的。所以width 对象更复杂。
    猜你喜欢
    • 1970-01-01
    • 2014-06-14
    • 2019-12-31
    • 2021-10-06
    • 2022-01-09
    • 2020-10-14
    • 1970-01-01
    • 2021-09-09
    • 2021-10-16
    相关资源
    最近更新 更多