下图为实现效果(图片在三次贝塞尔曲线中运动)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
html,
body,
canvas {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<canvas id="canvas" ></canvas>
</body>
<script>
const canvas = document.getElementById('canvas')
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const ctx = canvas.getContext('2d');
//起点
// var [x1, y1] = [10, 10];
// //小球起点
// var [x, y] = [10, 10];
// //控制点 如果是二次贝塞尔曲线用的控制点是cx,cy
// // var [cx, cy] = [100, 0];
// //终点
// var [x2, y2] = [200, 200]
// 三次贝塞尔曲线用的控制点是cx1,cx2,cy1,cy2
// var [cx1, cy1] = [100, 0];
// var [cx2, cy2] = [100, 250]
var t = 0
// 由于本示例为三次贝尔赛曲线所以控制点有两个
var pointarr = [
{
start:{x:10,y:10},//小球起点
begin:{x:10,y:10},//起点 这两个的区别是小球的起点一直随着运动轨迹在发生变化
control1:{x:100,y:0}, //控制点1
control2:{x:100,y:250}, //控制点2
end:{x:200,y:200} //终点
}
]
//画一条线
function draw() {
ctx.beginPath()
// ctx.moveTo(10, 10)
// 二次贝塞尔曲线的绘制 与上边的 ctx.moveTo()连用 ,三次的也是
// ctx.quadraticCurveTo(cx, cy, x2, y2)
// 三次贝尔赛曲线的绘制
// ctx.bezierCurveTo(cx1, cy1, cx2, cy2, x2, y2)
// 此次示例的是三次贝塞尔曲线
ctx.moveTo(pointarr[0].begin.x, pointarr[0].begin.y);
ctx.bezierCurveTo(pointarr[0].control1.x, pointarr[0].control1.y, pointarr[0].control2.x, pointarr[0].control2.y, pointarr[0].end.x, pointarr[0].end.y);
ctx.stroke()
ctx.closePath()
}
/*贝塞尔曲线上点位的控制*/
function computedPosition() {
// 二次贝塞尔曲线上运动轨迹的运算方式
// x = Math.pow(1 - t, 2) * x1 + 2 * t * (1 - t) * cx + Math.pow(t, 2) * x2
// y = Math.pow(1 - t, 2) * y1 + 2 * t * (1 - t) * cy + Math.pow(t, 2) * y2
// 三次的贝塞尔曲线运动轨迹的计算方式
// x = x1 * Math.pow((1 - t), 3) + 3 * cx1 * t * Math.pow((1 - t), 2) + 3 * cx2 * Math.pow(t, 2) * (1 - t) + x2 * Math.pow(t, 3)
// y = y1 * Math.pow((1 - t), 3) + 3 * cy1 * t * Math.pow((1 - t), 2) + 3 * cy2 * Math.pow(t, 2) * (1 - t) + y2 * Math.pow(t, 3)
// 根据开始到结束的大小判断,控制时间
if (pointarr[0].start.x > pointarr[0].end.x) {
t = 0;
pointarr[0].start.x = pointarr[0].begin.x;
pointarr[0].start.y = pointarr[0].begin.y;
}
pointarr[0].start.x = pointarr[0].begin.x * Math.pow((1 - t), 3) + 3 * t * pointarr[0].control1.x * Math.pow((1 - t), 2) + 3 * pointarr[0].control2.x * Math.pow(t, 2) * (1 - t) + pointarr[0].end.x * Math.pow(t, 3);
pointarr[0].start.y = pointarr[0].begin.y * Math.pow((1 - t), 3) + 3 * t * pointarr[0].control1.y * Math.pow((1 - t), 2) + 3 * pointarr[0].control2.y * Math.pow(t, 2) * (1 - t) + pointarr[0].end.y * Math.pow(t, 3);
}
function drawPoint() {
computedPosition()
// 下面四行为红色小球的运动轨迹但是需要加requestAnimationFrame(loopDraw)下面的代码cleaReact()
// ctx.beginPath()
// ctx.fillStyle = "red"
// ctx.arc(pointarr[0].start.x, pointarr[0].start.y, 10, 0, 2 * Math.PI)
// ctx.fill()
let leftimgrun1 = new Image()
leftimgrun1.src = './img/网络设备.png';
leftimgrun1.onload = function () {
ctx.clearRect(0, 0,pointarr[0].end.x+leftimgrun1.width,pointarr[0].end.y+leftimgrun1.width)
ctx.drawImage(leftimgrun1,pointarr[0].start.x-15,pointarr[0].start.y-15, 25, 25)
}
}
let loopDraw = () => {
requestAnimationFrame(loopDraw);//这个是由浏览器调度的 而 setTimeout 只能设置一个固定的时间间隔,这个时间不一定和屏幕的刷新时间相同。
// ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
draw()
drawPoint()
t += 0.007//控制动画移动速度
}
loopDraw()//启动动画
</script>
</html>
二次贝塞尔曲线的绘制:
ctx.quadraticCurveTo(cx, cy, x2, y2)
三次贝尔赛曲线的绘制:
ctx.bezierCurveTo(cx1, cy1, cx2, cy2, x2, y2)
二次贝尔赛曲线的运动的x,y
x = Math.pow(1 - t, 2) * x1 + 2 * t * (1 - t) * cx + Math.pow(t, 2) * x2
y = Math.pow(1 - t, 2) * y1 + 2 * t * (1 - t) * cy + Math.pow(t, 2) * y2
三次贝尔赛曲线的运动的x,y
x = x1 * Math.pow((1 - t), 3) + 3 * cx1 * t * Math.pow((1 - t),2) + 3 * cx2 * Math.pow(t, 2) * (1 - t) + x2 * Math.pow(t, 3)
y = y1 * Math.pow((1 - t), 3) + 3 * cy1 * t * Math.pow((1 - t), 2) + 3 * cy2 * Math.pow(t, 2) * (1 - t) + y2 * Math.pow(t, 3)