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

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

相关推荐
桃园码工1 天前
4_使用 HTML5 Canvas API (3) --[HTML5 API 学习之旅]
前端·html5·canvas
桃园码工7 天前
1_HTML5 Canvas 概述 --[HTML5 API 学习之旅]
前端·html5·canvas
码上佳人14 天前
Uniapp中canvas画图生成图片并下载到相册
uni-app·canvas
普兰店拉马努金18 天前
【Canvas与图标】乡土风金属铝边立方红黄底黑字图像处理图标
canvas·图标
SunFlower91419 天前
v3通过pdfjs-dist插件渲染后端返回的pdf文件流,并实现缩放、下一页
前端·svg·canvas·pdfjs-dist
普兰店拉马努金22 天前
【Canvas与雷达】点鼠标可暂停金边蓝屏雷达显示屏
canvas·雷达
Marshall35721 个月前
Canvas 和 SVG 的高级使用与性能优化
前端·svg·canvas
webmote1 个月前
做一个FabricJS.cc的中文文档网站——面向markdown编程
canvas·fabric·使用手册·中文·fabricjs
小黄人软件1 个月前
【AI协作】让所有用电脑的场景都能在ChatGPT里完成。Canvas :新一代可视化交互,让AI易用易得
人工智能·chatgpt·canvas
柳晓黑胡椒1 个月前
cesiusm实现 多图例展示+点聚合(base64图标)
css3·canvas·base64·cesium·animation