SVG Animation: Объект вдоль пути на свитке - PullRequest
0 голосов
/ 07 ноября 2018

Я создал SVG анимацию: объект вдоль пути на свитке .

Пожалуйста, проверьте код и демо Codepen

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

#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

$(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;
    }    
});

Пожалуйста, проверьте демо Codepen: https://codepen.io/yesvin/pen/XymwvX

Проблема в том, что объект (например, автомобиль) внутри SVG не вращается сам по пути. Я пытался с преобразованием вращения, но он не работает. Пожалуйста, проверьте закомментированную строку функции атрибута набора SVG.

Итак, как добиться того, чтобы объект вращался по дорожке на свитке? Есть ли другие расчеты для расчета угла объекта и длины пути?

Заранее спасибо.

1 Ответ

0 голосов
/ 07 ноября 2018

Проблема в центре поворота и начальном угле. В настоящее время начальное положение автомобиля таково, что его центр вращения должен быть в (171, 21). Вы можете начать с перевода этой точки в (0, 0), а затем повернуть ее на -65 градусов так, чтобы она указала вправо. В этом случае проще переписать данные пути, чтобы включить эти преобразования:

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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...