简体   繁体   English

SVG动画:沿滚动路径的对象

[英]SVG Animation: Object along a path on a scroll

I have created an SVG animation: Object along a path on a scroll . 我创建了一个SVG动画:沿着滚动路径的对象

Please check the below code and Codepen demo 请检查以下代码和Codepen演示

HTML HTML

    <circle r="2" cy="18.591" cx="169.887" fill="red" fill-opacity=".96" fill-rule="evenodd" stroke="red" stroke-width=".55"/>
    <circle r="2" id="dot" cy="-5" cx="0"  fill="red" fill-opacity=".96" fill-rule="evenodd" stroke="red" stroke-width=".55"/>

    <path id="c" d="M174.093 22.89a.384.384 0 0 0-.148.037l-.921.437-.002-.009a.113.113 0 0 0-.151-.054l-.978.463a.113.113 0 0 0-.054.151l.005.007-1.049.497a.384.384 0 0 0-.183.512l2.25 4.747c.066.14.205.22.35.219-.056.058-.101.15-.04.28l1.395 2.942-.498-.03a.134.134 0 0 0-.016.267l.644.04.602 1.27c.25.527.874.75 1.4.5l.346-.164a.113.113 0 0 0 .155.14l.978-.463a.113.113 0 0 0-.01-.209l.346-.164c.527-.249.75-.874.5-1.4l-.68-1.437.439-.45a.133.133 0 0 0-.003-.189.133.133 0 0 0-.19.002l-.369.379-1.306-2.757c-.069-.155-.164-.195-.25-.193a.382.382 0 0 0 .048-.404l-2.248-4.747a.384.384 0 0 0-.363-.22z" fill="#1a1a1a" fill-rule="evenodd"/>
</svg>

CSS CSS

#route {
  margin-top: 200px;
}

.code {
  height:150px;
  width:250px;
  background:#000;
  color:#fff;
  margin:20px;
  width: 40%;
  clear: both;
  height: 200px;
  background: #000;
  border-radius: 2px;
  margin: 100vh 0;
  padding: 10px;
}

JS JS

$(document).ready(function(){           
    $(window).scroll(function() {
        drawLine( $('#bx_a'),document.getElementById('path') );
        positionTheDot();
        //positionCar();            
    });

    // init the line length
    drawLine( $('#bx_a'),document.getElementById('path') );
    positionTheDot();       
    //positionCar();

    function positionTheDot() {
    // What percentage down the page are we? 
    var scrollPercentage = (document.documentElement.scrollTop + document.body.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight);
    // Get path length
    var path = document.getElementById("path");
    var pathLen = path.getTotalLength();
    // Get the position of a point at <scrollPercentage> along the path.
    var pt = path.getPointAtLength(scrollPercentage * pathLen);
    var  scrollY = window.scrollY || window.pageYOffset;
    var  maxScrollY = document.documentElement.scrollHeight - window.innerHeight;
   var  path = document.getElementById("path");
   // Calculate distance along the path the car should be for the current scroll amount
   var  pathLen = path.getTotalLength();
   var  dist = pathLen * scrollY / maxScrollY;
   var  pos = path.getPointAtLength(dist);
   // Calculate position a little ahead of the car (or behind if we are at the end), so we can calculate car angle
   if (dist + 1 <= pathLen) {
    var  posAhead = path.getPointAtLength(dist + 1);
    var  angle = Math.atan2(posAhead.y - pos.y, posAhead.x - pos.x);
   } else {
    var  posBehind = path.getPointAtLength(dist - 1);
    var  angle = Math.atan2(pos.y - posBehind.y, pos.x - posBehind.x);
   }

   // Position the red dot at this point
   var dot = document.getElementById("dot");          
   dot.setAttribute("transform", "translate("+ pt.x + "," + (pt.y+5) + ")");        
   var  car = document.getElementById("c");
   car.setAttribute("transform", "translate(" + (pt.x-171) + "," + (pt.y-21) + ")");
   //car.setAttribute("transform", "translate(" + (pt.x-171) + "," + (pt.y) + ") rotate(" + (rad2deg(angle)) + ")");
   };

   //draw the line
   function drawLine(container, line) {
    var pathLength = line.getTotalLength(),
    maxScrollTop = $(document).height() - $(window).height(),
    percentDone = $(window).scrollTop() / maxScrollTop,
    length = percentDone * pathLength;
    line.style.strokeDasharray = [ length,pathLength].join(' ');
   }

   function positionCar() {
    var  scrollY = window.scrollY || window.pageYOffset;
    var  maxScrollY = document.documentElement.scrollHeight - window.innerHeight;
    var  path = document.getElementById("path");
    // Calculate distance along the path the car should be for the current scroll amount
    var  pathLen = path.getTotalLength();
    var  dist = pathLen * scrollY / maxScrollY;
    var  pos = path.getPointAtLength(dist);
    // Calculate position a little ahead of the car (or behind if we are at the end), so we can calculate car angle
    if (dist + 1 <= pathLen) {
        var  posAhead = path.getPointAtLength(dist + 1);
        var  angle = Math.atan2(posAhead.y - pos.y, posAhead.x - pos.x);
    } else {
        var  posBehind = path.getPointAtLength(dist - 1);
        var  angle = Math.atan2(pos.y - posBehind.y, pos.x - posBehind.x);
    }
    // Position the car at "pos" totated by "angle"
    var  car = document.getElementById("c");
    car.setAttribute("transform", "translate(" + (pos.x) + "," + (pos.y) + ") rotate(" + (rad2deg(angle)) + ")");
    }

    function rad2deg(rad) {
        return 180 * rad / Math.PI;
    }    
});

Please check the Codepen demo: https://codepen.io/yesvin/pen/XymwvX 请检查Codepen演示: https ://codepen.io/yesvin/pen/XymwvX

The problem is that the object (ex: Car) inside the SVG is not rotating itself along the path. 问题在于SVG内部的对象(例如Car)没有沿路径旋转。 I tried with the transform rotation but it is not working. 我尝试了变换旋转,但无法正常工作。 Please check the commented line of the SVG set attribute function. 请检查SVG设置属性功能的注释行。

So, How to achieve, that the object has to rotate itself along a path on a scroll? 那么,如何实现对象必须沿着滚动路径旋转呢? Is there any other calculations to calculate the objects angle and path's length? 是否还有其他计算方法可以计算物体的角度和路径的长度?

Thanks in advance. 提前致谢。

The issue is the center of rotation, and the initial angle. 问题是旋转中心和初始角度。 Currently, the initial position of the car is such that its rotation center should be at (171, 21). 当前,汽车的初始位置应使其旋转中心位于(171,21)。 You could start out with translating that point to (0, 0), and then rotate it by -65deg so that it points to the right. 您可以首先将该点转换为(0,0),然后将其旋转-65deg,使其指向右侧。 In this case, it is easier to rewrite the path data to incorporate these transformations: 在这种情况下,更容易重写路径数据以合并以下转换:

d="M 3.02008,-2.00446 A 0.384,0.384 0 0 0 2.99106,-1.85469 L 2.99789,-0.835296 2.98889,-0.837286 A 0.113,0.113 0 0 0 2.87613,-0.723255 L 2.88243,0.358786 A 0.113,0.113 0 0 0 2.99646,0.471542 L 3.00492,0.469969 3.01203,1.63073 A 0.384,0.384 0 0 0 3.39872,2.01296 L 8.65185,1.97994 C 8.80663,1.97929 8.93788,1.88712 8.99825,1.75528 9.02715,1.83055 9.09151,1.91021 9.23511,1.90987 L 12.491,1.88891 12.2534,2.32758 A 0.134,0.134 0 0 0 12.4886,2.45492 L 12.797,1.88816 14.2024,1.87929 C 14.7857,1.87543 15.2515,1.40414 15.2473,0.821764 L 15.2448,0.438872 A 0.113,0.113 0 0 0 15.4372,0.357561 L 15.4309,-0.72448 A 0.113,0.113 0 0 0 15.2373,-0.803744 L 15.2349,-1.18664 C 15.2319,-1.76949 14.7597,-2.23574 14.1774,-2.23146 L 12.5876,-2.22247 12.3653,-2.81052 A 0.133,0.133 0 0 0 12.1927,-2.88767 0.133,0.133 0 0 0 12.1143,-2.71463 L 12.3018,-2.22003 9.25118,-2.20155 C 9.08154,-2.20452 9.00514,-2.13533 8.9706,-2.05654 A 0.382,0.382 45 0 0 8.62474,-2.27078 L 3.37245,-2.23957 A 0.384,0.384 0 0 0 3.01965,-2.00355 Z"

 $(document).ready(function(){ $(window).scroll(function() { drawLine( $('#bx_a'),document.getElementById('path') ); positionTheDot(); positionCar(); }); // init the line length drawLine( $('#bx_a'),document.getElementById('path') ); positionTheDot(); positionCar(); function positionTheDot() { // What percentage down the page are we? var scrollPercentage = (document.documentElement.scrollTop + document.body.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight); // Get path length var path = document.getElementById("path"); var pathLen = path.getTotalLength(); // Get the position of a point at <scrollPercentage> along the path. var pt = path.getPointAtLength(scrollPercentage * pathLen); var scrollY = window.scrollY || window.pageYOffset; var maxScrollY = document.documentElement.scrollHeight - window.innerHeight; var path = document.getElementById("path"); // Calculate distance along the path the car should be for the current scroll amount var pathLen = path.getTotalLength(); var dist = pathLen * scrollY / maxScrollY; var pos = path.getPointAtLength(dist); // Calculate position a little ahead of the car (or behind if we are at the end), so we can calculate car angle if (dist + 1 <= pathLen) { var posAhead = path.getPointAtLength(dist + 1); var angle = Math.atan2(posAhead.y - pos.y, posAhead.x - pos.x); } else { var posBehind = path.getPointAtLength(dist - 1); var angle = Math.atan2(pos.y - posBehind.y, pos.x - posBehind.x); } // Position the red dot at this point var dot = document.getElementById("dot"); dot.setAttribute("transform", "translate("+ pt.x + "," + (pt.y+5) + ")"); }; //draw the line function drawLine(container, line) { var pathLength = line.getTotalLength(), maxScrollTop = $(document).height() - $(window).height(), percentDone = $(window).scrollTop() / maxScrollTop, length = percentDone * pathLength; line.style.strokeDasharray = [ length,pathLength].join(' '); } function positionCar() { var scrollY = window.scrollY || window.pageYOffset; var maxScrollY = document.documentElement.scrollHeight - window.innerHeight; var path = document.getElementById("path"); // Calculate distance along the path the car should be for the current scroll amount var pathLen = path.getTotalLength(); var dist = pathLen * scrollY / maxScrollY; var pos = path.getPointAtLength(dist); // Calculate position a little ahead of the car (or behind if we are at the end), so we can calculate car angle if (dist + 1 <= pathLen) { var posAhead = path.getPointAtLength(dist + 1); var angle = Math.atan2(posAhead.y - pos.y, posAhead.x - pos.x); } else { var posBehind = path.getPointAtLength(dist - 1); var angle = Math.atan2(pos.y - posBehind.y, pos.x - posBehind.x); } // Position the car at "pos" totated by "angle" var car = document.getElementById("c"); car.setAttribute("transform", "translate(" + (pos.x) + "," + (pos.y) + ") rotate(" + (rad2deg(angle)) + ")"); } function rad2deg(rad) { return 180 * rad / Math.PI; } }); 
 #route { margin-top: 200px; } .code { height:150px; width:250px; background:#000; color:#fff; margin:20px; width: 40%; clear: both; height: 200px; background: #000; border-radius: 2px; margin: 100vh 0; padding: 10px; } svg { /*width:100%; height:auto;*/ } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div style="position:absolute; top:0; right:0; width:100%; height:auto; background:url('background-map.jpg') no-repeat;" id="route"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 334 1426" id="svgRoute"> <path id="path" d="M170 19s18 32 18 57c0 48-40 51-40 72 0 22 43 31 43 44 0 10-9.4 10-10 23-.7 14 2.3 16 2.2 28-.17 12-14 24-21 32-6.5 7.2-17 15-20 23-2.4 6.8-3.5 23 12 29 16 5.7 32 10 37 24 5.2 13-7.4 26-17 33-9.2 6.6-30 20-26 30 3.5 9.9 27 6.2 27 24 0 18 8.8 13 8.8 24-11 24 16 50 13 71-.46 17-15 23-8.2 42-32 37 1.3 83 26 106 28 20-33 5.7-33 39 2.4 51-28 113-34 139-4.1 18-3.5 41 18 41 8.1-.2 14-6.5 15-14 .37-6.3-6.1-14-16-12-11 1.8-16 11-19 24-1.3 6.6-2.1 17-2.3 28-.43 29 14 36 19 39 2.6 1.8 19 8.8 19 17 10 18-41 7.8-35 28 .61 10 37 22 36 35 8.4 94-128 42-89 130 8.8 36-63 33-60 68-2.1 25 35 32 38 44" stroke="red" fill="none"/> <circle r="2" cy="18.591" cx="169.887" fill="red" fill-opacity=".96" fill-rule="evenodd" stroke="red" stroke-width=".55"/> <circle r="2" id="dot" cy="-5" cx="0" fill="red" fill-opacity=".96" fill-rule="evenodd" stroke="red" stroke-width=".55"/> <path id="c" d="M 3.02008,-2.00446 A 0.384,0.384 0 0 0 2.99106,-1.85469 L 2.99789,-0.835296 2.98889,-0.837286 A 0.113,0.113 0 0 0 2.87613,-0.723255 L 2.88243,0.358786 A 0.113,0.113 0 0 0 2.99646,0.471542 L 3.00492,0.469969 3.01203,1.63073 A 0.384,0.384 0 0 0 3.39872,2.01296 L 8.65185,1.97994 C 8.80663,1.97929 8.93788,1.88712 8.99825,1.75528 9.02715,1.83055 9.09151,1.91021 9.23511,1.90987 L 12.491,1.88891 12.2534,2.32758 A 0.134,0.134 0 0 0 12.4886,2.45492 L 12.797,1.88816 14.2024,1.87929 C 14.7857,1.87543 15.2515,1.40414 15.2473,0.821764 L 15.2448,0.438872 A 0.113,0.113 0 0 0 15.4372,0.357561 L 15.4309,-0.72448 A 0.113,0.113 0 0 0 15.2373,-0.803744 L 15.2349,-1.18664 C 15.2319,-1.76949 14.7597,-2.23574 14.1774,-2.23146 L 12.5876,-2.22247 12.3653,-2.81052 A 0.133,0.133 0 0 0 12.1927,-2.88767 0.133,0.133 0 0 0 12.1143,-2.71463 L 12.3018,-2.22003 9.25118,-2.20155 C 9.08154,-2.20452 9.00514,-2.13533 8.9706,-2.05654 A 0.382,0.382 45 0 0 8.62474,-2.27078 L 3.37245,-2.23957 A 0.384,0.384 0 0 0 3.01965,-2.00355 Z" fill="#1a1a1a" fill-rule="evenodd"/> </svg> </div> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM