canvas实现手动绘制矩形
开场白
虽然在实际的开发中我们很少去绘制流程图
就算需要,我们也会通过第3方插件去实现
下面我们来简单实现流程图中很小的一部分
手动绘制矩形
绘制一个矩形的思路
我们这里绘制矩形
会使用到canvas.strokeRect(x,y, w, h)方法绘制一个描边矩形
x:矩形起点的 x 轴坐标。
y:矩形起点的 y 轴坐标。
width:矩形的宽度。正值在右边,负值在左边。
height:矩形的高度。正值下降,负值上升。
注意一下w,h这两个参数的正直和负值。
如果w,h是负数,会出现了2个斜着对称的矩形

绘制一个静态矩形
<!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{
/* 去除浏览器内置的margin */
margin: 0;
/* 整个页面铺满 */
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
<script>
// 获取canvas元素
let canvasEle = document.getElementById('canvas')
// 获取canvas的上下文
const ctx = canvasEle.getContext('2d')
// 设置canvas的大小(宽高) 与屏幕一样宽高
const screenSize = document.documentElement
canvasEle.width = window.screen.availWidth
canvasEle.height = window.screen.availHeight
// 给矩形的设置颜色,设置颜色一定要在绘制之前,否则将会不生效
ctx.strokeStyle = '#a0a'
// 绘制一个路径模式是的矩形,起始坐标100,100, 宽300,高280
ctx.strokeRect(100,100,300,280)
</script>
</html>

手动绘制矩形的基本思路
通过上面我们实现了静态绘制矩形。
如果我们想要手动画一个矩形,需要实现以下几个步骤
1.给canvas注册鼠标按下事件,在按下的时候记录矩形的起始坐标(x,y)
与此同时,还需要在按下时注册鼠标移动事件和抬起事件。
2.在鼠标移动的时候,通过计算得到矩形的宽和高。
计算矩形的宽度和高度时,我们要使用绝对值进行计算。
计算后立即绘制矩形
3.在鼠标抬起时,移除之前注册的鼠标移动事件和抬起事件
手动绘制矩形
<script>
// 获取canvas元素 oCan
let canvasEle = document.getElementById('canvas')
// 获取canvas的上下文
const ctx = canvasEle.getContext('2d')
// 设置canvas的大小(宽高) 与屏幕一样宽高
const screenSize = document.documentElement
canvasEle.width = window.screen.availWidth
canvasEle.height = window.screen.availHeight
// 所有的矩形信息
let rectArr = []
// 给canvas注册事件按下事件
canvasEle.addEventListener('mousedown',canvasDownHandler)
function canvasDownHandler(e){
console.log('按下', e)
rectArr = [e.clientX,e.clientY ]
// 按下的时候需要注册移动事件
canvasEle.addEventListener('mousemove', canvasMoveHandler)
// 抬起事件
canvasEle.addEventListener('mouseup', canvasMouseUpHandler)
}
// 移动的时候我们需要记录起始点和结束点,然后就可以绘制矩形了
function canvasMoveHandler(e){
console.log('我们在移动了', e)
// 在移动的时候就开始绘制矩形
drawRect(rectArr[0], rectArr[1], e.clientX, e.clientY)
}
function drawRect(x1,y1,x2,y2){
// 在计算矩形的宽高时,我们需要使用绝对值来进行计算
// 此时此刻移动的坐标减去最初按下的坐标就是矩形的宽和高
// 如果不用绝对值,可能会出现2个矩形
let rectWidth = Math.abs(x2-x1)
let rectHeight = Math.abs(y2-y1)
// 存储矩形的坐标信息
rectArr = [x1,y1,rectWidth,rectHeight]
ctx.strokeRect(...rectArr)
}
// 当我们鼠标抬起的时候要移除之前注册移动事件和抬起事件
function canvasMouseUpHandler(){
canvasEle.removeEventListener('mousemove', canvasMoveHandler)
canvasEle.removeEventListener('mouseup', canvasMouseUpHandler)
}
</script>


发现问题出现多余的路径
通过上面这张图片,我们虽然绘制手动绘制出了矩形。
但是出现了重复的路径。
我们先分析一下出现重复路径的原因。
我们在每次移动的过程中,都会绘制矩形。
只要我们在绘制前,清空矩形是不是就可以解决这个问题
我们来尝试一下
在绘之前清除多余的路径
function drawRect(x1,y1,x2,y2){
// 在计算矩形的宽高时,我们需要使用绝对值来进行计算
// 此时此刻移动的坐标减去最初按下的坐标就是矩形的宽和高
let rectWidth = Math.abs(x2-x1)
let rectHeight = Math.abs(y2-y1)
// 存储矩形的坐标信息
rectArr = [x1,y1,rectWidth,rectHeight]
// 在绘制矩形前,我们将矩形清空,然后在绘制,就不会出现多余的路径了
ctx.clearRect(0,0, canvasEle.width, canvasEle.height)
// 重新绘制矩形
ctx.strokeRect(...rectArr)
}

机智的小伙伴发现问题了?
有些机智的小伙伴发现:
如果我起始点是右下角,终点是左上角。
即:用户从(900, 1000)拖动到(50, 50)这种情况
按照这样的方向绘制矩形,是不是会出现问题呢?
确实会出现问题。
此时绘制的矩形不会随着我们的方向进行绘制。请看下面的图
如何处理这个问题呢?

主角闪亮登场 canvas.rect
canvas.rect(x,y,w,h)该方法创建一个矩形路径
x:矩形起点的 x 轴坐标。
y:矩形起点的 y 轴坐标。
width:矩形的宽度。正值在右边,负值在左边。
height:矩形的高度。正值下降,负值上升。
这个方法是创建一个矩形路径,创建的路径并不会直接绘制在画布上。
需要调用stroke()或fill()才能显示在画布上。
使用canvas.rect 绘制矩形路径
function drawRect(x1,y1,x2,y2){
let rectWidth = Math.abs(x2-x1)
let rectHeight = Math.abs(y2-y1)
// 绘制之前先清空之前实时移动产生的多余的矩形路径
ctx.clearRect(0,0, canvasEle.width, canvasEle.height)
// 开始画线
ctx.beginPath();
// 绘制路径矩形
ctx.rect(Math.min(x1, x2), Math.min(y1, y2), rectWidth, rectHeight);
// 绘制形状的轮廓。
ctx.stroke();
}

canvas.strokeRect与canvas.rect的异同
区别1功能性: canvas.strokeRect:绘制的是边框。canvas.rect创建矩形的路径(不绘立即绘制在矩形上)
区别2即时性: canvas.strokeRect是立即绘制。canvas.rect不是立即绘制,需要调用stroke()或fill()才能绘制
相同点:
1.都是绘制矩形
2.接受的参数相同
3.都是通过strokeStyle(颜色)和lineWidth(线的粗细)等来设置样式
连续绘制多个矩形
function drawRect(x1,y1,x2,y2){
let rectWidth = Math.abs(x2-x1)
let rectHeight = Math.abs(y2-y1)
let endX = Math.min(x1, x2)
let endY = Math.min(y1, y2)
// 绘制之前先清空之前实时移动产生的多余的矩形路径
ctx.clearRect(0,0, canvasEle.width, canvasEle.height)
// 绘制之前那些存储在 beforeRectArr 数组中的矩形
allRectInfoArr = [endX, endY, rectWidth, rectHeight]
ctx.clearRect(0,0, canvasEle.width, canvasEle.height)
beforeRectArr.forEach(element => {
ctx.beginPath();
ctx.strokeRect(...element)
ctx.stroke();
});
// 开始本次路径
ctx.beginPath();
// 绘制本次的矩形路径
ctx.rect(...allRectInfoArr);
// 开始填充矩形
ctx.stroke();
}
// 当我们鼠标抬起的时候要移除之前注册移动事件和抬起事件
function canvasMouseUpHandler(){
savaBeforeRect()
canvasEle.removeEventListener('mousemove', canvasMoveHandler)
canvasEle.removeEventListener('mouseup', canvasMouseUpHandler)
}
function savaBeforeRect(){
beforeRectArr.push(allRectInfoArr)
}

全部代码
<!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{
/* 去除浏览器内置的margin */
margin: 0;
/* 整个页面铺满 */
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
<script>
// 获取canvas元素 oCan
let canvasEle = document.getElementById('canvas')
// 获取canvas的上下文
const ctx = canvasEle.getContext('2d')
// 设置canvas的大小(宽高) 与屏幕一样宽高
const screenSize = document.documentElement
canvasEle.width = window.screen.availWidth
canvasEle.height = window.screen.availHeight
// 给矩形的设置颜色
// ctx.strokeStyle = '#a0a'
// // 绘制一个路径模式是的矩形,起始坐标100,100, 宽300,高280
// ctx.strokeRect(100,100,400,280)
// 矩形信息
let rectArr = []
// 所有的矩形信息
allRectInfoArr = []
let beforeRectArr =[]
// 给canvas注册事件按下事件
canvasEle.addEventListener('mousedown',canvasDownHandler)
function canvasDownHandler(e){
rectArr = [e.clientX,e.clientY ]
// 按下的时候需要注册移动事件
canvasEle.addEventListener('mousemove', canvasMoveHandler)
// 抬起事件
canvasEle.addEventListener('mouseup', canvasMouseUpHandler)
}
// 移动的时候我们需要记录起始点和结束点,然后就可以绘制矩形了
function canvasMoveHandler(e){
// 在移动的时候就开始绘制矩形
drawRect(rectArr[0], rectArr[1], e.clientX, e.clientY)
}
function drawRect(x1,y1,x2,y2){
let rectWidth = Math.abs(x2-x1)
let rectHeight = Math.abs(y2-y1)
let endX = Math.min(x1, x2)
let endY = Math.min(y1, y2)
// 绘制之前先清空之前实时移动产生的多余的矩形路径
ctx.clearRect(0,0, canvasEle.width, canvasEle.height)
// 绘制之前那些存储在 beforeRectArr 数组中的矩形
allRectInfoArr = [endX, endY, rectWidth, rectHeight]
beforeRectArr.forEach(element => {
ctx.beginPath();
ctx.strokeRect(...element)
ctx.stroke();
});
// 开始本次路径
ctx.beginPath();
// 绘制本次的矩形路径
ctx.rect(...allRectInfoArr);
// 开始填充矩形
ctx.stroke();
}
// 当我们鼠标抬起的时候要移除之前注册移动事件和抬起事件
function canvasMouseUpHandler(){
savaBeforeRect()
canvasEle.removeEventListener('mousemove', canvasMoveHandler)
canvasEle.removeEventListener('mouseup', canvasMouseUpHandler)
}
function savaBeforeRect(){
beforeRectArr.push(allRectInfoArr)
}
</script>
</html>
尾声
如果小伙伴觉得我写的不错的话
可以给我点个赞吗?感谢了。
后面会继续写:
如何选中矩形,更改矩形大小。
如何在矩形上添加文字。
如何绘制圆,箭头符号等
canvas实现手动绘制矩形的更多相关文章
- Android中使用Canvas和Paint绘制一个安卓机器人
场景 在Android中画笔使用Paint类,画布使用Canvas类来表示. 绘图的基本步骤 首先编写一个继承自View的自定义View类,然后重写其onDraw方法,最后把自定义的view添加到ac ...
- canvas 绘制 矩形 圆形
<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head> <tit ...
- canvas 绘制矩形和圆形
canvas绘制有两神方法:1).填充(fill)填充是将图形内部填满. 2).绘制边框 (stroke)绘制边框是不把图形内部填满,只是绘制图形的外框. 当我们在绘制图形的时候,首先要设定好绘制的样 ...
- Canvas入门(1):绘制矩形、圆、直线、曲线等基本图形
来源:http://www.ido321.com/968.html 一.Canvas的基础知识 Canvas是HTML 5中新增的元素,专门用于绘制图形.canvas元素就相当于一块“画布”,一块无色 ...
- [HTML5 Canvas学习]绘制矩形
1.使用strokeRect和fillRect方法绘制矩形 a.strokeRect是绘制一个不填充的矩形 b.fillRect是绘制一个填充的矩形 代码: <script> var ca ...
- canvas 绘制矩形
XXX(x,y,width,height) x矩形左上角x坐标 y矩形左上角y坐标 ...
- canvas学习总结六:绘制矩形
在第三章中(canvas学习总结三:绘制路径-线段)我们提高Canvas绘图环境中有些属于立即绘制图形方法,有些绘图方法是基于路径的. 立即绘制图形方法仅有两个strokeRect(),fillRec ...
- Javascript高级编程学习笔记(86)—— Canvas(3)绘制矩形
绘制矩形 矩形是唯一一种可以直接在2D上下文中绘制的形状. 与矩形有关的方法包括: fillRect() strokeRect() clearRect() 上述方法都接收四个参数: 绘制矩形的 X 坐 ...
- Canvas 绘制矩形,圆形,不规则图形(线条),渐变等图像效果
绘制矩形: getContext("2d") 对象是内建的 HTML5 对象,拥有多种绘制路径.矩形.圆形.字符以及添加图像的方法. fillStyle 方法将其染成红色,fill ...
- canvas绘制矩形
canvas绘制矩形 方法 fillRect(x, y, width, height) 画一个实心的矩形 clearRect(x, y, width, height) 清除一块儿矩形区域 stroke ...
随机推荐
- java datetime数据类型去掉时分秒
在Java中,如果我们想要表示一个日期而不包括时间(时分秒),我们通常会使用java.time包中的LocalDate类.LocalDate是一个不可变的日期对象,它只包含年.月.日三个字段. 1. ...
- Spring的全局(统一)异常处理
异常处理的三种方式 使用 @ExceptionHandler 注解 实现 HandlerExceptionResolver 接口(SpringMVC) 使用 @RestControllerAdvice ...
- 深耕分析型数据库领域,火山引擎ByteHouse入围《2024爱分析数据库厂商全景报告》
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群. 近日,爱分析发布<2024爱分析·数据库厂商全景报告>,报告中爱分析将数据市场从上至下划分为数据库服 ...
- 树莓派4B-GPIO控制舵机转动
树莓派4B-GPIO控制舵机转动 硬件需求: 树莓派 舵机 杜邦线 舵机 什么是舵机? 舵机(servomotor)是一种简化版本的伺服电机,是位置伺服的驱动器,能够通过输入PWM信号控制旋转角度,具 ...
- Swift开发基础05-可选项
可选项定义 可选项,一般也叫可选类型,它允许将值设置为nil 在类型名称后面加个问号? 来定义一个可选项 var name: String? = "Jack" name = nil ...
- 机器学习策略篇:详解处理数据不匹配问题(Addressing data mismatch)
处理数据不匹配问题 如果您的训练集来自和开发测试集不同的分布,如果错误分析显示有一个数据不匹配的问题该怎么办?这个问题没有完全系统的解决方案,但可以看看一些可以尝试的事情.如果发现有严重的数据不匹配问 ...
- 可视化—AntV G6实现节点连线及展开收缩分组
AntV 是蚂蚁金服全新一代数据可视化解决方案,主要包含数据驱动的高交互可视化图形语法G2,专注解决流程与关系分析的图表库 G6.适于对性能.体积.扩展性要求严苛的场景. demo使用数字模拟真实的节 ...
- django python 循环一个月的每一天
from datetime import datetime, timedelta def get_dates_in_month(year, month): start_date = datetime( ...
- [rCore学习笔记 010]基于 SBI 服务完成输出和关机
RustSBI的两个职责 它会在计算机启动时进行它所负责的环境初始化工作,并将计算机控制权移交给内核 在内核运行时响应内核的请求为内核提供服务 这里用不太确切的话表述一下,RustSBI作为介于内核和 ...
- Python 基于Python生成短8位唯一id解决方案
基于Python生成短8位唯一id解决方案 by:授客 QQ:1033553122 测试环境: Win10 Python 3.5.4 实现思路 利用62个可打印字符,通过随机生成32位UUID,由 ...