如果我想要每個物件的控制,旁邊都可以有刪除或是複製功能的 icon 可以點擊,並且可以個別操作,該怎麼做呢?
登登,可以使用 fabric.Control
來新增這樣的控制項在物件上!以達成以下的效果
並且,當我們希望所有的物件在生成時都有這樣的控制項,我們可以不要那麼忙的每新增一個物件,就把這屬性加到新的物件上,我們可以直接來修改 prototype!
修改 prototype 的概念可以回顧一下 day4 的物件的擴展與繼承
day4 的物件的擴展與繼承
來上例子:
conat canvas = new fabric.Canvas("canvas");
// 添加刪除控制項
// 在這邊自己命名 新的控制項按鈕名為:deleteControl,並直接把他新增在 fabric.Object.prototype.controls 上
fabric.Object.prototype.controls.deleteControl = new fabric.Control({
x: 0.5,
y: -0.5,
offsetY: -16,
cursorStyle: "pointer",
mouseUpHandler: function (eventData, transform, x, y) {
const target = transform.target;
const canvas = target.canvas;
canvas.remove(target);
canvas.requestRenderAll();
return true;
},
render: function (ctx, left, top, styleOverride, fabricObject) {
const size = this.sizeX || this.sizeY || 12;
ctx.save();
ctx.translate(left, top);
ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
ctx.fillStyle = "red";
ctx.beginPath();
ctx.arc(0, 0, size / 2, 0, 2 * Math.PI);
ctx.fill();
ctx.fillStyle = "white";
ctx.fillRect(-size / 4, -size / 8, size / 2, size / 4);
ctx.restore();
}
});
var circle = new fabric.Circle({
top: 100,
left: 60,
radius: 30,
stroke: "blue",
fill: "transparent"
});
canvas.add(circle);
canvas.setActiveObject(circle);
canvas.renderAll();
這兩種方式在修改 fabric.Object.prototype.controls
時有不同的用途和效果:
fabric.Object.prototype.controls = fabric.util.object.extend({}, fabric.Object.prototype.controls);
這種方式創建了 fabric.Object.prototype.controls
的一個淺拷貝。它的特點是:
- 創建了一個新的對象,這個對象包含了原始 controls
對象的所有屬性。
- 新對象與原始對象是分離的,修改新對象不會直接影響原始對象。
- 適用於當你想要重新定義整個 controls
對象,或者在不影響原始對象的情況下添加多個新控制項,適合大規模的修改或重構。
- 這種方法會保留所有現有的控制項,除非你明確地覆蓋或刪除它們。
- 可能在創建新對象時稍微消耗更多資源。
controls
對象fabric.Object.prototype.controls.deleteControl = new fabric.Control({...});
這種方式直接在原有的 controls
對象上添加或修改特定的控制項。它的特點是:
- 直接修改原始的 controls
對象。
- 只影響你明確指定的控制項(在這個例子中是 deleteControl
)。
- 其他已存在的控制項保持不變,適合小範圍的修改或添加功能。
- 適用於當你只想添加或修改個別控制項,而不想改變整個 controls
對象結構的情況。
- 直接修改,可能略微更高效。
fabric.Control
是 Fabric.js 中用於創建自定義控制項的類。它有許多可以使用的屬性和方法。以下是一些主要的屬性及其用途:
x
, y
,
offsetX
和 offsetY
屬性來進行像素級的微調。offsetX
, offsetY
cursorStyle
actionHandler
mouseDownHandler
, mouseUpHandler
可以用於實現更複雜的交互。
mouseDownHandler
:
-(function) 鼠標按下控制項時執行的函數。
mouseUpHandler
:
render
cornerSize
sizeX
和 sizeY
touchSizeX
, touchSizeY
visible
actionName
:(string) 與控制項相關聯的動作名稱。用於識別控制項的作用,便於事件處理。使用這些屬性,你可以創建功能豐富、外觀獨特的自定義控制項。
x
, y
)。actionHandler
, mouseDownHandler
等)。render
)。sizeX
, sizeY
, touchSizeX
, touchSizeY
)。visible
)。這些屬性和方法提供了極大的靈活性,使你能夠創建適合特定需求的自定義控制項。
render
函數function renderGreanIcon(ctx, left, top, styleOverride, fabricObject) {
const size = this.sizeX || this.sizeY || 12;
//設置控制項的大小。如果 `this.sizeX` 或 `this.sizeY` 被定義,就使用它們;否則默認為 12。
ctx.save(); //保存當前的繪圖上下文狀態,這樣後面的變換不會影響到其他繪圖操作。
ctx.translate(left, top); //將繪圖原點移動到控制項的位置
// 根據對象的旋轉角度旋轉繪圖上下文,確保控制項的方向與對象一致。
ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
// 繪製一個綠色的圓形作為控制項的背景
ctx.fillStyle = "green";
ctx.beginPath();
ctx.arc(0, 0, size / 2, 0, 2 * Math.PI);
ctx.fill();
// 在綠色圓形上繪製一個白色的小正方形
ctx.fillStyle = "white";
ctx.fillRect(-size / 4, -size / 4, size / 2, size / 2);
ctx.restore(); //恢復之前保存的繪圖上下文狀態,清除所有的變換。
}
import DelateIcon from '@/public/images/delete.js'; // 我之前是出來的方式是引用 js 檔裡的 svg 作為圖片來源
// --- 物件控制選項的圖片渲染 ---
const renderDeleteIcon = (ctx, left, top) => {
const imgDelete = new Image();
imgDelete.src = DelateIcon;
const size = 24;
ctx.save();
ctx.translate(left, top);
ctx.drawImage(imgDelete, -size / 2, -size / 2, size, size);
ctx.restore();
};
const onDelete = function (eventData, transform) { const canvas = transform.target.canvas; canvas.remove(canvas.getActiveObject()); canvas.renderAll(); };
fabric.Object.prototype.controls.clone = new fabric.Control({
x: -0.5,
y: -0.5,
// ... 其餘設定
mouseUpHandler: onDelete, // 這樣把 function 內容抽出來在外面定義也可以喔
render:renderDeleteIcon
})