canvas小画板--(1)平滑曲线
功能需求
项目需求:需要实现一个可以自由书写的小画板
简单实现
对于熟悉canvas的同学来说,这个需求很简单,短短几十行代码就能实现:
<!doctype html>
<html> <head>
<meta charset=utf-8>
<style>
canvas {
border: 1px solid #ccc
} body {
margin: 0;
}
</style>
</head> <body style="overflow: hidden;background-color: rgb(250, 250, 250);touch-action: none;">
<canvas id="c" width="1920" height="1080"></canvas>
<script>
var el = document.getElementById('c');
var ctx = el.getContext('2d');
//设置绘制线条样式
ctx.strokeStyle = 'red';
ctx.lineWidth = 1;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
var isDrawing;//标记是否要绘制
//存储坐标点
let lastX, lastY;
document.body.onpointerdown = function (e) {
console.log('pointerdown');
isDrawing = true;
lastX = e.clientX;
lastY = e.clientY;
};
document.body.onpointermove = function (e) {
console.log('pointermove');
if (isDrawing) {
draw(e.clientX, e.clientY, lastX, lastY);
}
lastX = e.clientX, lastY = e.clientY;
};
document.body.onpointerup = function (e) {
if (isDrawing) {
draw(e.clientX, e.clientY, lastX, lastY);
}
lastX = e.clientX, lastY = e.clientY;
isDrawing = false;
}; function draw(x, y, lastX, lastY) {
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(x, y);
ctx.stroke();
}
</script>
</body>
</html>
实现效果如下图:

实现的逻辑很简单:
1)监听事件pointerdown,pointermove,pointerup
2)标记是否拖拽画线模式变量 isDrawing,在down事件时置为true,up的时候置为false
3)使用canvas的api,设置线条样式,调用绘制线条接口lineTo方法
以上就简单的实现了画板功能,如果要求不高的用户可以使用,但一旦遇到有点要求的用户就无法交付这种产品,仔细看是线条折线感太强。
为什么会有折线感呢?
主要原因:
我们调用的api方法lineTo是两点连线也就是直线
浏览器对鼠标事件mousemove的采集是有采集频率的,并不是每个鼠标移动经过的每一个像素点都会触发事件。
当鼠标移动的越快,那么两点之间的间隔就越远,那么折线感就更明显。

如何能绘制平滑的曲线?
canvas提供的api中是有现成接口的,贝塞尔系列的接口就能满足我们的要求,接下来我们讲一下使用二次贝塞尔曲线绘制平滑曲线。
quadraticCurveTo(cpx,cpy,x,y)
二次贝塞尔曲线接口需要四个参数,cpx,cpy是曲线的控制点,x,y是曲线终点。
有人问那曲线的起点在哪里?其实曲线的起点取决于上一操作状态,可以是moveTo的位置,或者是lineTo的位置,或者是贝塞尔的终点。
那么怎么调用quadraticCurveTo,参数怎么传呢?
我们需要找出关键位置,直接用例子告诉大家吧
1)假如我们用鼠标采集到ABCDEF六个点
2)取前面三个点ABC计算,BC的中点B1,以A为起点,B为控制点,B1为终点,那么利用quadraticCurveTo可以绘制出这样一条贝塞尔曲线

3)接下来计算CD的中点C1,以B1为起点,C为控制点,C1为终点,那么利用quadraticCurveTo可以绘制出这样一条贝塞尔曲线

4)以此类推,当到了最后一个点时以D1为起点,E为控制点,F为终点,结束贝塞尔绘制。

根据算法进行代码改造
OK我们介绍了具体算法的影响,那用该算法对我们前面的代码进行改造:
<!doctype html>
<html> <head>
<meta charset=utf-8>
<style>
canvas {
border: 1px solid #ccc
} body {
margin: 0;
}
</style>
</head> <body style="overflow: hidden;background-color: rgb(250, 250, 250);touch-action: none;">
<canvas id="c" width="1920" height="1080"></canvas>
<script>
var el = document.getElementById('c');
var ctx = el.getContext('2d');
//设置绘制线条样式
ctx.strokeStyle = 'red';
ctx.lineWidth = 1;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
var isDrawing;//标记是否要绘制
//存储坐标点
let points = [];
document.body.onpointerdown = function (e) {
console.log('pointerdown');
isDrawing = true;
points.push({ x: e.clientX, y: e.clientY });
};
document.body.onpointermove = function (e) {
console.log('pointermove');
if (isDrawing) {
draw(e.clientX, e.clientY);
} };
document.body.onpointerup = function (e) {
if (isDrawing) {
draw(e.clientX, e.clientY);
}
points = [];
isDrawing = false;
}; function draw(mousex, mousey) {
points.push({ x: mousex, y: mousey });
ctx.beginPath();
let x = (points[points.length - 2].x + points[points.length - 1].x) / 2,
y = (points[points.length - 2].y + points[points.length - 1].y) / 2;
if (points.length == 2) {
ctx.moveTo(points[points.length - 2].x, points[points.length - 2].y);
ctx.lineTo(x, y);
} else {
let lastX = (points[points.length - 3].x + points[points.length - 2].x) / 2,
lastY = (points[points.length - 3].y + points[points.length - 2].y) / 2;
ctx.moveTo(lastX, lastY);
ctx.quadraticCurveTo(points[points.length - 2].x, points[points.length - 2].y, x, y);
}
ctx.stroke();
points.slice(0, 1); }
</script>
</body> </html>
在原有基础上我们用了一个数组points保存鼠标经过的点,根据算法可知绘制贝塞尔曲线至少要用三个点,绘制过程中维护points数组。
实现效果如下,可见平滑了很多!

canvas小画板--(1)平滑曲线的更多相关文章
- canvas小画板——(2)荧光笔效果
我们在上一篇文章中讲了如何绘制平滑曲线 canvas小画板——(1)平滑曲线. 透明度实现荧光笔 现在我们需要加另外一种画笔效果,带透明度的荧光笔.那可能会觉得绘制画笔的时候加上透明度就可以了.我们来 ...
- canvas小画板——(3)笔锋效果
画线准备 准备一个canvas <canvas id="canvasId" width="1000" height="800"> ...
- 如何开发一个简单的HTML5 Canvas 小游戏
原文:How to make a simple HTML5 Canvas game 想要快速上手HTML5 Canvas小游戏开发?下面通过一个例子来进行手把手教学.(如果你怀疑我的资历, A Wiz ...
- 两个Canvas小游戏
或许连小游戏都算不上,可以叫做mini游戏. 没有任何框架或者稍微有点深度的东西,所以有js基础的或者要追求炫酷效果的可以直接ctrl+w了. 先贴出两个游戏的试玩地址: 是男人就走30步 是男人就忍 ...
- canvas实现画板
canvas实现画板 主要用到知识点: 鼠标事件onmousedown() onmousemove() onmouseup() onmouseleave() 事件委托 canvas的一些方法 如:绘制 ...
- 一款基于HTML5 Canvas的画板涂鸦动画
今天给各网友分享一款基于HTML5 Canvas的画板涂鸦动画.记得之前我们分享过一款HTML5 Canvas画板工具,可以切换不同的笔刷,功能十分强大.本文今天要再来分享一款基于HTML5 Canv ...
- [原创]基于html5新标签canvas写的一个小画板
最近刚学了canvas,写个小应用练习下 源代码 <!DOCTYPE> <html> <head> <meta http-equiv="Conten ...
- 用canvas画一个的小画板(PC端移动端都能用)
前言 本篇的内容主要包括: canvas标签简介 画板的功能简介 画板的JS部分(包括:1.获取画布 2.使画板全屏幕显示且自适应 3.如何绘制直线 4.绘画时的三种状态(鼠标点击.移动.离开)5.画 ...
- HTML5 Canvas 小例子 简易画板
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
随机推荐
- day31 反射,内置方法,元类
目录 一.反射 1 什么是反射 2 如何实现反射 二.内置方法 1 什么是内置方法 2 为什么要用内置方法 3 如何使用内置方法 3.1 str 3.2 del 三.元类 1 什么是元类 2 clas ...
- vscode F2无法使用
rope库可能存在bug 解决方法: "python.jediEnabled": false //自动补全用微软自带
- Scala 基础(十三):Scala 模式匹配(一)
1 match 应用案例 Scala的模式匹配 案例代码完整: package com.atguigu.base object MatchDemo { def main(args: Array[Str ...
- python 爬虫,网页转PDF:OSError: No wkhtmltopdf executable found
解决办法: 代码中设置参数: path_wk = r‘D:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe‘ #wkhtmltopdf安装位置 config ...
- 07 flask源码剖析之用户请求过来流程
07 Flask源码之:用户请求过来流程 目录 07 Flask源码之:用户请求过来流程 1.创建ctx = RequestContext对象 2. 创建app_ctx = AppContext对象 ...
- SpringBoot2.x入门:使用CommandLineRunner钩子接口
前提 这篇文章是<SpringBoot2.x入门>专辑的第6篇文章,使用的SpringBoot版本为2.3.1.RELEASE,JDK版本为1.8. 这篇文章主要简单聊聊钩子接口Comma ...
- 【Maven】总结
导言:生产环境下开发不再是一个项目一个工程,而是每一个模块创建一个工程,而多个模块整合在一起就需要 使用到像 Maven 这样的构建工具. 1 Why? 1.1 真的需要吗? Maven 是干什么用的 ...
- bzoj3892[Usaco2014 Dec]Marathon*
bzoj3892[Usaco2014 Dec]Marathon 题意: 在二维平面上有N个点,从(x1,y1)到(x2,y2)的代价为|x1-x2|+|y1-y2|.求从1号点出发,按从1到N的顺序依 ...
- 手写简易SpringMVC
手写简易SpringMVC 手写系列框架代码基于普通Maven构建,因此在手写SpringMVC的过程中,需要手动的集成Tomcat容器 必备知识: Servlet相关理解和使用,Maven,Java ...
- Python Ethical Hacking - NETWORK_SCANNER(1)
NETWORK_SCANNER Discover all devices on the network. Display their IP address. Display their MAC add ...