微信小程序/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 天前
登录页还在用渐变?我一口气做了 5 个能摸的背景动效:吹蒲公英、滴墨染水、点熔岩闷裂
前端·canvas·交互设计
Highcharts.js1 天前
Highcharts 渲染方式解析:SVG 默认渲染与 Boost 模块的 WebGL 加速,以及它与其他可视化库的不同
svg·webgl·可视化·canvas·highcharts·渲染方式
AndrewHZ5 天前
图像处理入门018 | 简易图像浏览器开发:用 OpenCV + Tkinter 打造你的第一个图像 GUI 工具
图像处理·人工智能·opencv·canvas·tkinter·事件绑定
进哥AI研习社7 天前
WebGL 与视频背景——首屏视觉层的性能博弈
性能优化·webgl·gpu·canvas·shader·帧率·视频背景
MicrosoftReactor11 天前
技术速递|Canvas 如何让 Agentic Workflow 更可见、可控、更高效
ai·agent·canvas
又吹风_Bassy17 天前
介于 NanoVG 和 Skia 之间:C++17 可嵌入式 2D 渲染库 WhatsCanvas 全面介绍
canvas·skia·2d渲染库·nanovg·开源渲染库·whatscanvas·whatsui
今日无bug18 天前
HTML5 Canvas:从画图到游戏开发
前端·canvas
敲敲敲敲暴你脑袋23 天前
升级啦!纯前端打包下载离线地图
javascript·gis·canvas
DsirNg24 天前
用原生 HTML5 视频与 Canvas 实现浏览器端视频抽帧封面
javascript·canvas·视频抽帧·前端实战·html5 video·浏览器 api
牧艺1 个月前
cos-design BubbleField:用 Canvas 做一个「会呼吸」的深海气泡场
前端·webgl·canvas