【问题标题】:Move an object through set of coordinates on HTML5 Canvas通过 HTML5 Canvas 上的一组坐标移动对象
【发布时间】:2020-10-06 14:34:23
【问题描述】:

我想通过坐标数组(例如:{(300,400), (200,300), (300,200),(400,400)} ) 在 HTML5 画布上。我可以将对象移动到一个坐标,如下所示。以下代码在 (100,100) 处绘制一个圆圈并将其移动到 (300,400)。当我试图扩展它时我被卡住了,这样圆圈一个接一个地穿过一组坐标。

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

//circle object

let circle ={
x:100, 
y:100,
radius:10,
dx:1,
dy:1,
color:'blue'
}

//function to draw above circle on canvas 
function drawCircle(){

        ctx.beginPath();
        ctx.arc(circle.x,circle.y,circle.radius,0,Math.PI*2);
        ctx.fillStyle=circle.color;
        ctx.fill();
        ctx.closePath();
}

//Moving to a target coordinate (targetX,targetY)

function goTo(targetX,targetY){

        if(Math.abs(circel.x-targetX)<circle.dx && Math.abs(circel.y-targetY)<circle.dy){

            circle.dx=0;
            circle.dy=0;
            circel.x = targetX;
            circle.y = targetY;
        }

        else{

        const opp = targetY - circle.y;
        const adj = targetX - circle.x;

        const angle = Math.atan2(opp,adj)

        circel.x += Math.cos(angle)*circle.dx
        circle.y += Math.sin(angle)*circle.dy

        }

}


function update(){
         ctx.clearRect(0,0,canvas.width,canvas.height);
         
         drawCircle()
         goTo(300,400)
         requestAnimationFrame(update);

}

update()

【问题讨论】:

    标签: javascript canvas


    【解决方案1】:

    随机访问关键帧

    为了对动画进行最佳控制,您需要创建可按时间随机访问的路径点(关键帧)。这意味着您可以通过设置时间来获得动画中的任何位置。

    然后您可以播放和暂停、设置速度、反转和寻找动画中的任何位置。

    示例

    下面的示例使用一组点并添加所需的数据,以便在请求的时间快速定位关键帧并插入位置。

    蓝点将在pathTime 设置的时间内以恒定速度在路径上移动,在这种情况下为 4 秒。

    红点的位置由滑块设置。这是为了说明动画位置的随机访问。

    const ctx = canvas.getContext('2d');
    const pathTime = 4; // Total time to travel path from start to end in seconds
    var startTime, animTime = 0, paused = false;
    requestAnimationFrame(update);
    const P2 = (x, y) => ({x, y, dx: 0,dy: 0,dist: 0, start: 0, end: 0});
    const pathCoords = [
      P2(20, 20), P2(100, 50),P2(180, 20), P2(150, 100), P2(180, 180),   
      P2(100, 150), P2(20, 180), P2(50, 100), P2(20, 20),
    ];
    createAnimationPath(pathCoords);
    const circle ={
        draw(rad = 10, color = "blue") {
            ctx.fillStyle = color;
            ctx.beginPath();
            ctx.arc(this.x, this.y, rad, 0, Math.PI * 2);
            ctx.fill();
        }
    };
    function createAnimationPath(points) { // Set up path for easy random position lookup
        const segment = (prev, next) => {
            [prev.dx, prev.dy] = [next.x - prev.x, next.y - prev.y];
            prev.dist = Math.hypot(prev.dx, prev.dy);
            next.end = next.start = prev.end = prev.start + prev.dist;
        }
        var i = 1;
        while (i < points.length) { segment(points[i - 1], points[i++]) }
    }
    function getPos(path, pos, res = {}) {
        pos = (pos % 1) * path[path.length - 1].end;       // loop & scale to total length 
        const pathSeg = path.find(p => pos >= p.start && pos <= p.end);
        const unit = (pos - pathSeg.start) / pathSeg.dist; // unit distance on segment
        res.x = pathSeg.x + pathSeg.dx * unit;             // x, y position on segment
        res.y = pathSeg.y + pathSeg.dy * unit;
        return res;
    }
    function update(time){
        // startTime ??= time;         // Throws syntax on iOS
        startTime = startTime ?? time; // Fix for above
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        if (paused) { startTime = time - animTime }
        else { animTime = time - startTime }
        getPos(pathCoords, (animTime / 1000) / pathTime, circle).draw(); 
        getPos(pathCoords, timeSlide.value, circle).draw(5, "red"); 
        requestAnimationFrame(update);
    }
    pause.addEventListener("click", ()=> { paused = true; pause.classList.add("pause") });
    play.addEventListener("click", ()=> { paused = false; pause.classList.remove("pause") });
    rewind.addEventListener("click", ()=> { startTime = undefined; animTime = 0 });
    div {
        position:absolute;
        top: 5px;
        left: 20px;
    }
    #timeSlide {width: 360px}
    .pause {color:blue}
    button {height: 30px}
    <div><input id="timeSlide" type="range" min="0" max="1" step="0.001" value="0" width= "200"><button id="rewind">Start</button><button id="pause">Pause</button><button id="play">Play</button></div>
    <canvas id="canvas" width="200" height="200"></canvas>

    【讨论】:

      【解决方案2】:

      const canvas = document.getElementById('canvas');
      const ctx = canvas.getContext('2d');
      
      // array of path coords
      const pathCoords = [
        [200,100], 
        [300, 150], 
        [200,190],
        [400,100],
        [50,10],
        [150,10], 
        [0, 50], 
        [500,90],
        [20,190],
        [10,180],
      ];
      
      // current point
      let currentTarget = pathCoords.shift();
      
      //circle object
      const circle ={
        x:10, 
        y:10,
        radius:10,
        dx:2,
        dy:2,
        color:'blue'
      }
      
      //function to draw above circle on canvas 
      function drawCircle(){
        ctx.beginPath();
        ctx.arc(circle.x,circle.y,circle.radius,0,Math.PI*2);
        ctx.fillStyle=circle.color;
        ctx.fill();
        ctx.closePath();
      }
      
      //Moving to a target coordinate (targetX,targetY)
      function goTo(targetX, targetY){
        if(Math.abs(circle.x-targetX)<circle.dx && Math.abs(circle.y-targetY)<circle.dy){
          // dont stop...
          //circle.dx = 0;
          //circle.dy = 0;
          circle.x = targetX;
          circle.y = targetY;
          
          // go to next point
          if (pathCoords.length) {
            currentTarget = pathCoords.shift();
          } else {
            console.log('Path end');
          }
        } else {
          const opp = targetY - circle.y;
          const adj = targetX - circle.x;
      
          const angle = Math.atan2(opp,adj)
          circle.x += Math.cos(angle)*circle.dx
          circle.y += Math.sin(angle)*circle.dy
        }
      }
      
      function update(){
        ctx.clearRect(0,0,canvas.width,canvas.height);
        drawCircle();
        goTo(...currentTarget);
        requestAnimationFrame(update);
      }
      
      update();
      &lt;canvas id=canvas width = 500 height = 200&gt;&lt;/canvas&gt;

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-01
        • 2011-06-18
        • 1970-01-01
        • 1970-01-01
        • 2012-09-07
        相关资源
        最近更新 更多