前言
大家好! 我是热爱图形的fly, 之前在群里和粉丝讨论canvas 如何事件系统, 然后呢? 我自己其实也对这个比较感兴趣, 我看过很多canvas 实现的项目, 比如canvas 实现思维导图 xmind , canvas 实现一个绘图工具。 然后呢无论是哪一个,其实背后都是在canavs 背后实现了一套事件系统,可惜这些源码都不开源。所以本着学习的激情, 我参考了一些文章实现一个简单事件系统。本篇文章你可以学到下面👇这些内容
- 我是怎么基于canvas去构建基础框架的
- 几何算法—— 判断点是不是任意多边形内部
- 如何进行事件分发和阻止事件冒泡
本篇文章我全是干货。欢迎点赞、关注、收藏。
基础框架的搭建
图形类
第一步我要做的事就是进行概念抽象,大家去想一下,canvas本质是一层画布,然后画布上很多图形,有长方形、圆形、以及任意闭合的多边形. 从面向对象的角度考虑的话, 我们可以封装一个基类 —— shape 每个图形是不是都在canvas 去显示,所以都应该有一个
draw 方法, 还有一个方法就是判断鼠标的点 是不是在当前图形的内部,这个我我们后面在讨论吧。 然后每个图形有自己的特有的属性,结合canvas 的api 去设置。
export class Circle extends Shape {
constructor(props) {
super()
this.props = props
}
draw(ctx) {
}
// 判断鼠标的点是否在图形内部
isPointInClosedRegion(mouse) {
}
}
export class Rect extends Shape {
constructor(props) {
super()
this.props = props
}
draw(ctx) {
}
// 判断鼠标的点是否在图形内部
isPointInClosedRegion(mouse) {
}
}
上面两个图形看结构都是一样的,不一样的draw方法, 我给你1分钟时间思考🤔下,canvas 是如何画矩形和画圆的。 其实 就是两个api一个 arc一个rect 然后 你传入对应的参数就好了。这里没什么, 不知道的同学可以去MDN去看下, 我已经讲了很多篇了。我就直接给出代码:
const {
center, radius, fillColor = 'black' } = this.props
const {
x, y } = center
ctx.save()
ctx.beginPath()
ctx.fillStyle = fillColor
ctx.arc(x, y, radius, 0, Math.PI * 2)
ctx.fill()
ctx.closePath()
ctx.restore()
这是圆的, save 和 restore 的方法 妙处 就是 比如我给圆设置红色 ,如果我再去画矩形, 矩形也会变成红色, 这样就不可控了,圆的话就是 圆心 加 半径,加填充颜色。
看完圆的我们在看下矩形的。
const {
leftTop, width, height, fillColor = 'black' } = this.props
const {
x, y } = leftTop
ctx.save()
ctx.beginPath()
ctx.fillStyle = fillColor
ctx.fillRect(x, y, width, height)
ctx.closePath()
ctx.restore()
矩形的属性 一个左上角的点一个长度,一个宽度。ok ,到这里图形基本搭建完成,下面开始搭建画布类
画布类
画布类的目前做的事情非常简单哈,初始化一些属性。首先他有个add() 方法,去往画布增加各个图形。增加的图形,每一个图形内部都去实现了draw 方法。这样实现了往canvas 加图形的操作哈。直接看代码:
// 新建一个画布类
export class Canvas {
constructor() {
this.canvas = document.getElementById('canvas')
this.ctx = this.canvas.getContext('2d')
this.allShapes = []
}