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> ...
随机推荐
- 三分钟了解 Python3 的异步 Web 框架 FastAPI
快速编码,功能完善.从启动到部署,实例详解异步 py3 框架选择 FastAPI 的原因. FastAPI 介绍 FastAPI 与其它 Python-Web 框架的区别 在 FastAPI 之前,P ...
- day13 作业
目录 1.编写文件修改功能,调用函数时,传入三个参数(修改的文件路径,要修改的内容,修改后的内容)既可完成文件的修改 2.编写tail工具 3.编写登录功能 4.编写注册功能 选做题:编写ATM程序实 ...
- keepalived 热备
概述 keepalived高可用集群 keepalived最初是为了LVS的,因为LVS无法进行自动检测服务器的节点状态(可以自动部署LVS) keeplived后来加入VRRP给功 ...
- SQLAlchemy(一):SQLAlchemy去连接数据库、ORM介绍、将ORM模型映射到数据库中
SQLAlchemy01 /SQLAlchemy去连接数据库.ORM介绍.将ORM模型映射到数据库中 目录 SQLAlchemy01 /SQLAlchemy去连接数据库.ORM介绍.将ORM模型映射到 ...
- day7:字符串的操作/方法&字符串的格式化format&列表的操作
字符串的相关操作 1.字符串的拼接 strvar = "vegeta"+"ble" print(strvar) # vegetable 2.字符串的重复 str ...
- 关于python爬取异步ajax数据的一些见解
我们在利用python进行爬取数据的时候,一定会遇到这样的情况,在浏览器中打开能开到所有数据,但是利用requests去爬取源码得到的却是没有数据的页面框架. 出现这样情况,是因为别人网页使用了aja ...
- OSCP Learning Notes - Exploit(6)
Antivirus Bypassing Tools: Kali Linux Detection Platform: https://www.virustotal.com/gui/home/upload ...
- Ethical Hacking - NETWORK PENETRATION TESTING(17)
MITM - bypassing HTTPS Most websites use https in their login pages, this means that these pages are ...
- IOS上传图片方向问题
在显示上传完毕的图片的时候遇到了一个问题, 图片莫名其妙被逆时针旋转了90度就很离谱 如下图 经过一番查询, 原来是 IOS 的相机拍照的时候会把方向角写入到图片里面 因为我用的是 element 的 ...
- SQL数据多条转单条(CONCAT_WS)
一.concat()函数可以连接一个或者多个字符串 concat(str1,str2,…) 返回结果为连接参数产生的字符串.如有任何一个参数为NULL ,则返回值为 NULL. select conc ...