likes
comments
collection
share

uniapp实现canvas签名板功能

作者站长头像
站长
· 阅读数 41

实现效果

页面效果

uniapp实现canvas签名板功能

预览效果

uniapp实现canvas签名板功能

canvas的简单介绍

canvas 画布,在移动端一般用来制作海报,生成签名等,具体使用教程请查看 MDN Canvas 教程

关于 canvas 各种 api 请查看 w3schools

绘制一个线条

首先创建 canvas 标签。

<canvas id="myCanvas" width="300" height="150" style="border:1px solid grey"></canvas>

获取 canvas 渲染上下文,绘制图形。

const c = document.getElementById("myCanvas");
const ctx = c.getContext("2d");
ctx.beginPath();
ctx.moveTo(20, 20);
ctx.lineTo(20, 100);
ctx.lineTo(70, 100);
ctx.strokeStyle = "red";
ctx.stroke();

下面介绍一下相关 api 的作用。

  1. getContext("2d"):获取 2D 渲染上下文。
  2. beginPath():新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径。
  3. moveTo(x, y):将笔触移动到指定的坐标 x 以及 y 上。
  4. lineTo(x, y):绘制一条从当前位置到指定 x 以及 y 位置的直线。
  5. strokeStyle:设置绘制的线条颜色或者渐变、图案。
  6. stroke():绘制当前路径。

在web上实现一个签名板

实现绘制线条的步骤之后,制作一个签名板就很容易了。签名板一般分为绘制区域和按钮操作区域,操作按钮有重签和确认按钮。重签其实就是清除 canvas 之前绘制的内容,确认其实就是将 canvas 绘制的内容导出图片。

主要方法:

  1. CanvasRenderingContext2D.clearRect():通过把像素设置为透明以达到擦除一个矩形区域的目的
  2. canvas.toDataURL(type, encoderOptions):返回一个包含图片展示的 data URI,默认 type 是 png格式(base64的图片)。

完整实现代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    canvas {
      border: 1px solid #000;
    }

    button {
      margin-top: 10px;
    }
  </style>
</head>

<body>
  <canvas id="signatureCanvas" width="400" height="200"></canvas>
  <button id="clearButton">清除</button>
  <button id="saveButton">保存</button>

  <script>
    // 获取 Canvas 元素
    const canvas = document.getElementById('signatureCanvas');
    const context = canvas.getContext('2d');

    // 设置绘制属性
    context.strokeStyle = '#000';
    context.lineWidth = 2;

    // 添加绘制事件监听器
    let isDrawing = false;
    let lastX = 0;
    let lastY = 0;

    function startDrawing(e) {
      console.log(e);
      isDrawing = true;
      [lastX, lastY] = [e.offsetX, e.offsetY];
    }

    function draw(e) {
      if (!isDrawing) return;
      context.beginPath();
      context.moveTo(lastX, lastY);
      context.lineTo(e.offsetX, e.offsetY);
      context.stroke();
      [lastX, lastY] = [e.offsetX, e.offsetY];
    }

    function stopDrawing() {
      isDrawing = false;
    }

    canvas.addEventListener('mousedown', startDrawing);
    canvas.addEventListener('mousemove', draw);
    canvas.addEventListener('mouseup', stopDrawing);
    canvas.addEventListener('mouseout', stopDrawing);

    // 清除签名
    const clearButton = document.getElementById('clearButton');
    clearButton.addEventListener('click', () => {
      context.clearRect(0, 0, canvas.width, canvas.height);
    });

    // 保存签名
    const saveButton = document.getElementById('saveButton');
    saveButton.addEventListener('click', () => {
      const image = canvas.toDataURL(); // 获取签名图像的数据 URL
      // 在这里可以将图像发送到服务器或进行其他处理
      console.log(image);
    });
  </script>
</body>

</html>

uniapp vue3 实现签名板

小程序上使用 canavs 请查看 画布使用指南

  1. 添加 canvas 组件,将pc上的 mouse 相关事件需要换成对应 touch 事件。
<canvas @touchstart="handleTouch" @touchmove="handleMove" @touchend="handleEnd" class="my-canvas" type="2d"
              canvas-id="myCanvas" id="myCanvas"></canvas>
  1. 定义相关变量,存储信息。
const isDrawing = ref(false); // 是否正在绘制
const ctx = ref(null) // 画布渲染上下文
// 记录最新一次绘制的坐标
const position = reactive({
  x: 0,
  y: 0
})
  1. 初始化 Canvas。
onReady(() => {
  const query = uni.createSelectorQuery()
  query.select('#myCanvas')
      .fields({node: true, size: true})
      .exec((res) => {

        // Canvas 对象
        const canvas = res[0].node;
        // 渲染上下文
        ctx.value = canvas.getContext('2d')

        // Canvas 画布的实际绘制宽高
        const width = res[0].width
        const height = res[0].height

        // 初始化画布大小
        const dpr = uni.getSystemInfoSync().pixelRatio

        canvas.width = width * dpr
        canvas.height = height * dpr
        ctx.value.scale(dpr, dpr)

        // 设置绘制属性
        ctx.value.strokeStyle = '#000'; // 黑色线条
        ctx.value.lineWidth = 2; // 线条宽度

        drawBackground() // 设置白色背景板
      })
})

canvas 默认的背景是透明的,需要设置成白色的背景,实现签名“白纸黑字”。不然导出图片会出现问题的。

const drawBackground = () => {
  // 创建白色矩形背景板
  ctx.value.fillStyle = "#fff"
  ctx.value.fillRect(0, 0, ctx.value.canvas.width, ctx.value.canvas.height)
}

绘制步骤很简单,touchStart 开始绘制,touchMove 进行绘制,touchEnd 结束绘制。小程序现在也是直接使用了 web 的 canvas,我们直接使用 web 上 canvas 的 api 操作就行了。老版的小程序 canvas 很复杂很恶心,不用看了。谢天谢地!

// 开始绘制
const handleTouch = (e) => {
  isDrawing.value = true

  // 获取当前点的坐标
  const x = e.touches[0].x;
  const y = e.touches[0].y;

  position.x = x;
  position.y = y;
}

// 进行绘制
const handleMove = (e) => {
  if (!isDrawing.value) return;

  const x = e.touches[0].x;
  const y = e.touches[0].y;

  // beginPath() 新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径。
  ctx.value.beginPath();
  // moveTo(x,y) 将笔触移动到指定的坐标 x 以及 y 上。
  ctx.value.moveTo(position.x, position.y);
  // lineTo(x, y) 绘制一条从当前位置到指定 x 以及 y 位置的直线。
  ctx.value.lineTo(x, y);
  // stroke() 使用描边通过线条来绘制当前路径,不需要填充闭合路径
  ctx.value.stroke();
  position.x = x;
  position.y = y;
}

// 结束绘制
const handleEnd = (e) => {
  isDrawing.value = false
}

清除签名的时候需要注意,重新把背景设置成白色。不然变成透明背景,用户再次签名导出的图片又出问题了。

const clear = () => {
  ctx.value.clearRect(0, 0, ctx.value.canvas.width, ctx.value.canvas.height)
  drawBackground() // 设置成白色背景
}

最后一步,导出图片预览一下效果。小程序上导出 canvas 绘制内容生成临时路径使用 canvasToTempFilePath 方法。该方法需要传入 canvas 对象,就像 web 上 canvas 的 toDataURL 一样,需要获取到元素节点才能使用。

通过 createSelectorQuery 我们可以获取到小程序上的元素节点,生成的临时路径,使用 previewImage 方法来预览一下效果。

const confirm = () => {
  // 获取 canvas 对象
  uni.createSelectorQuery()
      .select('#myCanvas')
      .node()
      .exec((res) => {
        // 获取 Canvas 对象
        const canvas = res[0].node;
        // 生成图片
        uni.canvasToTempFilePath({
          canvas,
          success: function (res) {
            // 在H5平台下,tempFilePath 为 base64
            console.log(res.tempFilePath)

            // 预览图片
            uni.previewImage({
              urls: [res.tempFilePath]
            })

          },
          fail: (res) => {
            console.log(res)
          }
        })
      })
}

完整代码请查看 github。纯前端效果,仅供参考。如果要上生产环境,需要各位去 DIY 设计页面样式了。感谢阅读,共勉。

转载自:https://juejin.cn/post/7296647000967905306
评论
请登录