在HTML5画布上的一组坐标中移动对象



我想在HTML5 Canvas上通过坐标数组(例如:{(300400(,(200300(,(300200(,(400400(}(移动一个对象(本例中为圆形(。我可以将对象移动到一个坐标,如下所示。以下代码在(100100(处绘制一个圆,并将其移动到(300400(。当我试图扩展它,使圆一个接一个地通过一组坐标时,我被卡住了。

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()

随机访问关键帧

为了更好地控制动画,您需要创建可以随时间随机访问的路点(关键帧(。这意味着您只需设置时间就可以获得动画中的任何位置。

然后,您可以播放和暂停、设置速度、反转并搜索到动画中的任何位置。

示例

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

蓝点将在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>

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();
<canvas id=canvas width = 500 height = 200></canvas>

最新更新