目标:在nextjs中实现一个图片编辑器
首先需要适配下nextjs,写一个BaseCavans组件:
import * as fabric from "fabric";
import React, { useEffect, useRef } from "react";
const DEV_MODE = process.env.NODE_ENV === "development";
declare global {
var canvas: fabric.Canvas | undefined;
}
const BaseCanvas = React.forwardRef<
fabric.Canvas,
{ onLoad?(canvas: fabric.Canvas): void }
>(({ onLoad }, ref) => {
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => {
if (!canvasRef.current) {
return;
}
const canvas = new fabric.Canvas(canvasRef.current);
Object.assign(fabric.FabricObject.ownDefaults, {
cornerColor: "#fff",
cornerStyle: "circle",
borderColor: "#8142f6",
borderScaleFactor: 2,
transparentCorners: false,
cornerStrokeColor: "#8142f6",
cornerSize: 8,
padding: 6,
});
DEV_MODE && (window.canvas = canvas);
if (typeof ref === "function") {
ref(canvas);
} else if (typeof ref === "object" && ref) {
ref.current = canvas;
}
onLoad?.(canvas);
return () => {
DEV_MODE && delete window.canvas;
if (typeof ref === "function") {
ref(null);
} else if (typeof ref === "object" && ref) {
ref.current = null;
}
canvas.dispose();
};
}, [canvasRef, onLoad]);
return <canvas ref={canvasRef} />;
});
export default BaseCanvas;
BaseCanvas.displayName = "BaseCanvas";
然后在引入初始化cavans:
const onLoad = useCallback(
(canvas: fabric.Canvas) => {
canvas.setDimensions({
width: 378,
height: 504,
});
// 可添加一些初始化的元素,比如img 、text等
// 添加背景图
// Set the clipPath on the image instance
//imgInstance.clipPath = clipPath;
//canvas.add(imgInstance);
//canvas.sendObjectToBack(imgInstance);
setCanvas(canvas);
},
[ref]
);
<BaseCanvas ref={ref} onLoad={onLoad} />
比较常见的Fabric api说明:
const textbox = new fabric.Textbox('Hello World', {
left: 100,
top: 100,
width: 200,
fontSize: 20,
fontFamily: 'Arial',
fill: '#000000'
});
canvas.add(textbox);
// 2. 创建图片
fabric.Image.fromURL('image.jpg', (img) => {
img.set({
left: 100,
top: 100,
scaleX: 0.5,
scaleY: 0.5
});
canvas.add(img);
});
// 3. 创建形状
const rect = new fabric.Rect({
left: 100,
top: 100,
width: 100,
height: 100,
fill: 'red'
});
canvas.add(rect);
// 4. 添加阴影效果
object.set('shadow', new fabric.Shadow({
color: 'rgba(0,0,0,0.3)',
blur: 10,
offsetX: 5,
offsetY: 5
}));
// 5. 批量修改选中对象
const activeObjects = canvas.getActiveObjects();
activeObjects.forEach(obj => {
obj.set('fill', 'red');
});
canvas.requestRenderAll();
遇到的一些问题:
- Fabric官方文档以html版本说明并不适配nextjs
- Fabric版本更新,文档还未更新
- 在特殊情况下(比如Modal )文本输入框会失去焦点,输入不了
解决方法:
- 可以根据AI工具实现功能,但是也可能生成api错误,这个时候就需要看看源码fabric的属性了
- 如果还是找不到,还可以直接去搜搜github.com/fabricjs/fa… 生成input框引发的样式问题(定位不准等)导致,只需要加上textbox.hiddenTextareaContainer = canvas.lowerCanvasEl.parentNode;告诉 Fabric.js 将隐藏的 textarea 放在画布的父元素中
Appendix
github.com/fabricjs/fa…
github.com/fabricjs/fa…
github.com/fabricjs/fa…