遇到问题
- google 看能否找到解决方案
- gpt 问
- 在 github issues 根据对应关键字找
- 在 github 项目里面找,别人实现的项目,看是否有相似功能
踩坑
-
加视频的时候,元素框添加成功,对应视频却加载不出来
原因: 由于使用的是 西瓜视频 xgplayer,没有设置宽高导致渲染不出来
找到对应的 issues github.com/fabricjs/fa…
添加视频示例:fabricjs.com/video-eleme…
const addVideo = (w: number, h: number) => {
if (!canvasRef.current) return;
let canvas = canvasRef.current;
// 下面需要设置宽高,不然视频渲染不出来
const videoElement = document.querySelector("video") as HTMLVideoElement;
videoElement.width = w; // 设置宽度
videoElement.height = h; // 设置高度
const video1 = new fabric.Image(videoElement, {
left: 0,
top: 0,
objectCaching: false,
width: w,
height: h,
});
canvas?.add(video1);
// 设置层级
canvas.moveTo(video1, 0);
video1.getElement?.().play();
fabric.util.requestAnimFrame(function render() {
canvas.renderAll();
fabric.util.requestAnimFrame(render);
});
};
其他工具函数
/**
* 根据 ID 在 Fabric.js 画布中查找元素。
*
* @param {fabric.Canvas} canvas - Fabric.js 画布对象。
* @param {string} id - 要查找的元素的 ID。
* @returns {fabric.Object | undefined} - 返回找到的元素,如果找不到则返回 undefined。
*/
export const findFabricElementById = (canvas: fabric.Canvas, id: string) => {
return canvas
?.getObjects()
?.find((fabricElement: any) => fabricElement?.id === id);
};
/**
* 从画布上移除指定元素,并执行回调函数。
*
* @param {fabric.Canvas} canvas - Fabric.js 画布对象。
* @param {string} elementId - 要移除元素的 ID。
* @param {() => void} [onRemoved] - 移除元素后执行的回调函数。
*/
export const removeFabricElementById = (
canvas: fabric.Canvas,
elementId: string,
onRemoved?: () => void,
) => {
if (!canvas) return;
let element = findFabricElementById(canvas, elementId);
if (element) {
canvas.remove(element);
onRemoved && onRemoved();
}
};
/**
* 更新指定 ID 的 Fabric 元素
* @param canvas - Fabric.js 画布实例,代表整个绘图区域
* @param elementId - 要更新的元素的唯一标识符
* @param onUpdate - 可选参数,一个回调函数,将在元素更新后执行
*/
export const updateFabricElementById = (
canvas: fabric.Canvas,
elementId: string,
onUpdate?: (element: fabric.Object) => void,
) => {
if (!canvas) return;
// 通过元素 ID 查找要更新的元素
let element = findFabricElementById(canvas, elementId);
if (element) {
// 如果提供了 onUpdate 回调函数,调用它并传递更新后的元素
onUpdate && onUpdate(element);
// 重新渲染整个画布
canvas?.renderAll();
}
};
/**
* 控制画布上所有对象的可见性。
*
* @param {fabric.Canvas} canvas - Fabric.js 画布对象。
* @param {boolean} isVisible - 如果为 `true`,则将所有对象设置为可见;如果为 `false`,则将所有对象设置为隐藏。
*/
export const controlAllObjectsVisibility = (
canvas: fabric.Canvas,
isVisible: boolean,
) => {
const objects = canvas.getObjects();
objects.forEach((object: fabric.Object) => {
object.set("visible", isVisible);
});
};
/**
* 获取指定区域的 Textbox 元素的 Base64 图片。
*
* @param {fabric.Canvas} canvas - Fabric.js 画布对象。
* @param {number} width - 指定区域的宽度。
* @param {number} height - 指定区域的高度。
* @param {number} x - 指定区域的左上角 x 坐标。
* @param {number} y - 指定区域的左上角 y 坐标。
* @returns {string} - Base64 图片字符串。
*/
export const getAreaTextBoxesBase64 = (
canvas?: fabric.Canvas,
// @ts-ignore
width: number,
height: number,
x: number,
y: number,
) => {
if (!canvas) return "";
// 隐藏除 Textbox 外的其他元素
let objects = canvas.getObjects();
objects.forEach((object: fabric.Object) => {
if (!(object instanceof fabric.Textbox)) {
object.set("visible", false);
}
});
// 设置画布的裁剪区域
// @ts-ignoreƒ
canvas?.set({
clipTo: (ctx: CanvasRenderingContext2D) => {
ctx.rect(x, y, width, height);
},
});
// 获取指定区域的 Base64 图片
let canvasBase64 = canvas.toDataURL({
format: "png", // 指定输出格式
width: width,
height: height,
left: x, // 左上角 x 坐标
top: y, // 左上角 y 坐标
});
controlAllObjectsVisibility(canvas, true);
// 渲染画布
canvas.renderAll();
return canvasBase64 || "";
};