大家好,我是前端西瓜哥。今天我们来谈谈图形编辑器中,简单说说图形编辑实现图形工具,需要用到的填充算法。
图形的特点是宽高是固定的,在图形编辑器绘制图片有两种方案。
一种是将 宽高比锁死,不允许改变,这样我们就不用考虑容器矩形的宽高和图片宽高不一致的处理逻辑。
开源的 Excaildraw 白板工具使用了该方案,见下图:
另一种就可以自由地调整矩形宽高,但相应地要设置图片的填充策略。
填充策略有很多,我从 CSS 属性 object-fit 的可取值来描述一些策略:
- cover:图片尽可能覆盖容器不能留白,会丢掉一些内容,是最常用的策略;
- contain:图片要刚好完整显示,会留白;
- …
这些策略我之前写过一篇文章,这篇:
《在容器内显示图片的五种方案:contain、cover、fill、none、scale-down》
本文就不再一一讲解这些方案了,会挑其中常见的 cover 策略是如何渲染图片,我们要实现的效果如下:
效果就是,使用 cover 策略,不留白,且图片要居中。
我们用到 CanvasRenderingContext2D.drawImage()
方法。
drawImage 有多种写法,这里我用最长的那个:
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
就是将图片抠一个矩形区域(sx, sy, sWidth, sHeight)出来,再缩放到画布的特定区域(dx, dy, dWidth, dHeight)。
先计算图片能够 cover 容器,需要乘以的 scale 值。
function calcCoverScale(w: number, h: number, cw: number, ch: number) {
if (w === 0 || h === 0) return 1;
const scaleW = cw / w;
const scaleH = ch / h;
const scale = Math.max(scaleW, scaleH);
return scale;
}
// 计算
const scale = calcCoverScale(image.width, image.height, width, height);
这里的 width 和 height 表示容器宽高。
让 width 除以 scale,让容器宽高可以对上图片(边界有重合)。
计算裁切矩形的左上角位置。
const sx = image.width / 2 - width / scale / 2;
const sy = image.height / 2 - height / scale / 2;
接着就是裁切矩形的宽高。看图,宽是 width / scale,高也同理,是 height / scale。
最后就是绘制:
ctx.drawImage(image, sx, sy, width / scale, height / scale, x, y, width, height);
项目地址,欢迎 star:
https://github.com/F-star/suika
线上体验:
https://blog.fstars.wang/app/suika/
结尾
当然宽高不固定的实现,不仅有 cover,你还可以其他策略,原理在前文中提及的文章有说明。
我是前端西瓜哥,欢迎关注我,学习更多前端知识。