zoukankan      html  css  js  c++  java
  • 小程序 canvas type=2d 来做画画板,有橡皮擦,选颜色,选粗细,撤销和还原

     canvas api 文档:https://www.canvasapi.cn/

    组件里的 canvas

     
     
            <canvas
             class="handWriting"
              id="handWriting"
              canvas-id="handWriting"
              type="2d"
              disable-scroll="true"
              @touchstart="uploadScaleStart"
              @touchmove="uploadScaleMove"
              @touchend="uploadScaleEnd"
              @touchcancel="uploadScaleEnd"
              @tap.stop
            />
    this.handwriting = new Handwriting(
          {
            canvasName: 'handWriting',
          },
          this
        )
    import { systemObj, loadImgSync, canvasToUrlSync } from '../../utils/utils'
    
    class Handwriting {
      // 内置数据
      ctx: any
      canvas: any
      canvasWidth = 300
      canvasHeight = 600
      canvasSaveImgs: any = []
      drawCurrent = 0
      beginPoint: any = {}
      points: any = []
      canvasName = ''
      that = {}
    
      firstTouch = true // 第一次触发
      lineColorVal = ''
      lineColorAlpha = 1
      lineSize = 10
      isClear = false // 橡皮擦
    
      constructor(opts: any, _this: any) {
        this.canvasName = opts.canvasName || 'handWriting'
        this.that = _this
        this.init()
      }
    
      init() {
        const query = uni.createSelectorQuery().in(this.that)
        const config = { node: true, size: true }
        query
          .select(`#${this.canvasName}`)
          .fields(config, (res: any) => {
            // console.log('canvas init:=>', res, systemObj)
            const canvas = res.node
            const ctx = canvas.getContext('2d')
            const { pixelRatio: dpr } = systemObj
            const width = res.width * dpr
            const height = res.height * dpr
            canvas.width = width
            canvas.height = height
            ctx.scale(dpr, dpr)
            this.ctx = ctx
            this.canvas = canvas
            this.canvasWidth = width
            this.canvasHeight = height
            // ctx.fillRect(10, 10, 33, 33) // test
          })
          .exec()
      }
      // 笔迹开始
      uploadScaleStart(event: any) {
        // console.log('start', event)
        const e = event.mp
        if (e.type !== 'touchstart') return false
        const { x, y } = e.touches[0]
        this.points.push({ x, y })
        this.beginPoint = { x, y }
        this.ctx.strokeStyle = `rgba(${this.lineColorVal}, ${this.lineColorAlpha})`
        this.ctx.lineWidth = this.lineSize
    
        if (systemObj.platform !== 'devtools') {
          this.ctx.lineCap = 'round'
          let type = 'source-over'
          this.isClear && (type = 'destination-out')
          this.ctx.globalCompositeOperation = type
        }
    
        // if (this.firstTouch) {
        //   this.firstTouch = false
        // }
      }
      drawLine(beginPoint: any, controlPoint: any, endPoint: any) {
        this.ctx.beginPath()
        this.ctx.moveTo(beginPoint.x, beginPoint.y)
        this.ctx.quadraticCurveTo(controlPoint.x, controlPoint.y, endPoint.x, endPoint.y)
        this.ctx.stroke()
        this.ctx.closePath()
      }
      // 笔迹移动
      uploadScaleMove(event: any) {
        // console.log('move')
        let e = event.mp
        if (e.type !== 'touchmove') return false
        if (e.cancelable) {
          // 判断默认行为是否已经被禁用
          if (!e.defaultPrevented) {
            e.preventDefault()
          }
        }
        const { x, y } = e.touches[0]
        this.points.push({ x, y })
        if (this.points.length > 3) {
          const lastTwoPoints = this.points.slice(-2)
          const controlPoint = lastTwoPoints[0]
          const endPoint = {
            x: (lastTwoPoints[0].x + lastTwoPoints[1].x) / 2,
            y: (lastTwoPoints[0].y + lastTwoPoints[1].y) / 2,
          }
          this.drawLine(this.beginPoint, controlPoint, endPoint)
          this.beginPoint = endPoint
        }
      }
      // 笔迹结束
      async uploadScaleEnd(event: any) {
        const e = event.mp
        if (e.type != 'touchend') return 0
        const { x, y } = e.changedTouches[0]
        this.points.push({ x, y })
    
        if (this.points.length > 3) {
          const lastTwoPoints = this.points.slice(-2)
          const controlPoint = lastTwoPoints[0]
          const endPoint = lastTwoPoints[1]
          this.drawLine(this.beginPoint, controlPoint, endPoint)
        }
        this.beginPoint = null
        this.points = []
    
        await this.drawEnd()
      }
      async getCanvasUrl() {
        return await canvasToUrlSync(this.canvas)
      }
      async drawEnd() {
        const saveSteps = this.canvasSaveImgs.length
        if (this.drawCurrent > 0) {
          this.canvasSaveImgs.length = saveSteps - this.drawCurrent
          this.drawCurrent = 0
        }
        this.canvasSaveImgs.push(await this.getCanvasUrl())
      }
      selectColorEvent(val: any) {
        this.lineColorVal = val
        this.isClear = false
      }
      selectLineSize(val: any) {
        this.lineSize = val
      }
      clearEvent() {
        this.isClear = true
      }
      noClearEvent() {
        this.isClear = false
      }
      clearAllCanvas() {
        this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
      }
      async stepChange(type: string) {
        const saveSteps = this.canvasSaveImgs.length
    
        if (type === 'last') {
          if (this.drawCurrent < saveSteps) {
            this.drawCurrent++
          } else {
            return
          }
        }
        if (type === 'next') {
          if (this.drawCurrent > 0) {
            this.drawCurrent--
          } else {
            return
          }
        }
    
        this.clearAllCanvas()
        this.ctx.globalCompositeOperation = 'source-over'
    
        if (this.drawCurrent === saveSteps) {
          return
        }
    
        const index = saveSteps - this.drawCurrent - 1
        const { pixelRatio: dpr } = systemObj
        const img: any = await loadImgSync(this.canvas, this.canvasSaveImgs[index])
        this.ctx.drawImage(
          img,
          0,
          0,
          this.canvasWidth,
          this.canvasHeight,
          0,
          0,
          this.canvasWidth / dpr,
          this.canvasHeight / dpr
        )
      }
      getHelpfulData() {
        return {
          drawCurrent: this.drawCurrent,
          saveSteps: this.canvasSaveImgs.length,
        }
      }
    }
    
    export default Handwriting

    utils.js

    export function loadImgSync(canvas: any, url: string) {
      const img = canvas.createImage()
      img.src = url
      return new Promise((resolve, reject) => {
        img.onload = () => {
          resolve(img)
        }
      })
    }
    
    export function canvasToUrlSync(canvas: any) {
      return new Promise((resolve, reject) => {
        wx.canvasToTempFilePath({
          canvas,
          success: async (res: any) => {
            // console.log('tools-url:>', res.tempFilePath)
            // uni.previewImage({
            //   urls: [res.tempFilePath]
            // })
            resolve(res.tempFilePath)
          },
          fail: (err) => {
            console.log('图片生成失败:' + JSON.stringify(err))
            reject()
          },
        })
      })
    }

    export const systemInfo = uni.getSystemInfoSync()

  • 相关阅读:
    HTML常用标签
    JSP是什么?
    Linux下叹号!的用法
    原码、反码、补码、移码之间的关系和转换
    关于联想超极本出现蓝屏Default Boot Device Missing or Boot Failed的解决办法
    基于UEFI和GPT模式下U盘安装windows8.1和Linux双启动教程
    horizon服务
    neutron网络服务部署
    neutron网络服务
    cinder存储服务
  • 原文地址:https://www.cnblogs.com/xiangsj/p/15100105.html
Copyright © 2011-2022 走看看