HTML5 canvas实现画图程序(附代码)

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

项目简介

整个项目分为两大部分

Demo演示地址

项目特点

可扩展性强

sprite精灵实现

父类

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元素的实现

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. 属性介绍

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. 事件逻辑

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. 方法介绍

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实现画图程序(附代码)的详细内容,更多内容请关注技术你好其它相关文章!

来源链接:
免责声明:
1.资讯内容不构成投资建议,投资者应独立决策并自行承担风险
2.本文版权归属原作所有,仅代表作者本人观点,不代表本站的观点或立场
标签: Canvas
上一篇:php获取远程图片并下载保存到本地的方法分析 下一篇:html5实现移动端下拉刷新(原理和代码)

相关资讯