Canvas 画贝塞尔曲线(二阶曲线和三阶曲线)
效果图为动态图,一个小圆点沿着曲线运动,并显示实时点坐标。
在线预览:
二阶:http://qingshanboke.com/demo/quadratic.htm
三阶:http://qingshanboke.com/demo/bezier.htm
一、实现思路:
1.用两个canvas实现,一个绘制曲线,一个绘制运动圆点。
2.绘制曲线:可以通过canvas提供的API方法绘制。
二阶:quadraticCurveTo(controlX, controlY, endingPointX, endingPointY) 1个控制点。
三阶:
bezierCurveTo(controlX1, controlY1, controlX2, controlY2, endPointX, endPointY),2个控制点。
3.绘制圆点:根据贝塞尔曲线公式,计算出不同时刻圆点坐标,然后绘制到canvas上。
二、实现过程:
1.二阶曲线:
核心公式:
实现代码:
<html>
<title>二阶贝塞尔曲线</title>
<style type="text/css">
body {
background: black;
}
#canvas {
position: absolute;
top: 0;
left: 0;
width: 600px;
height: 600px;
}
#line {
position: absolute;
top: 0;
left: 0;
width: 600px;
height: 600px;
}
</style>
<body>
<canvas id="canvas" width="600" height="600"></canvas>
<canvas id="line" width="600" height="600"></canvas>
<script type="text/javascript">
var point = {
begin: {
x: 20,
y: 20
},
control: {
x: 40,
y: 400
},
end: {
x: 600,
y: 600
},
};
function drawline() {
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.moveTo(point.begin.x, point.begin.y);
ctx.quadraticCurveTo(point.control.x, point.control.y, point.end.x, point.end.y);
ctx.strokeStyle = "#2578b0";
ctx.lineWidth = 2;
ctx.stroke();
}
drawline();
let t = 0;
function drawPoint() {
//根据二次贝塞尔曲线的公式,获取某时刻t[0-1]的贝塞尔曲线上的点
let x = Math.pow((1 - t), 2) * point.begin.x + 2 * t * (1 - t) * point.control.x + Math.pow(t, 2) * point.end.x;
let y = Math.pow((1 - t), 2) * point.begin.y + 2 * t * (1 - t) * point.control.y + Math.pow(t, 2) * point.end.y;
//移出画布后,重新开始
if (x > 600) {
t = 0;
x = point.begin.x;
y = point.begin.y;
}
let canvas = document.getElementById("line");
let ctx = canvas.getContext("2d");
//清除上一次的点
ctx.clearRect(0, 0, 600, 600);
ctx.beginPath();
//画小圆点
ctx.moveTo(point.begin.x, point.begin.y);
ctx.arc(x, y, 4, 0, 2 * Math.PI, false);
ctx.fillStyle = "white";
ctx.fill();
//显示坐标
ctx.font = 'bold 12px Arial';
ctx.textAlign = 'left';
ctx.textBaseline = 'bottom';
ctx.fillStyle = 'white';
ctx.fillText("x:" + parseInt(x), x, y - 24);
ctx.fillText("y:" + parseInt(y), x, y - 12);
ctx.closePath();
t += 0.006;
}
setInterval(drawPoint, 60);
</script>
</body>
</html>
在线预览:http://qingshanboke.com/demo/quadratic.htm
2.三阶曲线:
核心公式:
实现代码:
<html>
<title>三阶贝塞尔曲线</title>
<style type="text/css">
body {
background: black;
}
#canvas {
position: absolute;
top: 0;
left: 0;
width: 600px;
height: 600px;
}
#line {
position: absolute;
top: 0;
left: 0;
width: 600px;
height: 600px;
}
</style>
<body>
<canvas id="canvas" width="600" height="600"></canvas>
<canvas id="line" width="600" height="600"></canvas>
<script type="text/javascript">
var point = {
begin: {
x: 0,
y: 600
},
control1: {
x: 500,
y: 500
},
control2: {
x: 400,
y: 40
},
end: {
x: 600,
y: 0
},
};
function drawline() {
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.moveTo(point.begin.x, point.begin.y);
ctx.bezierCurveTo(point.control1.x, point.control1.y, point.control2.x, point.control2.y, point.end.x, point.end.y);
ctx.strokeStyle = "#2578b0";
ctx.lineWidth = 2;
ctx.stroke();
}
drawline();
let t = 0;
function drawPoint() {
//根据三次贝塞尔曲线的公式,获取某时刻t[0-1]的贝塞尔曲线上的点
let x = point.begin.x * Math.pow((1 - t), 3) + 3 * t * point.control1.x * Math.pow((1 - t), 2) + 3 * point.control2.x * Math.pow(t, 2) * (1 - t) + point.end.x * Math.pow(t, 3);
let y = point.begin.y * Math.pow((1 - t), 3) + 3 * t * point.control1.y * Math.pow((1 - t), 2) + 3 * point.control2.y * Math.pow(t, 2) * (1 - t) + point.end.y * Math.pow(t, 3);
//移出画布后,重新开始
if (x > 600) {
t = 0;
x = point.begin.x;
y = point.begin.y;
}
let canvas = document.getElementById("line");
let ctx = canvas.getContext("2d");
//清除上一次的点
ctx.clearRect(0, 0, 600, 600);
ctx.beginPath();
//画小圆点
ctx.moveTo(point.begin.x, point.begin.y);
ctx.arc(x, y, 4, 0, 2 * Math.PI, false);
ctx.fillStyle = "white";
ctx.fill();
//显示坐标
ctx.font = 'bold 12px Arial';
ctx.textAlign = 'left';
ctx.textBaseline = 'bottom';
ctx.fillStyle = 'white';
ctx.fillText("x:" + parseInt(x), x, y - 24);
ctx.fillText("y:" + parseInt(y), x, y - 12);
ctx.closePath();
t += 0.006;
}
setInterval(drawPoint, 60);
</script>
</body>
</html>
在线预览:http://qingshanboke.com/demo/bezier.htm
参考资料:
https://www.w3school.com.cn/tags/canvas_quadraticcurveto.asp
https://www.w3school.com.cn/tags/canvas_beziercurveto.asp
https://baike.baidu.com/item/%E8%B4%9D%E5%A1%9E%E5%B0%94%E6%9B%B2%E7%BA%BF/1091769?fr=aladdin
https://blog.csdn.net/ixygj197875/article/details/80043658
上一篇: 百度富文本编辑器使用
下一篇: IT男的热爱(ToDoList)