vue canvas 基础入门

体验demo地址: https://arthurdarkstone.github.io/vue-canvas/
完整版的代码地址: https://github.com/LuciferDarkstone/vue-canvas

canvas

先看下成品效果
预览1预览2

Canvas Api

话不多说、先了解下canas 的api

https://www.canvasapi.cn/
canvas api可以看出,canvas 的api 还不是很复杂

首先了解下入口函数: getContext()
参数 getContext 的参数有四种类型 2d | webgl | webgl2 | bitmaprenderer 由于是入门教程,这里只举例最简单的2d

canvas Init 初始化

由于我们使用的是 vue ,所以要最大程度利用vue 自身特性来结合canvas
canvas绘制之初,首先需要用到获取canvas 的元素,

<canvas id="canvas" />

const canvas = document.querySelector('#canvas')

这里直接用 document.querySelector 根据id来获取canvas 元素

第二步就是利用刚才提到的入口函数来获取 context 即canvas的 “上下文
由于我们用的是vue ,可以将context 放到 data 里面

  data() {
    return {
      context: {},
  },
  mount() {
  	const canvas = document.querySelector('#canvas')
    this.context = canvas.getContext('2d')
  }

canvas 绘制

就像把大象放进冰箱里,canvas绘制的也是简单的三个步骤,
context.beginPath(开始)、context.xxx(绘制)、 context.closePath(结束)

绘制的是最重要的一步,从api 来看,都是简单的小学几何画图
绘制的方法通过api 命名,我们可以大致推断出api 的作用,具体的详细功能同学们可以去自己去查看
https://www.canvasapi.cn/

这里只简单介绍下一会会用到的 api
beginPath closePath 就是绘制开始,结束时调用的函数,比如每次画线时, 都要用到,注意记得 closePath 关闭图案绘制

	this.context.strokeRect(0, 0, this.canvasWidth, this.canvasHeight)
	this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
	this.context.fillRect(0, 0, this.canvasWidth, this.canvasHeight)

我的画板的核心是绘制矩形, 一般情况下这三个绘制函数已经足够了

鼠标事件监听

绘制时候需要监听鼠标移动的事件,来决定绘制的图像的形状

  1. 获取鼠标点击时初始点位置,即图像的原点
  2. 获取鼠标点击时移动的距离,即图像的大小
  3. 获取鼠标松开时的位置,即图像的最终大小

首先在 template 中定义canvas 的监听事件

	<canvas
      id="canvas"
      class="canvas-item"
      :width="canvasWidth"
      :height="canvasHeight"
      @mousedown="canvasDown($event)"
      @mouseup="canvasUp($event)"
      @mousemove="canvasMove($event)"
    />

同时在methods 中定义对应函数

canvasDown(e) {}
canvasMove(e) {}
canvasUp(e) {}

canvas init

此时的画板是空白的,各项的指数都是默认值,
空白
可以在mounted() 中定义canvas 绘制的各个参数

  mounted() {
    const canvas = document.querySelector('#canvas')

    this.context = canvas.getContext('2d')
    this.initCanvas()
  },
  methods: {
    initCanvas() { // 初始化
      this.context.lineWidth = 1
      this.context.shadowBlur = 1
      this.context.shadowColor = '#2c3e50'
      this.context.strokeStyle = '#2c3e50'
    }
  }

也可以定义一个 reset 的函数,来重置画板

resetCanvas() { // 清空画布
  this.context.fillStyle = '#fff'
  this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
  this.context.fillRect(0, 0, this.canvasWidth, this.canvasHeight)
  this.context.fillStyle = '#000'
},

canvas 绘制

绘制的过程是在 canvasDown canvasMove canvasUp 中的

	canvasDown(e) {
      // reset
      this.moving = true // 是否是在绘制
      this.moveStep = 0
      this.boxNumber++

      const { target } = e

      // 获取鼠标初始位置
      const canvasX = e.clientX - target.offsetLeft
      const canvasY = e.clientY - target.offsetTop
      // 初始位置赋值给全局
      this.rectPos.x = canvasX
      this.rectPos.y = canvasY
      this.context.beginPath()

      this.context.moveTo(canvasX, canvasY)
      this.tempImgData = this.context.getImageData(0, 0, this.canvasWidth, this.canvasHeight) // 记录暂时图像
    },
	canvasMove(e) {
      if (this.moving) {
        const { target } = e
        // 获取鼠标位置
        const canvasX = e.clientX - target.offsetLeft
        const canvasY = e.clientY - target.offsetTop
        // 获取初始位置
        const { x, y } = this.rectPos

        this.context.fillStyle = '#2883dd'
        this.context.strokeRect(x, y, canvasX - x, canvasY - y)
        this.context.fillStyle = '#000'
      }
    },
	canvasUp(e) {
      const { target } = e
      // 获取鼠标结束位置
      const canvasX = e.clientX - target.offsetLeft
      const canvasY = e.clientY - target.offsetTop
      // 获取初始位置
      const { x, y } = this.rectPos
      if (this.moving) {
		this.context.fillStyle = '#2883dd'
        this.context.strokeRect(x, y, canvasX - x, canvasY - y)
        this.context.fillStyle = '#000'
        this.context.fillRect(x, y, canvasX - x, canvasY - y)
	  }

      this.context.closePath()
      this.moving = false
    },

现在实现的效果类似会是这样
hover为了实现在鼠标移动时能够有过度效果,可以结合vue 的watch 来监听移动时间来实现

在每次记录鼠标点击时,记录初始未开始本次绘制时的图像数据

	canvasDown(e) {
 	  // xxxxxxxxxx
 	  // xxxxxxxxxxxx
      this.tempImgData = this.context.getImageData(0, 0, this.canvasWidth, this.canvasHeight)
    },

首先要记录mouseMove 中的鼠标移动距离(绘制的图型大小)

canvasMove(e) {
   if (this.moving) {
     const { target } = e
     // 获取鼠标位置
     const canvasX = e.clientX - target.offsetLeft
     const canvasY = e.clientY - target.offsetTop
     // 获取初始位置
     const { x, y } = this.rectPos
 	
 	 this.moveX = canvasX - x
 	 this.moveY = canvasY - y

     this.context.fillStyle = '#2883dd'
     this.context.strokeRect(x, y, canvasX - x, canvasY - y)
     this.context.fillStyle = '#000'
   }
 },
watch: {
  moveX(newV, oldV) {
    if (newV - oldV) { // mouseOver rect选择效果
      this.context.putImageData(this.tempImgData, 0, 0)
    }
  },
  moveY(newV, oldV) {
    if (newV - oldV) { // mouseOver rect选择效果
      this.context.putImageData(this.tempImgData, 0, 0)
    }
  }
 },

这样即可简单实现效果

增加功能

现在实现的仅仅是一个能绘制矩形的画板,可以向其中按照需求增加功能, 如:

增加角标
增加角标记录初始位置
记录初始位置
同理也可绘制 直线、圆等奇怪图形,不做介绍

完整版代码地址: https://github.com/LuciferDarkstone/vue-canvas

Logo

前往低代码交流专区

更多推荐