In the development of wechat applets, some requirement scenarios require users to sign by hand or draw some paths, and canvas is usually used to realize such requirements

We can find the usage method of canvas interface in the official document of small program development, and we can see the official prompt of wechat in the document

2.9.0 Supports a new Canvas 2D interface (type attribute needs to be specified) and supports same-layer rendering. The original interface is no longer maintained. Related API: Get canvas instance.

The instructions in the official document are indeed the old canvas document, so this article will introduce the methods of drawing signatures of the new and old Canvas in detail

In this case, MPX, the development framework of small program, is used. MPX uses the native tags and syntax of wechat small program, so the code can be directly copied into the project for use.

Use the old Canvas interface

Introduce how to use the old version of the small program Canvas interface

  1. First add a Canvas container to the page, and add the corresponding time monitor and handler function

    <view class="main">
      <canvas canvas-id="custom-canvas" class="canvas" bindtouchstart="onStart" bindtouchmove="onMove" bindtouchend="onEnd"></canvas>
    </view>
    Copy the code

    Note that you cannot add type=”2d” to a Canvas element. If you do, the applet will parse the canvas into a new version of canvas2D

  2. Add handler functions to the script

    <script>
    import { createPage } from '@mpxjs/core'
    let ctx
    
    createPage({
      data: {},
      methods: {
        onStart(e) {
          console.log(e)
          const [touch] = e.touches
          const { x, y } = touch
          ctx.moveTo(x, y)
        },
        onMove(e) {
          const [touch] = e.touches
          const { x, y } = touch
          const point = { x, y }
          this.draw(point)
        },
        draw(point) {
          ctx.lineTo(point.x, point.y)
          ctx.stroke()
          ctx.draw(true)
          ctx.moveTo(point.x, point.y)
        },
        onEnd() {
          console.log('Draw end')},init() {
          ctx = wx.createCanvasContext('custom-canvas'.this)
          ctx.setStrokeStyle('#00ff00')
          // Set the width of the line
          ctx.setLineWidth(5)
          // Make the ends of the line more rounded
          ctx.setLineCap('round')
          // Make the connection between the two lines more rounded
          ctx.setLineJoin('round')}},onLoad() {
        this.init()
      }
    })
    </script>
    Copy the code

    Note here:

    • Since you don’t need to use an instance of canvas in the template, you declare CTX as a local variable here

    • Using the old Canvas interface, we can place the initialization process in the onLoad event mounted by the page. During the initialization process, we can create a Canvas instance through the wx.createCanvasContext method. When using frames, you need to pass this value as the second argument to the wx.createcanvasContext method, otherwise you will not get the canvas instance

    • At the start of the TouchStart event, we need to get the starting position of the touch, via the Touches property in the event, which returns the array of positions of the touches. At this point, we set the starting position of the canvas to the position of the touch

      const [touch] = e.touches
      const { x, y } = touch
      ctx.moveTo(x, y)
      Copy the code
    • When drawing events, we must draw as lineTo() > stroke() > draw() > moveTo(). Why add moveTo()? Let’s do a GIF of 0-0

      Don’t usemoveTo()Situation:

      And you can see that if we move too fast, we get dotted points

      addedmoveTo()The effect of:

    • The old version of the interface is no longer maintained, but if you want to adapt to v2.9.0 before the wechat version base library, you need to use the old version of the interface

  3. Set the size of the canvas. Here I set the size of the entire screen

    <style lang="stylus">
    .canvas {
      width 100vw
      height 100vh
      background-color red
    }
    </style>
    Copy the code

Use the new canvas

The new canvas in wechat applet is rendered based on Web standard canvas2D, so relevant interface documents can be viewed from canvas2D section in MDN

How to use canvas2D to implement signature

  1. Also add canvas container element

    <view class="wrapper">
        <canvas
          wx:ref="SIGNATURE"
          class="signature"
          disable-scroll="{{true}}"
          bindtouchstart="onStart"
          bindtouchmove="onMove"
          bindtouchend="onEnd"
          bindtap="oMouseDown"
          type="2d"
        >
        </canvas>
      </view>
    Copy the code

    Note: The Canvas container here adds the type=”2d” attribute to declare that a new version of canvas2D is being used

  2. Instantiate the Canvas instance

    import { createPage } from '@mpxjs/core'
    let context
    
    createPage({
      data: {
        listData: ['mobile phone'.'电视'.'computer']},properties: {
        orders: Array
      },
      methods: {
        /**
         * 绘制签名
         */
        onStart(e) {
          console.log(e)
          const [touch] = e.touches
          const { x, y } = touch
          context.moveTo(x, y)
        },
        onMove(e) {
          const [touch] = e.touches
          const { x, y } = touch
          const point = { x, y }
          this.draw(point)
        },
        cancel(e) {},
        tap(e) {},
        error(e) {},
        onEnd(e) {
          this.triggerEvent('signature-touch-end')},draw(point) {
          context.lineTo(point.x, point.y)
          context.stroke()
          context.moveTo(point.x, point.y)
        },
        init() {
          this.$refs.SIGNATURE.node((result) = > {
            const canvas = result.node
            context = canvas.getContext('2d')
            const { windowHeight, windowWidth, pixelRatio: dpr } = wx.getSystemInfoSync()
            canvas.width = windowWidth * dpr
            canvas.height = windowHeight * dpr
            context.strokeStyle = 'red'
            context.lineWidth = 5
            context.fillStyle = 'rgba(255, 255, 255, 0)'
            context.scale(dpr, dpr)
          }).exec()
        }
      },
      ready() {
        this.init()
      }
    })
    Copy the code

    A brief explanation of the above code:

    • Since the instance of canvas2D needs to get the canvas container element, we can only call the initialization function in onReady at the earliest. If we call this function in onLoad or onShow, we cannot get the Canvas container element

    • This.$refs.signature in the initialization function is a wrapper around the applets’ fetch element method, wx.createsElectorQuery (), so you can use the applets’ native methods to fetch the Canvas container

    • The use of canvas2D requires explicit setting of width and height. The default size of canvas in the applet is 300 * 150, so here I first get the size of the entire available screen, then adapt it to the DPR of the device screen, and scale the canvas. In this way, the display effect of canvas will be specific to each pixel, which is the secret of the ultimate canvas

    • Touch starts the same as the old Canvas interface, requiring moveTo to the starting point

    • The way canvas2D draws is different from the old canvas: Canvas2D just needs lineTo() > stroke() > moveTo() without explicitly calling draw(), as shown in the following GIF, or the older canvas is more delicate

  3. Sets the width and height of the canvas container

    .wrapper {
      width 100vw
      height 100vh
      display flex
      justify-context center
      align-items center
    }
    .signature {
      width 100vw
      height 100vh
      margin:0 auto
    }
    Copy the code

    Note: The width and height of the Canvas element set here is different from the width and height of the canvas instantiated. It can be considered as a container, and the width and height in the instance are the width and height of the canvas

other

The old canvas interface of canvas2D and applet also provides methods to clear the canvas and generate pictures. In this article, we only show the drawing part of the canvas. If you want to do further functions, you can refer to relevant documents