微日志_免费提供日志记录|作品展示|学习教程|免费日记

Canvas之手写板,最简单得曲线平滑解决方案,你更喜欢哪一种?

贝塞尔曲线 手写板 阅读:25

体验地址:暂无地址

几种线条的绘制解决方案,话不多说,直接看代码,配效果图。

方式一:使用moveTo+lineTo进行绘制

<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Canvas曲线绘制</title>
<style>
* {
padding: 0;
margin: 0;
        }

#canvas {
width: 100%;
height: 100%;
touch-action: none;
position: fixed;
top: 0;
left: 0;
z-index: 999;
        }
</style>
</head>

<body>
<canvas id="canvas" width="1920" height="720"></canvas>
</body>
<script>
let mouseDown = false, startPoint = null;
let canvas = document.querySelector('#canvas');
let ctx = canvas.getContext('2d');
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.globalCompositeOperation = 'source-over';
ctx.strokeStyle = `rgba(0,0,0,255)`;
canvas.addEventListener('pointerdown', e => {
mouseDown = true;
startPoint = {
x: e.offsetX,
y: e.offsetY
        };
    })
canvas.addEventListener('pointermove', e => {
if (!mouseDown) return;
setContextLineWidth(ctx, e.pressure || 0.65);
coustomDrawLine(ctx, startPoint.x, startPoint.y, e.offsetX, e.offsetY);
startPoint = {
x: e.offsetX,
y: e.offsetY
        };
    })
canvas.addEventListener('pointerup', e => {
if (mouseDown)
mouseDown = false;
    })
function coustomDrawLine(ctx, x, y, a, b) {
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(a, b);
ctx.stroke();
ctx.closePath();
    }
function setContextLineWidth(ctx, pressure) {
ctx.lineWidth = (pressure * 20 + 1) * 0.25;
    }
</script>

</html>

效果图如下,均是用手绘板进行绘制:

方式二,采用二次贝塞尔曲线进行绘制

<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Canvas曲线绘制</title>
<style>
* {
padding: 0;
margin: 0;
        }

#canvas {
width: 100%;
height: 100%;
touch-action: none;
position: fixed;
top: 0;
left: 0;
z-index: 999;
        }
</style>
</head>

<body>

<canvas id="canvas" width="1920" height="720"></canvas>
</body>
<script>
let points = [], mouseDown = false, startPoint = null;
let canvas = document.querySelector('#canvas');
let ctx = canvas.getContext('2d');
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.globalCompositeOperation = 'source-over';
ctx.strokeStyle = `rgba(0,0,0,255)`;
canvas.addEventListener('pointerdown', e => {
mouseDown = true;
startPoint = {
x: e.offsetX,
y: e.offsetY
        };
addPoint(startPoint);
    })
canvas.addEventListener('pointermove', e => {
if (!mouseDown) return;
setContextLineWidth(ctx, e.pressure || 0.65);
updateCurveDrawing(ctx, {
x: e.offsetX,
y: e.offsetY
        });
    })
canvas.addEventListener('pointerup', e => {
if (mouseDown) {
points = [];
mouseDown = false;
        }

    })
function addPoint(params) {
points.push({
            ...params
        });
    }
function updateCurveDrawing(ctx, params) {
addPoint(params);
let ccp = computedControlPoint(points);
if (ccp) {
drawingCurve(ctx, startPoint, ccp.controlPoint, ccp.endPoint);
startPoint = ccp.endPoint;
        }
    }
function computedControlPoint(points) {
if (points.length > 3) {
const lastTwoPoints = points.slice(-2);
const controlPoint = lastTwoPoints[0];
const endPoint = lastTwoPoints[1];
return {
controlPoint, endPoint
            }
        }
return false;
    }
function setContextLineWidth(ctx, pressure) {
ctx.lineWidth = (pressure * 20 + 1) * 0.25;
    }
function drawingCurve(ctx, startPoint, controlPoint, endPoint) {
ctx.beginPath();
ctx.moveTo(startPoint.x, startPoint.y);
ctx.quadraticCurveTo(controlPoint.x, controlPoint.y, endPoint.x, endPoint.y);
ctx.stroke();
ctx.closePath();
    }
</script>

</html>

效果图如下:

方式三:采用三次贝塞尔曲线进行绘制

<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Canvas曲线绘制</title>
<style>
* {
padding: 0;
margin: 0;
        }

#canvas {
width: 100%;
height: 100%;
touch-action: none;
position: fixed;
top: 0;
left: 0;
z-index: 999;
        }
</style>
</head>

<body>

<canvas id="canvas" width="1920" height="720"></canvas>
</body>
<script>
let points = [], tension = 0.65, mouseDown = false;
let canvas = document.querySelector('#canvas');
let ctx = canvas.getContext('2d');
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.globalCompositeOperation = 'source-over';
ctx.strokeStyle = `rgba(66, 118, 255,255)`;

canvas.addEventListener('pointerdown', e => {
mouseDown = true;
points.push({
x: e.offsetX,
y: e.offsetY
        })
    })
canvas.addEventListener('pointermove', e => {
if (!mouseDown) return;
points.push({
x: e.offsetX,
y: e.offsetY
        })
setContextLineWidth(ctx, e.pressure || 0.65);
drawCurve(points,0.5);
    })
canvas.addEventListener('pointerup', e => {
if (mouseDown) {
points = [];
mouseDown = false;
        }

    })

function drawCurve(points, tension) {
ctx.beginPath();
ctx.moveTo(points[0].x, points[0].y);
var t = (tension != null) ? tension : 1;
for (var i = 0; i < points.length - 1; i++) {
var p0 = (i > 0) ? points[i - 1] : points[0];
var p1 = points[i];
var p2 = points[i + 1];
var p3 = (i != points.length - 2) ? points[i + 2] : p2;

var cp1x = p1.x + (p2.x - p0.x) / 6 * t;
var cp1y = p1.y + (p2.y - p0.y) / 6 * t;

var cp2x = p2.x - (p3.x - p1.x) / 6 * t;
var cp2y = p2.y - (p3.y - p1.y) / 6 * t;

ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, p2.x, p2.y);
        }
ctx.stroke();
ctx.closePath();
points.splice(0, 1);
    }

function setContextLineWidth(ctx, pressure) {
ctx.lineWidth = (pressure * 20 + 1) * 0.25;
    }

</script>

</html>

效果图如下:

看了上面的几种方式,是不是觉得效果都差不多,我使用手绘板绘制出来效果看起来是差不多,如果你用鼠标测试,就会发现他们的差距了。

如果觉得本篇文章对你有用的话,记得支持一下哟!