【Fabric.js 系列】Fabric.js 是如何实现元素的平移、旋转、缩放的

如何实现元素的平移、旋转、缩放

在上一节中,我们知道了元素是如何渲染到 Canvas 的画布上,这一节我们将了解如何对元素进行平移、旋转、缩放。

如何平移、旋转、缩放元素

在上一节我们知道,元素都继承自 fabric.Object,而 fabric.Object 的 render 方法都由各个元素实现。那么对于元素的平移、旋转、缩放,我们又需要如何抽离出通用的逻辑呢?

不妨思考一下,这个案例

假设要在 (100, 100) 的地方绘制一个 50*50 的矩形,并将其放大 2 倍,之后旋转 45°,该怎么画呢?

正常逻辑是:

  1. 手动算下宽高 100 * 100

  2. 手动算下旋转之后各个顶点的坐标

  3. 连接四个顶点,绘制矩形

也就是我们先手动先计算出各个转化后的坐标,通过坐标绘制出图形。

但在 Canvas 中,要改掉这种绘制的思想,而是要通过并善用变换坐标系来绘制物体

思路如下:

1 绘制一个 50*50 的矩形

2 转化坐标系

代码如下:

js 复制代码
ctx.save(); // 之前提到过了,你要修改 ctx 上的一些配置或者画一个物体,最好先 save 一下,这是个好习惯
ctx.translate(100, 100); // 此时原点已经变到了 (100, 100) 的地方
ctx.scale(2, 2); // 坐标系放大两倍
ctx.rotate(Util.degreesToRadians(45)); // 注意 canvas 中用的都是弧度(弧度 / 2 * Math.PI = 角度 / 360),所以需要简单换算下
ctx.fillRect(-width/2, height/2, width, height); // 绘制矩形的方法固定不变,宽高一般也不会去修改
ctx.restore(); // 画完之后还原 ctx 状态,这是个好习惯

尽量不去改变物体的宽高和大小,而是通过各种变换来达到所需要的效果

矩阵运算

在 Fabric.js 中,并不是通过 translate、scale、rotate 这些方法来实现元素的平移、旋转、缩放,而是通过矩阵运算来实现。

通过 transform api 做矩阵变化,参数 是一个数组,里面有6个元素,默认值是 [1, 0, 0, 1, 0, 0]。

js 复制代码
[0]: 水平缩放(x轴方向)
[1]: 水平倾斜(x轴方向)
[2]: 垂直倾斜(y轴方向)
[3]: 垂直缩放(y轴方向)
[4]: 水平移动(x轴方向)
[5]: 垂直移动(y轴方向

1 修改 viewportTransform[0]、viewportTransform[3] 达到缩放横纵坐标的值

2 修改 viewportTransform[4]、viewportTransform[5] 达到平移画布的效果

对于上面这个例子,我们只需要修改 viewportTransform 的值,然后重新渲染画布就好了。

js 复制代码
const width = 50;
const height = 50;
const angle = (45 / 180) * Math.PI; // Math.PI / 4
ctx.save();
ctx.transform( // 旋转
  2 * Math.cos(angle),
  Math.sin(angle),
  -Math.sin(angle),
  2 * Math.cos(angle),
  100,
  100,
);
ctx.fillRect(-width/2, height/2, width, height); // 绘制矩形的方法固定不变,宽高一般也不会去修改
ctx.restore();

同样的,在 fabric.js 中,在 render 方法中,会调用 transform 方法,将 viewportTransform 的值设置为 transform 的值,以达到对元素进行平移、旋转、缩放的效果。

如何实现漫游

通过监听滚轮事件,然后修改 viewportTransform 的值,以达到对画布进行平移的效果。

js 复制代码
canvas.on("mouse:wheel", function (opt) {
   onsole.log("opt", opt);
   const deltaY = opt.e.deltaY;
   const deltaX = opt.e.deltaX;
   zoom *= 0.999 ** deltaY;
   if (zoom > 20) zoom = 20;
   if (zoom < 0.01) zoom = 0.01;
   const vpt = this.viewportTransform;
   console.log("vpt", vpt);
   vpt[0] = zoom; // 在 X 轴方向上的偏移量。
   vpt[3] = zoom; // 在 Y 轴方向上的偏移量。
   vpt[4] += deltaX; // 俩个点的位置差
   vpt[5] += deltaY; // 俩个点的位置差
   this.requestRenderAll();
   this.setViewportTransform(this.viewportTransform);

   // let zoom = canvas.getZoom();
   // zoom *= 0.999 ** delta;
   // if (zoom > 20) zoom = 20;
   // if (zoom < 0.01) zoom = 0.01;
   // canvas.zoomToPoint({ x: opt.e.offsetX, y: opt.e.offsetY }, zoom);
   opt.e.preventDefault();
   opt.e.stopPropagation();
});

演示效果👇:

演示地址: enson0131.github.io/mini-fabric...

仓库案例

github.com/enson0131/m...

参考文档

相关推荐
老K(郭云开)4 小时前
最新版Edge浏览器集成ActiveX控件之金山WpsDocFrame控件
前端·javascript·chrome·3d·中间件
Anyexyz4 小时前
Windows 11 卸载 Edge
前端·windows·edge
一路向前的月光6 小时前
React(6)
前端·javascript·react.js
众智创新团队6 小时前
singleTaskAndroid的Activity启动模式知识点总结
前端
祁许6 小时前
【Vue】打包vue3+vite项目发布到github page的完整过程
前端·javascript·vue.js·github
我的86呢!6 小时前
uniapp开发h5部署到服务器
前端·javascript·vue.js·uni-app
小爬的老粉丝7 小时前
基于AIOHTTP、Websocket和Vue3一步步实现web部署平台,无延迟控制台输出,接近原生SSH连接
前端
程序员晚天7 小时前
算法中的冒泡排序
前端
~央千澈~7 小时前
大前端之前端开发接口测试工具postman的使用方法-简单get接口请求测试的使用方法-简单教学一看就会-以实际例子来说明-优雅草卓伊凡
前端·测试工具·postman
LBJ辉7 小时前
3. CSS中@scope
前端·css