首页前端开发HTMLHTML5 canvas实现画图程序(附代码)

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

时间2024-01-23 14:47:22发布访客分类HTML浏览259
导读:收集整理的这篇文章主要介绍了HTML5 canvas实现画图程序(附代码),觉得挺不错的,现在分享给大家,也给大家做个参考。这篇文章给大家介绍的内容是关于HTML5 canvas实现画图程序(附代码),有一定的参考价值,有需要的朋友可以参考...
收集整理的这篇文章主要介绍了HTML5 canvas实现画图程序(附代码),觉得挺不错的,现在分享给大家,也给大家做个参考。这篇文章给大家介绍的内容是关于HTML5 canvas实现画图程序(附代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

项目简介

整个项目分为两大部分

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

  2. 精灵
    精灵则指的是每一种可以绘制的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实现画图程序(附代码)的详细内容,更多请关注其它相关文章!

声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!

html5javascript

若转载请注明出处: HTML5 canvas实现画图程序(附代码)
本文地址: https://pptw.com/jishu/584324.html
Websocket原理的深入理解 canvas实现九宫格心形拼图的方法(附代码)

游客 回复需填写必要信息