【问题标题】:Moving SVG path through points通过点移动 SVG 路径
【发布时间】:2021-10-27 17:26:28
【问题描述】:

这可能看起来很奇怪,但我想通过一个固定点移动一些 SVG 路径。我知道我们如何通过<animateMotion> 的路径为点设置动画,我试图获得相同的结果,但点将被固定并且路径将通过它。

到目前为止,我认为我可以使用path.getTotalLength(),我制作了一个循环来在我的路径上创建点,并且我想为我的路径设置动画以使其以每个点为中心,但我对 SVG 和 Javascript 的了解非常有限。

const path = document.getElementById('chemin')
let svg = document.getElementById("mySVG");
let totalLength = path.getTotalLength();
let intersections = 30;

for (var i = 0; i <= intersections; i++) {
    let distance = i * 1 / intersections * totalLength;
    let point = path.getPointAtLength(distance);
    addCircleToSVG(point.x, point.y);
}

function addCircleToSVG(x, y) {
    let circle = document.createElementNS("http://www.w3.org/2000/svg", 'circle');
    circle.setAttribute("cx", x);
    circle.setAttribute("cy", y);
    circle.setAttribute("r", "5");
    circle.setAttribute("fill", "#8888ff");
    svg.appendChild(circle);
}
<div class="svgDiv">
    <svg version="1.1" id="mySVG" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
        x="0px" y="0px" viewBox="0 0 1306 989" style="enable-background:new 0 0 1306 989;" xml:space="preserve">
        <style type="text/css">
            .st1 {
                fill: #fff;
                stroke: #000000;
                stroke-width: 3;
                stroke-miterlimit: 10;
            }

            .st2 {
                fill: none;
                stroke: #ff0000;
                stroke-width: 8;
                stroke-miterlimit: 10;
                stroke-linecap: round;
            }
        </style>
        <g>
            <path id="chemin" class="st2" d="M315,443l13-11h13l13-2h9l7.5,1.5h10l8-4l4-5l15,5l10,4h12h16l16-2l4-1h11h9l8-6h6l8-2l5-3l4-2l5-4l3-3v-4l4-3
                    l5-1h11c0,0,0,0,2,0s12,0,12,0l6,3l3,4l4,4l6,2c0,0,1,0,3-1s6-3,6-3l3-2l5,1h6l8,3l8,1c0,0,4,1,5,1s9,0,9,0l7,1h9h5l6-2l4-1l4-3
                    l5-2l6-4l4-5l4-4l2-5c0,0,1-2,1-4s0-5,0-5v-4c0,0,4,3,4,3l7,2l5,3l6,1l11,2l8,2l7,5l10,2c3-3,6-5,6-5l4-3l4-2l4,2l4-1l-2-6l5-5
                    c0,0,8,3,8,0s4-6,4-6l6-4l3-4l6-6c0,0,0-3-2-7s-5-8-5-8s-2-5-3-9s-4-9-4-11s2-6,1-8s-5-7-5-7v-8l-1-7v-5l-8-11">
            </path>
        </g>
    </svg>

</div>
        

起初这似乎是一个想法,但现在我觉得它不会让我到任何地方,我被卡住了......

编辑: 一张图可能更容易理解 that's the "steps" I want

【问题讨论】:

  • svg 是否居中?还是与每个点相关的线?所以就像在添加点之前线条似乎对每个点进行了动画处理(比如印第安纳琼斯地图样式?或者like this 带点?)是的,抱歉,我仍然不确定我是否正在可视化意图,稍后会重新访问为了好玩,很快就出发了。 :D
  • 我添加了一张图片来显示我正在尝试做的事情,它可能会有所帮助 ^^' 点始终居中,路径通过它并遵循它自己的路径......没问题,谢谢!
  • 您想逐个突出显示每个点,然后将路径转换为该点坐标?

标签: javascript animation svg path


【解决方案1】:

主要思想是我在更改路径上圆的位置时更改了 svg 元素的 viewBox 属性的值。这给人一种错觉,即路径在移动,而不是点。

我正在使用输入类型范围来移动圆圈。

start 变量表示路径开始的点 (d="M315,443...) 以及点的初始位置:&lt;circle cx="315" cy="443"

请阅读代码中的cmets。

let lengthChemin = chemin.getTotalLength();
// the starting point of the circle on the path
let start={x:315,y:443}

//while moving the thumb of the slider
control.addEventListener("input", ()=>{
  // get the actual value of the input
  let val = parseInt(control.value);
  //get the new position of the circle on the path
  let pos = chemin.getPointAtLength(lengthChemin*val/100);
  //update the circle's position
  updateElement({cx:pos.x, cy:pos.y}, circle)
  //update the viewBox value
  theSVG.setAttribute("viewBox",`${pos.x - start.x} ${pos.y - start.y} 1306 600`)
})


function updateElement(o, element) {
  for (var name in o) {
    if (o.hasOwnProperty(name)) {
      element.setAttributeNS(null, name, o[name]);
    }
  }
  return element;
}
<input id="control" type="range" min="0" max="100" value="0" />

<svg id="theSVG" viewBox="0 0 1306 600">

  <g transform="translate(0,-250)">
    <path id="chemin" stroke="red" stroke-width="3" fill="none"  d="M315,443l13-11h13l13-2h9l7.5,1.5h10l8-4l4-5l15,5l10,4h12h16l16-2l4-1h11h9l8-6h6l8-2l5-3l4-2l5-4l3-3v-4l4-3
                    l5-1h11c0,0,0,0,2,0s12,0,12,0l6,3l3,4l4,4l6,2c0,0,1,0,3-1s6-3,6-3l3-2l5,1h6l8,3l8,1c0,0,4,1,5,1s9,0,9,0l7,1h9h5l6-2l4-1l4-3
                    l5-2l6-4l4-5l4-4l2-5c0,0,1-2,1-4s0-5,0-5v-4c0,0,4,3,4,3l7,2l5,3l6,1l11,2l8,2l7,5l10,2c3-3,6-5,6-5l4-3l4-2l4,2l4-1l-2-6l5-5
                    c0,0,8,3,8,0s4-6,4-6l6-4l3-4l6-6c0,0,0-3-2-7s-5-8-5-8s-2-5-3-9s-4-9-4-11s2-6,1-8s-5-7-5-7v-8l-1-7v-5l-8-11">
    </path>
    
    <circle id="circle" cx="315" cy="443" r="10"/>
  </g>
  
  
</svg>

观察:我只翻译带有路径和圆圈的组,因为我希望它在您运行 sn-p 时可见。您可以删除它。

【讨论】:

  • 这正是我的想法,非常感谢!因此,如果我理解得很好,更改 viewBox 的值将使所有其他元素(我有更多的正方形和点)以与路径相同的方式移动,对吗? (只是为了确定,这实际上是我想要的)
  • 基本上是的,但一切都取决于你所拥有的。如果事情没有按您的预期进行,请提出一个包含所有详细信息的不同问题。我很乐意提供帮助。
  • 注意:如果你将默认的pathLength (see MDN)设置为100,你可能不需要任何输入计算
【解决方案2】:

const path = document.getElementById('chemin')
const svg = document.getElementById("mySVG");
const rect = svg.getAttribute('viewBox').split(' ');

const cx = rect[2]/2;
const cy = rect[3]/5; // Should be /2 (to not be out of small view field here)

const circle = svg.querySelector('circle');
circle.setAttribute('cx', cx);
circle.setAttribute('cy', cy);

const intersections = 30;
const timeStep = 500;

const points = [];

for(let i=0; i <= intersections; i++){
    points.push(path.getPointAtLength((path.getTotalLength()/intersections)*i));
}

points.forEach((p,i) => {
    setTimeout(() => {movePath(p)}, timeStep*i);
})

function movePath(point){
    path.setAttribute('transform', `translate(${cx-point.x}, ${cy-point.y})`);
}
<div class="svgDiv">
    <svg version="1.1" id="mySVG" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
        x="0px" y="0px" viewBox="0 0 1306 989" style="enable-background:new 0 0 1306 989;" xml:space="preserve">
        <style type="text/css">
            .st1 {
                fill: #fff;
                stroke: #000000;
                stroke-width: 3;
                stroke-miterlimit: 10;
            }

            .st2 {
                fill: none;
                stroke: #ff0000;
                stroke-width: 8;
                stroke-miterlimit: 10;
                stroke-linecap: round;
            }
        </style>
        <g>
            <path id="chemin" class="st2" d="M315,443l13-11h13l13-2h9l7.5,1.5h10l8-4l4-5l15,5l10,4h12h16l16-2l4-1h11h9l8-6h6l8-2l5-3l4-2l5-4l3-3v-4l4-3
                    l5-1h11c0,0,0,0,2,0s12,0,12,0l6,3l3,4l4,4l6,2c0,0,1,0,3-1s6-3,6-3l3-2l5,1h6l8,3l8,1c0,0,4,1,5,1s9,0,9,0l7,1h9h5l6-2l4-1l4-3
                    l5-2l6-4l4-5l4-4l2-5c0,0,1-2,1-4s0-5,0-5v-4c0,0,4,3,4,3l7,2l5,3l6,1l11,2l8,2l7,5l10,2c3-3,6-5,6-5l4-3l4-2l4,2l4-1l-2-6l5-5
                    c0,0,8,3,8,0s4-6,4-6l6-4l3-4l6-6c0,0,0-3-2-7s-5-8-5-8s-2-5-3-9s-4-9-4-11s2-6,1-8s-5-7-5-7v-8l-1-7v-5l-8-11">
            </path>
        </g>
        <circle cx="0" cy="0" r="5" fill="#8888ff"></circle>
    </svg>
</div>

【讨论】:

    猜你喜欢
    • 2017-03-29
    • 1970-01-01
    • 1970-01-01
    • 2012-05-22
    • 2017-03-30
    • 1970-01-01
    • 2020-04-05
    • 1970-01-01
    • 2013-01-27
    相关资源
    最近更新 更多