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

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

相关推荐
柳晓黑胡椒2 天前
cesiusm实现 多图例展示+点聚合(base64图标)
css3·canvas·base64·cesium·animation
余生H9 天前
即时可玩web小游戏(二):打砖块(支持移动端版) - 集成InsCode快来阅读并即时体验吧~
前端·javascript·inscode·canvas·h5游戏
普兰店拉马努金16 天前
【Canvas与图标】牛皮纸文件袋图标
canvas·图标·文件袋·牛皮纸
德育处主任18 天前
前端啊,拿Lottie炫个动画吧
前端·svg·canvas
GDAL19 天前
深入剖析Canvas的getBoundingClientRect:精准定位与交互事件实现
canvas
剑亦未配妥22 天前
使用js和canvas、html实现简单的俄罗斯方块小游戏
前端·javascript·canvas·1024程序员节
howard200523 天前
2.1 HTML5 - Canvas标签
html5·canvas
普兰店拉马努金1 个月前
【Canvas与标牌】立入禁止标牌
canvas·警示·标识·立入禁止
Anlige1 个月前
Javascript:使用canvas画二维码矩阵
javascript·canvas·qrcode
牛老师讲GIS1 个月前
分享一个从图片中提取色卡的实现
canvas·提取颜色