微信小程序/mpvue/uniapp 实现canvas在图片上绘画框选

前言:简单的框选需求踩坑无数,此刻只想说句轻舟已过万重山。

  1. 微信官方Canvas新旧接口问题
  2. 轨迹不规则问题
  3. 再上一次基础上画图问题
  4. 安卓真机drawImage模糊问题
  5. 安卓真机fillRect不能为负值问题
  6. 撤回、恢复、清空问题
  7. 黑白蒙版生成问题(AI接口需要)

1、微信官方Canvas新旧接口

由于mpvue框架限制(无数次吐槽这个框架6年前就已经不再维护了),只能使用旧版CanvasContext接口。 uniapp框架建议使用新版 Canvas2D 接口。

js 复制代码
 // 旧版
const ctx = wx.createCanvasContext('myCanvas'); 

// 新版
const query = wx.createSelectorQuery()
    query.select('#myCanvas')
      .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)
      })
  }

2、轨迹不规则

绘制矩形比较简单,一笔下来没有问题,但是如果过程轨迹反复弯曲,就会出现下面情况

如果只是画一次,那么直接ctx.draw(false)就好了不会出现这个问题,但是需求是可以反复绘画矩形。

3、再上一次基础上画图

既然是要在上一次基础上画图,那么ctx.draw(true)就要这样,但是这样又会出现问题2。于是换个思路,每次画完都保存一次临时图片,再上一次临时图片基础上画图。代码如下

js 复制代码
this.ctx.draw(true, () => {
    wx.canvasToTempFilePath({
      x: 0,
      y: 0,
      width: this.canvasWidth,
      height: this.canvasHeight,
      destWidth: this.canvasWidth,
      destHeight: this.canvasHeight,
      canvasId: 'myCanvas',
      success: res => {
        this.allDrawWorksPath.push(res.tempFilePath)
      },
      fail: res => {
        console.log('获取画布图片失败', res);
      }
})

4、安卓真机drawImage模糊问题

本以为一切就大功告成了,模拟器和ios没有问题,但是到了andriod真机,就会出现画的矩形越多,之前的矩形就越模糊,查阅了很多方法比如放大图片比例并未解决,比如动态改变canvasid,但是这个方法尤其的麻烦。于是突然奇想,在canvas和图片两层之间夹一层绘画轨迹图片,有点类似于汉堡,说到这突然想起电影《无双》里面一个片段,两层之间夹一层水印的道理

于是有了下面代码

html 复制代码
<canvas class="mycanvas" canvas-id="myCanvas" disable-scroll @touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd" :style="{'width': canvasWidth+ 'px', 'height': canvasHeight+'px', left: canvasLeft + 'px', top: canvasTop + 'px',zIndex: 9}"></canvas>
html 复制代码
 <image :src="轨迹图片" :style="{'width': canvasWidth+ 'px', 'height': canvasHeight+'px', left: canvasLeft + 'px', top: canvasTop + 'px',zIndex: 8,'position':'absolute'}" />
 <image src="真实图片" :style="{'width': canvasWidth+ 'px', 'height': canvasHeight+'px', left: canvasLeft + 'px', top: canvasTop + 'px',zIndex: 7,'position':'absolute'}" />

5、安卓真机fillRect不能为负值

就当再一次以为大功告成的时候,结果安卓真机毫无意外的又出了意外。右下向左上框选的时候,没有显示。这个问题就是源于安卓机不支持fillRect()方法里面的width和height为负值的情况。于是将fillRect拆成fill和rect两个方法。先去rect再去fill,巧妙解决问题

js 复制代码
this.ctx.rect(this.p1.x, this.p1.y, rectWidth, rectHeight);
this.ctx.fill()

6、撤回、恢复、清空

这三个问题就比较好解决了,但是还是有坑。如果使用轨迹重绘,那么在真机上会看到重绘过程,用户体验极差尤其是轨迹太多的情况。于是采用临时图片的方式,不用担心模拟器会闪屏,再真机上是没有任何问题的。

js 复制代码
this.ctx.draw(true, () => {
    wx.canvasToTempFilePath({
      x: 0,
      y: 0,
      width: this.canvasWidth,
      height: this.canvasHeight,
      destWidth: this.canvasWidth,
      destHeight: this.canvasHeight,
      canvasId: 'myCanvas',
      success: res => {
        this.allDrawWorksPath.push(res.tempFilePath) // 没错就是这一步很关键
      },
      fail: res => {
        console.log('获取画布图片失败', res);
      }
    })
  });

7、黑白蒙版生成问题(AI接口需要)

由于业务需要,要将画好的图片变成黑白蒙版以供AI接口。所以还需要一个canvas来单独绘制黑白蒙版,过程踩过的坑就不多说了,最后只有这个办法最有效。一定要最后点击的时候再去生成蒙版,再过程生成会出现卡顿现象。秒生成。

在此之前,已经实现了涂抹功能,也踩过很多坑,总的来说比款选坑少,就不多描述了。。。最后贴上效果图

相关推荐
蛋蛋_dandan6 小时前
Fabric.js从0到1实现图片框选功能
canvas
wayhome在哪2 天前
用 fabric.js 搞定电子签名拖拽合成图片
javascript·产品·canvas
德育处主任2 天前
p5.js 掌握圆锥体 cone
前端·数据可视化·canvas
德育处主任3 天前
p5.js 3D 形状 "预制工厂"——buildGeometry ()
前端·javascript·canvas
德育处主任5 天前
p5.js 3D盒子的基础用法
前端·数据可视化·canvas
掘金安东尼5 天前
2分钟创建一个“不依赖任何外部库”的粒子动画背景
前端·面试·canvas
百万蹄蹄向前冲6 天前
让AI写2D格斗游戏,坏了我成测试了
前端·canvas·trae
用户2519162427118 天前
Canvas之画图板
前端·javascript·canvas
FogLetter11 天前
玩转Canvas:从静态图像到动态动画的奇妙之旅
前端·canvas
用户25191624271112 天前
Canvas之贪吃蛇
前端·javascript·canvas