业务中涉及图片的制作和审核功能,审核人员需要在图片中进行标注,并说明存在的问题,标注过程中需要支持放大缩小,移动等交互,将业务剥离,这个需求,可以定义为实现一个图片标注功能。
实现这个功能并不容易,其涉及的前端知识点众多,本文带领大家从零到一,亲手实现一个,支持缩放,移动,编辑的图片标注功能,文字描述是抽象的,眼见为实,实现效果如下所示:
这里涉及两个关键功能,一个是绘制,包括缩放和旋转,一个是编辑,包括选取和修改尺寸,涉及到的技术包括,缩放,移动,和自定义形状的绘制(本文仅实现矩形),绘制形状的选取,改变尺寸和旋转角度等。
从大的技术选型来说,有两种实现思路,一种是 canvas,一种是 dom+svg,下面简单介绍下两种思路和优缺点。
canvas 可以方便实现绘制功能,但编辑功能就比较困难,当然这可以使用库来实现,这里我们考虑自己亲手实现功能。
- 优点:
- 性能较好,尤其是在处理大型图片和复杂图形时。
- 支持更复杂的图形绘制和像素级操作。
- 一旦图形绘制在 Canvas 上,就不会受到 DOM 的影响,减少重绘和回流。
- 缺点:
- 交互相对复杂,需要手动管理图形的状态和事件。
- 对辅助技术(如屏幕阅读器)支持较差。
- 可能遇到的困难:
- 实现复杂的交互逻辑(如选取、移动、修改尺寸等)可能比较繁琐。
- 在缩放和平移时,需要手动管理坐标变换和图形重绘。
dom+svg 也可以实现功能,缩放和旋转可以借助 css3 的 transform。
- 优点:
- 交互相对简单,可以利用 DOM 事件系统和 CSS。
- 对辅助技术支持较好,有助于提高可访问性。
- 缺点:
- 在处理大型图片和复杂图形时,性能可能不如 Canvas。
- SVG 元素数量过多时,可能会影响页面性能。
- 可能遇到的困难:
- 在实现复杂的图形和效果时,可能需要较多的 SVG 知识和技巧。
- 管理大量的 SVG 元素和事件可能会使代码变得复杂。
总的来说,如果对性能有较高要求,或需要进行复杂的图形处理和像素操作,可以选择基于 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 的限制。