本文示例源码:https://github.com/yanhaijing/imagic

本文示例预览:https://yanhaijing.com/imagic/demo/

业务中涉及图片的制作和审核功能,审核人员需要在图片中进行标注,并说明存在的问题,标注过程中需要支持放大缩小,移动等交互,将业务剥离,这个需求,可以定义为实现一个图片标注功能。

实现这个功能并不容易,其涉及的前端知识点众多,本文带领大家从零到一,亲手实现一个,支持缩放,移动,编辑的图片标注功能,文字描述是抽象的,眼见为实,实现效果如下所示:

https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/61ba0d2b3fb94f7bb94e45fd85288acc~tplv-k3u1fbpfcp-jj-mark:3024:0:0:0:q75.gif#?w=667&h=470&s=7598552&e=gif&f=77&b=caddda

技术方案

这里涉及两个关键功能,一个是绘制,包括缩放和旋转,一个是编辑,包括选取和修改尺寸,涉及到的技术包括,缩放,移动,和自定义形状的绘制(本文仅实现矩形),绘制形状的选取,改变尺寸和旋转角度等。

从大的技术选型来说,有两种实现思路,一种是 canvas,一种是 dom+svg,下面简单介绍下两种思路和优缺点。

canvas 可以方便实现绘制功能,但编辑功能就比较困难,当然这可以使用库来实现,这里我们考虑自己亲手实现功能。

dom+svg 也可以实现功能,缩放和旋转可以借助 css3 的 transform。

总的来说,如果对性能有较高要求,或需要进行复杂的图形处理和像素操作,可以选择基于 Canvas 的方案。否则可以选择基于 DOM + SVG 的方案。在具体实现时,可以根据项目需求和技术栈进行选择。

下面我们选择基于 canvas 的方案,通过例子,一步一步实现完成功能,让我们先从最简单的开始。

渲染图片

本文我们不讲解 canvas 基础,如果你不了解 canvas,可以先在网上找资料,简单学习下,图片的渲染非常简单,只用到一个 API,这里我们直接给出代码,示例如下:

这里我们提前准备一个 canvas,宽高设定为 1000*700,这里唯一的一个知识点就是要在图片加载完成后再绘制,在实战中,需要注意绘制的图片不能跨域,否则会绘制失败。

<body>
  <div>
    <canvas id="canvas1" width="1000" height="700"></canvas>
  </div>
  <script>
    const canvas1 = document.querySelector('#canvas1');
    const ctx1 = canvas1.getContext('2d');
    let width = 1000;
    let height = 700;

    let img = new Image();
    img.src = './bg.png';
    img.onload = function () {
      draw();
    };

    function draw() {
      console.log('draw');
      ctx1.drawImage(img, 0, 0, width, height);
    }
  </script>
</body>

现在我们已经成功在页面中绘制了一张图片,这非常简单,让我们继续往下看吧。

缩放

实现图片缩放功能,我们需要了解两个关键的知识点:如何监听缩放事件和如何实现图片缩放。

先来看第一个,我用的是 Mac,在 Mac 上可以通过监听鼠标的滚轮事件来实现缩放的监听。当用户使用鼠标滚轮时,会触发 wheel 事件,我们可以通过这个事件的 deltaY 属性来判断用户是向上滚动(放大)还是向下滚动(缩小)。

可以看到在 wheel 事件中,我们修改了 scale 变量,这个变量会在下面用到。这里添加了对最小缩放是 1,最大缩放是 3 的限制。