如何一次(按时间顺序)滚动绘制每个 SVG 路径? [英] How to scroll draw each SVG path one at a time (chronologically)?

查看:24
本文介绍了如何一次(按时间顺序)滚动绘制每个 SVG 路径?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这与此处有关.但是,我认为这是一项艰巨的任务.所以我把它分解成更小的块.

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

 <头><meta charset="UTF-8"><title>单行</title><link rel="stylesheet" type="text/css" href="line.css"><风格>SVG {位置:固定;保证金:自动;顶部:0;左:0;右:0;底部:0;宽度:50%;}/*.线{中风-dashoffset:850;中风-dasharray:850;}.盒子 {中风-dashoffset:1852;中风-dasharray:1852;}*/.全部{中风-dashoffset:2702;中风-dasharray:2702;}.直线{高度:3000px;位置:相对;宽度:360px;边距:40vh 自动 0 自动;}</风格><身体><主要角色=文章"标题=行"><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="保留"><style type="text/css">.st0{fill:none;stroke:#000000;stroke-width:8;stroke-miterlimit:10;}</风格><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>

</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><脚本>$(document).ready(function() {//'stroke-dashoffset'单元的变量var $dashOffset = $(".all").css("stroke-dashoffset");//在滚动事件上 - 执行函数$(窗口).滚动(功能(){//计算用户离页面多远var $percentageComplete = (($(window).scrollTop()/($("html").height() - $(window).height())) * 100);//将dashoffset像素值转换为整数var $newUnit = parseInt($dashOffset, 10);//获取要从'stroke-dashoffset'中减去的值var $offsetUnit = $percentageComplete * ($newUnit/100);//设置dashoffset的新值来创建绘图效果$(".all").css("stroke-dashoffset", $newUnit - $offsetUnit);});});

解决方案

这是怎么回事?您可以通过设置 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() {//在滚动事件上 - 执行函数$(window).scroll(scrollEventHandler);//在开始时调用滚动事件处理程序一次以初始化破折号偏移量滚动事件处理程序();});函数 scrollEventHandler(){//计算用户在页面下方的位置var percentOfScroll = (($(window).scrollTop()/($("html").height() - $(window).height())) * 100);//对于每个被绘制的元素...for (var i=0; i<scrollBehaviour.length; i++){var data = scrollBehaviour[i];var elem = document.getElementById(data.id);//获取这个元素路径的长度var dashLen = calcPathLength(elem);//计算当前滚动位置相对于我们的路径下降的位置var fractionThroughThisElem = (percentOfScroll - data.startPct)/(data.endPct - data.startPct);//将分数值限制在此路径内 (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);}}函数 calcPathLength(elem){如果(elem.getTotalLength){//这是一条路径返回 elem.getTotalLength();}else if (elem.tagName === "rect"){//处理矩形元素:周长长度 = w + w + h + h返回 (elem.width.baseVal.value + elem.height.baseVal.value) * 2;}else if (elem.tagName === "circle"){//处理圆元素:周长长度 = 2 * r * PI返回 elem.r.baseVal.value * 2 * Math.PI;}else if (elem.tagName === "line"){//处理线元素:使用毕达哥拉斯定理var dx = elem.x2.baseVal.value - elem.x1.baseVal.value;var dy = elem.y2.baseVal.value - elem.y1.baseVal.value;返回 Math.sqrt(dx * dx + dy * dy);}//如果您使用其他 elem 类型,则必须在此处添加对它们的支持.}

svg {位置:固定;保证金:自动;顶部:0;左:0;右:0;底部:0;宽度:50%;}/*.线{中风-dashoffset:850;中风-dasharray:850;}.盒子 {中风-dashoffset:1852;中风-dasharray:1852;}.全部{中风-dashoffset:2702;中风-dasharray:2702;}*/.直线{高度:3000px;位置:相对;宽度:360px;边距:40vh 自动 0 自动;}

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script><主要角色=文章"标题=行"><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="保留"><style type="text/css">.st0{fill:none;stroke:#000000;stroke-width:8;stroke-miterlimit:10;}</风格><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>

</main>

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>

解决方案

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>

这篇关于如何一次(按时间顺序)滚动绘制每个 SVG 路径?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆