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()

  • 相关阅读:
    1.27
    1.25
    Representation Learning with Contrastive Predictive Coding
    Learning a Similarity Metric Discriminatively, with Application to Face Verification
    噪声对比估计(负样本采样)
    Certified Adversarial Robustness via Randomized Smoothing
    Certified Robustness to Adversarial Examples with Differential Privacy
    Dynamic Routing Between Capsules
    Defending Adversarial Attacks by Correcting logits
    Visualizing Data using t-SNE
  • 原文地址:https://www.cnblogs.com/xiangsj/p/15100105.html
Copyright © 2011-2022 走看看