利用vue製做在線塗鴉板

效果展現javascript

繪畫板

Canvas API簡介

調用方法

  • getImageData() 返回ImageData對象,該對象爲畫布上指定的矩形複製像素數據html

  • putImageData() 把圖像數據(從指定的 ImageData 對象)放回畫布上java

  • clearRect() 在給定的矩形內清除指定的像素git

  • toDataURL() 返回canvas圖像的URLgithub

  • lineTo() 添加一個新點,建立從該點到最後指定點的線條canvas

  • stroke() 繪製已定義的路徑數組

  • beginPath() 起始一條路徑,或重置當前路徑this

  • moveTo() 把路徑移動到畫布中的指定點,不建立線條spa

調用屬性

  • strokeStyle 設置或返回用於筆觸的顏色、漸變或模式code

  • shadowBlur 設置或返回用於陰影的模糊級別

  • shadowColor 設置或返回用於陰影的顏色

  • lineWidth 設置或返回當前的線條寬度

更多API請參考 canvas基本使用

功能需求說明

  • 基礎線條繪製功能

  • 筆觸顏色修改

  • 筆刷粗細調整

  • 撤回、前進、狀況功能

  • 生成圖片

初始化數據

  • colors: 筆觸顏色列表

  • brushs: 筆刷對應的粗細

  • context: canvas context

  • imgUrl: 用於存放保存圖片的地址

  • canvasMoveUse: 是否容許執行move時候繪製線條

  • preDrawAry: 存儲當前表面狀態數組-上一步

  • nextDrawAry: 存儲當前表面狀態數組-下一步

  • middleAry: 中間數組

  • lineWidth: 線條寬度

  • lineColor: 線條顏色

  • shadowBlur: 陰影

data() {
  return {
    colors: ['#fef4ac','#0018ba','#ffc200','#f32f15','#cccccc','#5ab639'],
    brushs: [{
            className: 'small fa fa-paint-brush',
            lineWidth: 3
          },{
            className: 'middle fa fa-paint-brush',
            lineWidth: 6
          },{
            className: 'big fa fa-paint-brush',
            lineWidth: 12
          }],
    context: {},
    imgUrl: [],
    canvasMoveUse: true,
    preDrawAry: [],
    nextDrawAry: [],
    middleAry: [],
    config: {
      lineWidth: 1,
      lineColor: "#f2849e",
      shadowBlur: 2
    }
  }
}

設置繪畫配置

setCanvasStyle() {
    this.context.lineWidth = this.config.lineWidth
    this.context.shadowBlur = this.config.shadowBlur
    this.context.shadowColor = this.config.lineColor
    this.context.strokeStyle = this.config.lineColor
  }

筆觸顏色及粗細相關設置(點擊修改config數據):

<!-- 畫筆顏色 -->
<li 
  v-for="item in colors" 
  :class="{'active':config.lineColor === item}"
  :style="{ background: item }" 
  @click="setColor(item)"
></li>
<!-- 畫筆粗細 -->
 <span 
  v-for="pen in brushs" 
  :class="[pen.className,{'active': config.lineWidth === pen.lineWidth}]"
  @click="setBrush(pen.lineWidth)"
></span>

畫筆的移動操做

// 當在屏幕中移動時即開始繪製準備
beginPath(e){
  const canvas = document.querySelector('#canvas')
  if (e.target !== canvas) {
    this.context.beginPath()
  }
}
// 在canvas中鼠標按下
 canvasDown(e) {
  // 讓move方法可用
  this.canvasMoveUse = true
  // client是基於整個頁面的座標
  // offset是cavas距離頂部以及左邊的距離
  const canvasX = e.clientX - e.target.parentNode.offsetLeft
  const canvasY = e.clientY - e.target.parentNode.offsetTop
  // 設置canvas的配置
  this.setCanvasStyle()
  //清除子路徑
  this.context.beginPath()
  // 移動的起點
  this.context.moveTo(canvasX, canvasY)
  //當前繪圖表面狀態
  const preData = this.context.getImageData(0, 0, 600, 400)
  //當前繪圖表面進棧
  // 按下至關於新的操做的開始,因此把當前記錄數據放到prev中
  this.preDrawAry.push(preData)
},
// canvas中鼠標移動
canvasMove(e) {
  if(this.canvasMoveUse) {
    // 只有容許移動時調用
    const t = e.target
    let canvasX
    let canvasY
    // 因爲手機端和pc端獲取頁面座標方式不一樣,因此須要作出判斷
    if(this.isPc()){
      canvasX = e.clientX - t.parentNode.offsetLeft
      canvasY = e.clientY - t.parentNode.offsetTop
    }else {
      canvasX = e.changedTouches[0].clientX - t.parentNode.offsetLeft
      canvasY = e.changedTouches[0].clientY - t.parentNode.offsetTop
    }
    // 鏈接到移動的位置並上色
    this.context.lineTo(canvasX, canvasY)
    this.context.stroke()
  }
},
// canvas中鼠標放開
canvasUp(e){
  const preData = this.context.getImageData(0, 0, 600, 400)
  if (!this.nextDrawAry.length) {
    // 在沒有撤銷過的狀況下,將當前數據放入prev
    //當前繪圖表面進棧
    this.middleAry.push(preData)
  } else {
    // 在撤銷的狀況下,將在後面步驟的數據狀況記錄
    this.middleAry = []
    this.middleAry = this.middleAry.concat(this.preDrawAry)
    this.middleAry.push(preData)
    this.nextDrawAry = []
  }
  // 設置move時不可繪製
  this.canvasMoveUse = false
}

爲了保證移動端的可用性,加入touchstart等。

<canvas 
  id="canvas" 
  class="fl" 
  width="600" 
  height="400" 
  @mousedown="canvasDown($event)" 
  @mouseup="canvasUp($event)"
  @mousemove="canvasMove($event)"
  @touchstart="canvasDown($event)" 
  @touchend="canvasUp($event)"
  @touchmove="canvasMove($event)"
>

撤銷清空等操做

// 撤銷
if (this.preDrawAry.length) {
  const popData = this.preDrawAry.pop()
  const midData = this.middleAry[this.preDrawAry.length + 1]
  this.nextDrawAry.push(midData)
  this.context.putImageData(popData, 0, 0)
}
// 前進
if (this.nextDrawAry.length) {
  const popData = this.nextDrawAry.pop()
  const midData = this.middleAry[this.middleAry.length - this.nextDrawAry.length - 2]
  this.preDrawAry.push(midData)
  this.context.putImageData(popData, 0, 0)
}
// 清空
this.context.clearRect(0, 0, this.context.canvas.width, this.context.canvas.height)
// 清空先後數據
this.preDrawAry = []
this.nextDrawAry = []
// middleAry恢復到默認數據
this.middleAry = [this.middleAry[0]]

demo地址


查看代碼

相關文章
相關標籤/搜索