SVG学习【2】:使用遮罩和动画实现证件扫描效果

263 阅读2分钟

前言

项目中要求实现一个证件扫描识别页,未提供UI资源,遂自力更生。

SVG实现

实现遮罩

绘制一个铺满全屏的矩形遮罩层起手:

<svg class="ocr-overlay" width="100%" height="100%">
  <rect
    width="100%"
    height="100%"
    fill="rgba(0,0,0,0.7)"
  />
</svg>

<style>
    .ocr-overlay {
        position: fixed;
        top: 0;
        left: 0;
        height: 100%;
        width: 100%;
    }
</style>

实现识别框

前面已经绘制了一个全屏覆盖的遮罩层,现需挖空中间区域来实现视觉引导(识别区域),可以用svg遮罩实现这一点,遮罩中:白色=保留内容,黑色=透明,因此,扫描框区域用黑色填充,实现透明穿透:

<svg class="ocr-overlay" width="100%" height="100%">
  <!-- 定义遮罩 -->
  <defs>
    <mask id="scanMask">
      <rect width="100%" height="100%" fill="white" />
      <rect
        x="5%"
        rx="5"
        ry="5"
        y="30%"
        width="90%"
        height="30%"
        fill="black"
      />
    </mask>
  </defs>

  <!-- 应用遮罩 -->
  <rect
    width="100%"
    height="100%"
    fill="rgba(0,0,0,0.7)"
    mask="url(#scanMask)"
  />
</svg>

效果如下:

image.png

添加边框及呼吸动画

为扫描区域添加边框和文字说明:

<svg class="ocr-overlay" width="100%" height="100%">
  ...
  <!-- 边框 -->
  <rect
    x="5%"
    y="30%"
    width="90%"
    height="30%"
    fill="none"
    stroke="#1989fa"
    stroke-width="2"
    rx="5"
    ry="5"
  >
    <animate
      attributeName="stroke-opacity"
      values="0.3;1;0.3"
      dur="2.5s"
      repeatCount="indefinite"
    />
    <!-- <animate attributeName="stroke-width" values="0.5;1.5;0.5" dur="2.5s" repeatCount="indefinite"/> -->
  </rect>

  <text fill="#fff" x="50%" y="65%" class="text-16" text-anchor="middle">
    请将证件置于扫描框中,停留5s
  </text>
</svg>

边框动画说明:为描边透明度stroke-opacity(也可选择描边宽度stroke-width)绘制一个不限次数的呼吸动画,类似CSS Animation,效果如下:

image.png

添加扫描线及扫描动画

简单实现一个上下移动的扫描动效:

<svg class="ocr-overlay" width="100%" height="100%">
  ...
  <!-- 扫描线 -->
  <line
    x1="7%"
    y1="32%"
    x2="93%"
    y2="32%"
    stroke="#1989fa"
    stroke-width="1"
  >
    <animate
      attributeName="y1"
      values="32%;58%;32%"
      dur="2.5s"
      repeatCount="indefinite"
    />
    <animate
      attributeName="y2"
      values="32%;58%;32%"
      dur="2.5s"
      repeatCount="indefinite"
    />
  </line>
</svg>

扫描线动画说明:由于是垂直方向移动的扫描线,因此分别对扫描线的y1y2添加动画,效果如下:

scan.webp

完整代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <svg class="ocr-overlay" width="100%" height="100%">
      <!-- 定义遮罩 -->
      <defs>
        <mask id="scanMask">
          <rect width="100%" height="100%" fill="white" />
          <rect
            x="5%"
            rx="5"
            ry="5"
            y="30%"
            width="90%"
            height="30%"
            fill="black"
          />
        </mask>
      </defs>

      <!-- 应用遮罩 -->
      <rect
        width="100%"
        height="100%"
        fill="rgba(0,0,0,0.7)"
        mask="url(#scanMask)"
      />

      <!-- 边框 -->
      <rect
        x="5%"
        y="30%"
        width="90%"
        height="30%"
        fill="none"
        stroke="#1989fa"
        stroke-width="2"
        rx="5"
        ry="5"
      >
        <animate
          attributeName="stroke-opacity"
          values="0.3;1;0.3"
          dur="2.5s"
          repeatCount="indefinite"
        />
        <!-- <animate attributeName="stroke-width" values="0.5;1.5;0.5" dur="2.5s" repeatCount="indefinite"/> -->
      </rect>

      <text fill="#fff" x="50%" y="65%" class="text-16" text-anchor="middle">
        请将证件置于扫描框中,停留5s
      </text>

      <!-- 扫描线 -->
      <line
        x1="7%"
        y1="32%"
        x2="93%"
        y2="32%"
        stroke="#1989fa"
        stroke-width="1"
      >
        <animate
          attributeName="y1"
          values="32%;58%;32%"
          dur="2.5s"
          repeatCount="indefinite"
        />
        <animate
          attributeName="y2"
          values="32%;58%;32%"
          dur="2.5s"
          repeatCount="indefinite"
        />
      </line>
    </svg>

    <style>
      * {
        margin: unset;
        padding: unset;
        box-sizing: border-box;
      }

      .ocr-overlay {
        position: fixed;
        top: 0;
        left: 0;
        height: 100%;
        width: 100%;
      }
    </style>
  </body>
</html>

总结

效果比较简单,但记录一下,总的来说,svg总是会在你觉得某功能用css不好实现或兼容时,给你带来一点小小的矢量震撼!