小程序 Canvas 2D 爬坑


微信小程序聲稱 2.9.0 起支持新的 Canvas 2D 接口,且官方推薦,使用性能更好的2d模式。

官網文檔地址 https://developers.weixin.qq.com/miniprogram/dev/component/canvas.html
新的 canvas 2d,接口與 Web 一致,然而,官方的文檔上對新 api 的說明寥寥無幾,只能翻看 Web端api。

wxml

<canvas type="2d" id="canvas" style="width: 100%;height: 400rpx"/>

wxml 中就是簡單加個 id、type,以及樣式。但是官方的 bug 提示中
Bug & Tip

  1. tip: Canvas 2D(新接口)需要顯式設置畫布寬高 (默認為 300x150)

這里有個細節,后續會用。先按照正常流程往后走,取 ctx 對象

drawCanvas(){
    const query = wx.createSelectorQuery()
    query.select('#canvas')
      .fields({ node: true, size: true })
      .exec((res) => {
        const canvas = res[0].node
        const ctx = canvas.getContext('2d')

        const dpr = wx.getSystemInfoSync().pixelRatio
        canvas.width = res[0].width * dpr
        canvas.height = res[0].height * dpr
        ctx.scale(dpr, dpr)

        ctx.fillRect(0, 0, 100, 100)
      })
}

標簽里定義了寬高,在這里又重新定義,難以理解,試着刪除 width、height 的設置。
然而后面的操作出現了變形,即使繪入一個正方形,在畫布上展示的比例也不對。打印出 canvasNode,如下

通過 style 設置的寬高 _width: 375,_height: 195;實際寬高 width: 300,height: 150,顯然來自默認寬高。
回想一下前面的官方bug 提示

  1. tip: Canvas 2D(新接口)需要顯式設置畫布寬高 (默認為 300x150)

大膽設想一下,style設置寬高,相當於設置組件的外部容器,js設置寬高,則是定義實際操作的畫布的寬高。。。
此外,dpr 設置像素比,縮放坐標系,把當前的坐標系橫縱軸放大、縮小到 drp 倍。官方demo中,采用的是設備像素比,旨在達到最佳像素尺寸的圖。
項目中,實際使用時,更多是750設計稿,不妨將其縮放比設為屏幕寬度/750標准寬度,此后的所有尺寸,都可以按照750設計稿上的尺寸來寫入。改寫一下

async drawCanvas(){
    // 取 canvas 節點
    // 此處使用 await
    let canvasNode = await new Promise((resolve, reject)=>{
      // 注意:若canvas是定義在在組件內,需改用
      // const query = wx.createSelectorQuery().in(this)
      const query = wx.createSelectorQuery()
      query.select('#canvas')
        .fields({ node: true, size: true })
        .exec(res=>{
          resolve(res[0])
        })
    })
    let canvas = canvasNode.node,
    ctx = canvas.getContext('2d')
    this.canvas = canvas
    this.ctx = ctx
    // 獲取設備像素比調整畫布尺寸,並縮放坐標系
    const dpr = wx.getSystemInfoSync().screenWidth / 750
    canvas.width = canvasNode.width * dpr
    canvas.height = canvasNode.height * dpr

    // 設置 canvas 坐標原點
    ctx.translate(width/2, height * 2 / 3);
    ctx.scale(dpr, dpr)
}

此處,ctx.translate()用來調整 canvas 坐標系,默認是左上角,ctx.translate(width/2, height * 2 / 3)可設置坐標系原點為橫向中心,縱向2/3高度處。可根據實際應用做調增。
到這里,初步完成 canvas 的前期初始化,后面即可繪制

async render () {
    let canvas = this.canvas
    let ctx = this.ctx
    // 實例化 canvas 圖像
    let image = await new Promise((resolve)=>{
      const img = canvas.createImage()
      img.src = '../images/img-arrow.png'
      img.onload = () => {
        resolve(img)
      }
    })

    let angle = -45    // 實際角度
    let abs = 1        // 正反轉

    // 循環執行
    const renderLoop = () => {
      if(angle>45){
        abs = -1
      }else if(angle<-45){
        abs = 1
      }

      // 清楚畫布
      ctx.clearRect(-375, -400, 750, 750)
      // 保存當前幀,以備復原
      ctx.save()
      // 畫布旋轉
      ctx.rotate(degree / 180 * Math.PI);
      // 繪制圖像
      ctx.drawImage(image, -110, -228, 221, 302)
      // 操作完后復原至 save 步驟
      ctx.restore()
        
      angle += abs
    }
    // 動畫幀循環執行
    canvas.requestAnimationFrame(()=>{
      renderLoop()
    }) 
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM