微信小程序/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来单独绘制黑白蒙版,过程踩过的坑就不多说了,最后只有这个办法最有效。一定要最后点击的时候再去生成蒙版,再过程生成会出现卡顿现象。秒生成。

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

相关推荐
漠河愁23 天前
pdf文件渲染到canvas
canvas·pdf.js·fabirc.js
xachary1 个月前
前端使用 Konva 实现可视化设计器(21)- 绘制图形(椭圆)
canvas·konva
x007xyz1 个月前
前端纯手工绘制音频波形图
前端·音视频开发·canvas
甄齐才2 个月前
canvas绘制文本时,该如何处理首行缩进、自动换行、多内容以省略号结束、竖排的呢?
canvas·html2canvas·海报·html转图片·文章分享·dom-to-image·html转image
万水千山走遍TML2 个月前
canvas绘制表格
前端·javascript·vue.js·canvas·canvas绘图·在vue中使用canvas·canvas绘制表格
xachary2 个月前
前端使用 Konva 实现可视化设计器(19)- 连接线 - 直线、折线
javascript·vue·canvas·konva
梦想身高1米82 个月前
canvas.toDataURL后图片背景变成黑色
前端·canvas
x007xyz2 个月前
Fabric.js实时播放视频并扣除绿幕
前端·javascript·canvas
xachary2 个月前
前端使用 Konva 实现可视化设计器(18)- 素材嵌套 - 加载阶段
算法·canvas·konva
LeaferJS2 个月前
LeaferJS 1.0 重磅发布:强悍的前端 Canvas 渲染引擎
前端·canvas