一、案例
和 react 结合的使用案例:https://github.com/saninmersion/react-context-fabricjs
二、常见功能用法
以下代码都将采用 useContext 管理 canvas
调整 canvas 画板背景颜色
export const Menu: FC = () => {
const { canvas } = useContext(FabricContext);
const handelSetBackgroundColor = useCallback(
(color: string) => {
if (canvas) {
canvas.backgroundColor = color;
canvas.renderAll();
}
},
[canvas]
);
return <Button onClick={()=> handelChangeBackgroundColor("#f9f9f9")}>调整背景颜色</Button>
}
实现遮罩功能
遮罩效果:
超出虚线部分的图片或内容是不显示的。遮罩的实现是借助裁剪功能实现,相关文档:http://fabricjs.com/clippath-part3 。
添加图片时指定一个正方形的裁剪区,图片就只能在该区域内展示。
const clipPath = new fabric.Rect({
top: 150,
left: 200,
hasControls: false,
height: 300,
fill: "transparent",
width: 200,
absolutePositioned: true,
});
fabric.Image.fromURL(url, (image)=> {
image.clipPath = clipPath;
canvas.add(image);
});
从上面代码可以看到正方形的裁剪区并没有添加到 canvas 进行渲染,所以不会有 border 样式,因此还要添加一个大小、位置相同的带边框的正方形。
const strokeWidth = 2;
const clipBorder = new fabric.Rect({
top: 150 + strokeWidth,
left: 200 + strokeWidth,
width: 200 - strokeWidth * 2,
height: 300 - strokeWidth * 2,
fill: "transparent",
stroke: "#cccccc",
strokeWidth,
strokeDashArray: [6, 6], // 数值越大,虚线越稀疏
absolutePositioned: true,
selectable: false,
hoverCursor: "default",
});
canvas.add(clipBorder);
另外一种方式是将裁剪区和裁剪区边框封为一个图案组渲染到 canvas 上。
首先定义方形遮罩类:
class ClipRect extends fabric.Group {
private _clipPath: fabric.Rect;
constructor(options: fabric.IRectOptions = {}) {
const strokeWidth = 2;
// 方形遮罩
const clipPath = new fabric.Rect({
...(options ? options : {}),
fill: "transparent",
absolutePositioned: true,
selectable: false,
});
// 遮罩边框
const clipBorder = new fabric.Rect({
...options,
top: (options.top || 0) + strokeWidth,
left: (options.left || 0) + strokeWidth,
width: (options.width || 0) - strokeWidth * 2,
height: (options.height || 0) - strokeWidth * 2,
fill: "transparent",
stroke: "#cccccc",
strokeWidth,
strokeDashArray: [6, 6],
rx: 4,
ry: 4,
absolutePositioned: true,
selectable: false,
});
super([clipBorder, clipPath], pick(options, ["selectable"]));
this._clipPath = clipPath;
}
// 向外暴漏一个拿到遮罩的方法
getClipPath() {
return this._clipPath;
}
}
初始化时添加到 canvas
const clipRect = new ClipRect({
top: 185,
left: 200,
width: 200,
height: 200,
originX: "center",
originY: "center",
});
canvase.add(clipRect);
添加新图片时将图片的裁剪区设置为之前暴漏的那个方形遮罩
const handleAddImage = useCallback(async () => {
if (!canvas) {
return;
}
const image = await Image.fromURLAsync("<http://fabricjs.com/lib/pug.jpg>", {
clipPath: (
canvas.getObjects().find((item) => item instanceof ClipRect) as ClipRect
)?.getClipPath(),
});
canvas.add(image);
}, [canvas]);
使添加的图片具有原物品的纹路
一件衣服的产品图片分为多图层,将一个带有衣服褶皱纹路的透明图片置于用户添加的图片之上时,用户添加的图片上也会有褶皱效果。将褶皱层图片置于最顶部图层方法:
canvas.setOverlayImage(frontImage); // frontImage 始终置于最顶层,不受新添加的图案影响
canvas.bringToFront(frontImage); // 好像不生效!
添加仅在遮罩范围内显示的文字
同理添加文字时设置裁剪区即可
清除
使用 clear 将清除所有图案。
const handelReset = useCallback(() => {
if (canvas) {
canvas.clear();
// 重绘初始画面
}
}, [canvas]);
保存为 JSON 数据
const handleToJSON = useCallback(
async (event) => {
if (!canvas) {
return;
}
console.log(canvas.toJSON());
},
[canvas]
);
关于 回退/前进
例子: https://github.com/abhi06991/Undo-Redo-Fabricjs
使用 localStorage 存储记录例子 https://github.com/paulcredmond/fabric-undoredo
关于 “回退 / 前进” 的讨论:https://github.com/fabricjs/fabric.js/issues/23