我是靠谱客的博主 玩命仙人掌,这篇文章主要介绍HTML5 canvas实现画图程序(附代码),现在分享给大家,希望可以做个参考。

这篇文章给大家介绍的内容是关于HTML5 canvas实现画图程序(附代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

项目简介

整个项目分为两大部分

  1. 场景
    场景负责canvas控制,事件监听,动画处理

  2. 精灵
    精灵则指的是每一种可以绘制的canvas元素

Demo演示地址

项目特点

可扩展性强

sprite精灵实现

父类

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
class Element { constructor(options = { fillStyle: 'rgba(0,0,0,0)', lineWidth: 1, strokeStyle: 'rgba(0,0,0,255)' }) { this.options = options } setStyle(options){ this.options = Object.assign(this.options. options) } }
登录后复制
  1. 属性:

  • options中存储了所有的绘图属性

    • fillStyle:设置或返回用于填充绘画的颜色、渐变或模式

    • strokeStyle:设置或返回用于笔触的颜色、渐变或模式

    • lineWidth:设置或返回当前的线条宽度

    • 使用的都是getContext("2d")对象的原生属性,此处只列出了这三种属性,需要的话还可以继续扩充。

  • 有需要可以继续扩充

  1. 方法:

  • setStyle方法用于重新设置当前精灵的属性

  • 有需要可以继续扩充

所有的精灵都继承Element类。

子类

子类就是每一种精灵元素的具体实现,这里我们介绍一遍Circle元素的实现

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
class Circle extends Element { // 定位点的坐标(这块就是圆心),半径,配置对象 constructor(x, y, r = 0, options) { // 调用父类的构造函数 super(options) this.x = x this.y = y this.r = r } // 改变元素大小 resize(x, y) { this.r = Math.sqrt((this.x - x) ** 2 + (this.y - y) ** 2) } // 移动元素到新位置,接收两个参数,新的元素位置 moveTo(x, y) { this.x = x this.y = y } // 判断点是否在元素中,接收两个参数,点的坐标 choose(x, y) { return ((x - this.x) ** 2 + (y - this.y) ** 2) < (this.r ** 2) } // 偏移,计算点和元素定位点的相对偏移量(ofsetX, offsetY) getOffset(x, y) { return { x: x - this.x, y: y - this.y } } // 绘制元素实现,接收一个ctx对象,将当前元素绘制到指定画布上 draw(ctx) { // 取到绘制所需属性 let { fillStyle, strokeStyle, lineWidth } = this.options // 开始绘制beginPath() 方法开始一条路径,或重置当前的路径 ctx.beginPath() // 设置属性 ctx.fillStyle = fillStyle ctx.strokeStyle = strokeStyle ctx.lineWidth = lineWidth // 画圆 ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI) // 填充颜色 ctx.stroke() ctx.fill() // 绘制完成 } // 验证函数,判断当前元素是否满足指定条件,此处用来检验是否将元素添加到场景中。 validate() { return this.r >= 3 } }
登录后复制

arc() 方法创建弧/曲线(用于创建圆或部分圆)

  • x 圆的中心的 x 坐标。

  • y 圆的中心的 y 坐标。

  • r 圆的半径。

  • sAngle 起始角,以弧度计。(弧的圆形的三点钟位置是 0 度)。

  • eAngle 结束角,以弧度计。

  • counterclockwise 可选。规定应该逆时针还是顺时针绘图。False = 顺时针,true = 逆时针。

注意事项:

  • 构造函数的形参只有两个是必须的,就是定位点的坐标。

  • 其它的形参都必须有默认值。

所有方法的调用时机

  • 我们在画布上绘制元素的时候回调用resize方法。

  • 移动元素的时候调用moveTo方法。

  • choose会在鼠标按下时调用,判断当前元素是否被选中。

  • getOffset选中元素时调用,判断选中位置。

  • draw绘制函数,绘制元素到场景上时调用。

scene场景的实现

  1. 属性介绍

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class Sence { constructor(id, options = { width: 600, height: 400 }) { // 画布属性 this.canvas = document.querySelector('#' + id) this.canvas.width = options.width this.canvas.height = options.height this.width = options.width this.height = options.height // 绘图的对象 this.ctx = this.canvas.getContext('2d') // 离屏canvas this.outCanvas = document.createElement('canvas') this.outCanvas.width = this.width this.outCanvas.height = this.height this.outCtx = this.outCanvas.getContext('2d') // 画布状态 this.stateList = { drawing: 'drawing', moving: 'moving' } this.state = this.stateList.drawing // 鼠标状态 this.mouseState = { // 记录鼠标按下时的偏移量 offsetX: 0, offsetY: 0, down: false, //记录鼠标当前状态是否按下 target: null //当前操作的目标元素 } // 当前选中的精灵构造器 this.currentSpriteConstructor = null // 存储精灵 let sprites = [] this.sprites = sprites /* .... */ } }
登录后复制
  1. 事件逻辑

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
class Sence { constructor(id, options = { width: 600, height: 400 }) { /* ... */ // 监听事件 this.canvas.addEventListener('contextmenu', (e) => { console.log(e) }) // 鼠标按下时的处理逻辑 this.canvas.addEventListener('mousedown', (e) => { // 只有左键按下时才会处理鼠标事件 if (e.button === 0) { // 鼠标的位置 let x = e.offsetX let y = e.offsetY // 记录鼠标是否按下 this.mouseState.down = true // 创建一个临时target // 记录目标元素 let target = null if (this.state === this.stateList.drawing) { // 判断当前有没有精灵构造器,有的话就构造一个对应的精灵元素 if (this.currentSpriteConstructor) { target = new this.currentSpriteConstructor(x, y) } } else if (this.state === this.stateList.moving) { let sprites = this.sprites // 遍历所有的精灵,调用他们的choose方法,判断有没有被选中 for (let i = sprites.length - 1; i >= 0; i--) { if (sprites[i].choose(x, y)) { target = sprites[i] break; } } // 如果选中的话就调用target的getOffset方法,获取偏移量 if (target) { let offset = target.getOffset(x, y) this.mouseState.offsetX = offset.x this.mouseState.offsetY = offset.y } } // 存储当前目标元素 this.mouseState.target = target // 在离屏canvas保存除目标元素外的所有元素 let ctx = this.outCtx // 清空离屏canvas ctx.clearRect(0, 0, this.width, this.height) // 将目标元素外的所有的元素绘制到离屏canvas中 this.sprites.forEach(item => { if (item !== target) { item.draw(ctx) } }) if(target){ // 开始动画 this.anmite() } } }) this.canvas.addEventListener('mousemove', (e) => { // 如果鼠标按下且有目标元素,才执行下面的代码 if (this.mouseState.down && this.mouseState.target) { let x = e.offsetX let y = e.offsetY if (this.state === this.stateList.drawing) { // 调用当前target的resize方法,改变大小 this.mouseState.target.resize(x, y) } else if (this.state === this.stateList.moving) { // 取到存储的偏移量 let { offsetX, offsetY } = this.mouseState // 调用moveTo方法将target移动到新的位置 this.mouseState.target.moveTo(x - offsetX, y - offsetY) } } }) document.body.addEventListener('mouseup', (e) => { if (this.mouseState.down) { // 将鼠标按下状态记录为false this.mouseState.down = false if (this.state === this.stateList.drawing) { // 调用target的validate方法。判断他要不要被加到场景去呢 if (this.mouseState.target.validate()) { this.sprites.push(this.mouseState.target) } } else if (this.state === this.stateList.moving) { // 什么都不做 } } }) } }
登录后复制
  1. 方法介绍

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Sence { // 动画 anmite() { requestAnimationFrame(() => { // 清除画布 this.clear() // 将离屏canvas绘制到当前canvas上 this.paint(this.outCanvas) // 绘制target this.mouseState.target.draw(this.ctx) // 鼠标是按下状态就继续执行下一帧动画 if (this.mouseState.down) { this.anmite() } }) } // 可以将手动的创建的精灵添加到画布中 append(sprite) { this.sprites.push(sprite) sprite.draw(this.ctx) } // 根据ID值,从场景中删除对应元素 remove(id) { this.sprites.splice(id, 1) } // clearRect清除指定区域的画布内容 clear() { this.ctx.clearRect(0, 0, this.width, this.height) } // 重绘整个画布的内容 reset() { this.clear() this.sprites.forEach(element => { element.draw(this.ctx) }) } // 将离屏canvas绘制到页面的canvas画布上 paint(canvas, x = 0, y = 0) { this.ctx.drawImage(canvas, x, y, this.width, this.height) } // 设置当前选中的精灵构造器 setCurrentSprite(Element) { this.currentSpriteConstructor = Element }
登录后复制

相关文章推荐:

canvas如何实现二维码和图片合成的代码

HTML5 Canvas实现交互式地铁线路图

以上就是HTML5 canvas实现画图程序(附代码)的详细内容,更多请关注靠谱客其它相关文章!

最后

以上就是玩命仙人掌最近收集整理的关于HTML5 canvas实现画图程序(附代码)的全部内容,更多相关HTML5内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(119)

评论列表共有 0 条评论

立即
投稿
返回
顶部