欸~ 畫布上面物件太多,我想拉近一點看可以嗎?
欸~ 畫布佔版面太大了,我想拉遠一點看可以嗎?
欸~ 我想仔細確認一下上傳的圖看起來對不對,可以往右移嗎?
這 不 是 來 了 嗎 !
實現如同 illustrator 一般的拖拉大法!
實作解析:
// 鼠標滾輪縮放
canvas.on("mouse:wheel", function (opt) {
const delta = opt.e.deltaY;
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();
scaleText.innerText = Math.round(zoom * 100).toString();
});
canvas.on("mouse:wheel", function (opt) { ... });
為畫布添加了一個鼠標滾輪事件監聽器。當用戶滾動鼠標滾輪時,會觸發這個 function。
const delta = opt.e.deltaY;
獲取鼠標滾輪的滾動量。deltaY
是一個數值,向上滾動為負值,向下滾動為正值。
稍後用為增減 zoom 的指標
zoom = canvas.getZoom();
獲取當前畫布的縮放倍率。先取得才知道要改多少馬
zoom *= 0.999 ** delta;
計算新的縮放級別。
這裡使用了指數運算來實現平滑的縮放效果:
這個運算通常用於需要逐漸減少(指數衰減)某個值的情況,例如在動畫中用於計算逐漸減少的速度或透明度或是在物理模擬或動畫效果中。
意思是將 0.999
這個數字提升到 delta
次方。
0.999
:基數(base),這是一個接近於 1 的數字。
**
:指數運算符,用於計算基數的指數次方。
delta
:指數(exponent),這是一個變量,表示基數要提升的次數。
ex:0.999 ** 2
=> 0.999²
0.999 ** 98
=> 0.999⁹⁸
當 delta
為正(向下滾動)時,0.999 ** delta
會小於 1,縮小畫布。
當 delta
為負(向上滾動)時,0.999 ** delta
會大於 1,放大畫布。
簡單說,就是以指數性放大、指數性縮小
if (zoom > 20) zoom = 20;
和 if (zoom < 0.01) zoom = 0.01;
這兩行設置縮放的上限和下限,防止過度縮放或縮小。
canvas.zoomToPoint({ x: opt.e.offsetX, y: opt.e.offsetY }, zoom);
zoomToPoint
方法來執行縮放。這個方法接受兩個參數:
{ x: opt.e.offsetX, y: opt.e.offsetY }
zoom
opt.e.preventDefault();
阻止瀏覽器預設的滾動行為。
opt.e.stopPropagation();
阻止事件冒泡,確保其他元素不會接收到這個滾輪事件。
力求實現了一個平滑的縮放效果,縮放的中心點是鼠標所在的位置,並且設置了縮放的上下限。
使用指數運算 0.999 ** delta
可以讓縮放感覺更自然,而不是線性的縮放。
分為三個部分:
let panning = false;
let lastPosX, lastPosY;
// 鼠標按下開始平移
canvas.on("mouse:down", function (opt) {
const evt = opt.e;
if (evt.altKey === true) {
panning = true; // 設定滑鼠已按下
// 紀錄按下去當下的位置
lastPosX = evt.clientX;
lastPosY = evt.clientY;
canvas.setCursor("grab");
}
});
// 鼠標移動進行平移時
canvas.on("mouse:move", function (opt) {
//如果按下滑鼠,且同時按了 alt 鍵 才會觸發
if (panning && opt.e.altKey) {
const evt = opt.e;
// 把目前的 x,y 位移量同步到畫布上
canvas.viewportTransform[4] += evt.clientX - lastPosX;
canvas.viewportTransform[5] += evt.clientY - lastPosY;
canvas.requestRenderAll();
// 更新當前位置
lastPosX = evt.clientX;
lastPosY = evt.clientY;
}
});
等等,這裡的 canvas.viewportTransform[4]
、canvas.viewportTransform[5]
是什麼??
viewportTransform
是一个数组,里面有6个元素,默认值是[1, 0, 0, 1, 0, 0]
。
从下标0开始,它们分别代表:[0]
: 水平缩放(x轴方向)[1]
: 水平倾斜(x轴方向)[2]
: 垂直倾斜(y轴方向)[3]
: 垂直缩放(y轴方向)[4]
: 水平移动(x轴方向)[5]
: 垂直移动(y轴方向)
其实这涉及到线性代数的知识,在canvas
中,transform()
方法也可以称为“变换矩阵”。我们把
viewportTransform
的6个元素分别用a, b, c, d, e, f
来代替:viewportTransform[a, b, c, d, e, f]
。然后这样排列一下,看上去会不会觉得没那么“凌乱”了。
---from Fabric.js 变换视窗-腾讯云开发者社区-腾讯云 (tencent.com)
(他舉了蠻多例子,想更了解不同數值會造成的影響可以看這邊)
// 鼠標釋放結束平移
canvas.on("mouse:up", function () {
panning = false;
canvas.setCursor("default");
});
設定好結束的狀態,結束這回合的位移。
最後,放上今日的🌰:
fabricjs 畫布縮放與平移