fabric-texture
Version:
This JavaScript library enables fast and efficient image distortion transformations using Canvas 2D.
491 lines (490 loc) • 16 kB
TypeScript
import type { Bezier } from 'bezier-js';
import { fabric } from 'fabric';
import { Texture, TransformData } from './texture.class';
import type { AbstractMode } from './abstract-mode.class';
/**
* FabricTexture 实例的配置选项
*
* 定义初始化 FabricTexture 实例时的配置选项,包括:
* - 历史记录功能的开关
* - 历史记录变化的事件监听
*
* @example
* ```typescript
* const fabricTexture = new FabricTexture(canvas, {
* // 启用变形历史记录
* history: true,
*
* // 监听历史记录变化
* onHistoryChange: ({ undo, redo }) => {
* // 根据历史记录状态更新 UI
* }
* });
* ```
*/
type FabricTextureOptions = {
/**
* 是否启用变形操作的历史记录
*
* 启用后,实例将维护一个变形状态的撤销/重做栈,
* 使用户可以撤销或重做他们的变形操作。
*
* @default false
*
* @remarks 启用历史记录会消耗额外的内存来存储过程变形数据。
*/
history: boolean;
/**
* 历史记录变化时的回调函数
*
* @param records 当前的历史记录状态
* @param records.undo 可撤销的变形记录数组
* @param records.redo 可重做的变形记录数组
*
* @remarks undo 数组的第一项始终是初始状态
*/
onHistoryChange: (records: {
undo: TransformData[];
redo: TransformData[];
}) => void;
};
/**
* 贴图渲染选项
*/
type RenderOptions = {
/**
* 是否跳过记录此次渲染的变形状态
*
* 设为 true 时,本次渲染不会被添加到撤销栈中。
* 常用于以下场景:
* - 临时预览渲染
* - 恢复历史状态时的渲染
* - 重置变形时的渲染
*
* @default false
*/
withoutRecord: boolean;
};
/**
* Fabric.js 贴图变形工具类
*
* 提供基于 Fabric.js 的图像变形功能,支持:
* - 网格化变形:将图像划分为可调整的网格区域
* - 交互式编辑:支持鼠标拖拽调整变形效果
* - 实时预览:变形效果实时渲染
* - 历史记录:支持撤销/重做操作
* - 性能优化:自动处理大尺寸图像,优化渲染性能
*
* @example
* ```typescript
* // 1. 创建 Fabric.js 画布
* const canvas = new fabric.Canvas('canvas');
*
* // 2. 初始化贴图工具
* const fabricTexture = new FabricTexture(canvas, {
* history: true, // 启用历史记录
* });
*
* // 3. 准备需要变形的 fabric 元素对象,不限于图像元素
* const image = new fabric.Image(imageElement);
* canvas.add(image);
*
* // 4. 进入编辑模式
* fabricTexture.enterEditing(image, null, new GridMode());
*
* // 5. 完成编辑后退出
* fabricTexture.leaveEditing();
* ```
*
* @remarks 使用前请确保已正确安装并引入 fabric.js
*
* @see AbstractMode 查看如何自定义变形模式
* @see Texture 了解底层变形实现
*/
export declare class FabricTexture {
/**
* Fabric.js 画布实例 用于渲染和管理变形操作的画布对象
*/
canvas: fabric.Canvas;
/**
* 实例配置选项 包含历史记录开关和变化监听器等配置
*/
options: FabricTextureOptions;
/**
* 当前激活的变形模式 控制图像变形的交互方式和效果
* @default null
*/
mode: AbstractMode | null;
/**
* 核心变形引擎实例 负责处理底层的图像变形计算
* @default null
*/
texture: Texture | null;
/**
* 当前正在编辑的 Fabric 对象 可以是任何 Fabric.js 支持的对象类型(图片、路径等)
* @default null
*/
target: fabric.Object | null;
/**
* 目标对象的画布表示 存储目标对象的原始图像数据
* @default null
*/
targetCanvas: HTMLCanvasElement | null;
/**
* 贴图的边界范围 记录变形区域的边界坐标,用于计算位置偏移
* @property {number} left - 左边界坐标
* @property {number} right - 右边界坐标
* @property {number} top - 上边界坐标
* @property {number} bottom - 下边界坐标
*/
textureBoundary?: {
left: number;
right: number;
top: number;
bottom: number;
};
/**
* 贴图在水平方向的缩放比例 用于保持变形后的图像与原始尺寸的比例关系
* @default 1
*/
textureScaleX: number;
/**
* 贴图在垂直方向的缩放比例 用于保持变形后的图像与原始尺寸的比例关系
* @default 1
*/
textureScaleY: number;
/**
* 变形后的贴图对象 在画布上显示的实际图像对象
*/
textureObject?: fabric.Image;
/**
* 网格路径元素列表 存储所有网格线的 Fabric.Path 对象
* @remarks 用于显示变形网格和处理交互
*/
paths?: fabric.Path[];
/**
* 贝塞尔曲线到路径对象的映射 用于快速查找曲线对应的路径对象
* @remarks 使用 WeakMap 避免内存泄漏
*/
curvePathMap: WeakMap<Bezier, fabric.Path>;
/**
* 路径对象到贝塞尔曲线的映射 用于快速查找路径对应的曲线对象
* @remarks 使用 WeakMap 避免内存泄漏
*/
pathCurveMap: WeakMap<fabric.Path, Bezier>;
/**
* 变形操作的历史记录 存储变形操作的撤销/重做状态
* @property {TransformData[]} undo - 可撤销的操作记录
* @property {TransformData[]} redo - 可重做的操作记录
*/
records: {
undo: Omit<TransformData, 'compressedCoordinates'>[];
redo: Omit<TransformData, 'compressedCoordinates'>[];
};
/**
* 普通渲染的清理回调函数
* 存储渲染过程中创建的交互元素的清理函数。
* 在下次渲染前或离开编辑态时会被调用,可用于清理上一次渲染的交互元素。
*
* @private
* @type {(() => void) | void}
*/
private _renderReturnCallback?;
/**
* 脏渲染的清理回调函数
* 存储脏渲染(结构发生变化,比如添加或删除了区域分割点)时创建的交互元素的清理函数。
* 在下次脏渲染前或离开编辑态时会被调用,可用于清理上一次渲染的交互元素。
*
* @private
* @type {(() => void) | void}
*/
private _dirtyRenderReturnCallback?;
/**
* 下一帧渲染的请求标识
* 存储 requestAnimationFrame 返回的标识符。
* 用于在需要时取消已计划但尚未执行的渲染操作,
* 避免不必要的渲染和性能浪费。
*
* @private
* @type {number | undefined}
*/
private _nextFrameRender;
/**
* 创建 FabricTexture 实例
*
* 初始化一个贴图变形工具实例。该实例将与指定的 Fabric.js 画布关联,
* 用于处理画布上的图像变形操作。
*
* @param canvas - Fabric.js 画布实例
* @param [options] - 配置选项
* @param [options.history=false] - 是否启用操作历史记录
* @param [options.onHistoryChange] - 历史记录变化时的回调函数
*
* @example
* ```typescript
* const canvas = new fabric.Canvas('canvas');
* const texture = new FabricTexture(canvas);
* ```
*
* @remarks
* 1. 创建实例后,需要调用 enterEditing 方法才能开始编辑
* 2. 启用历史记录会消耗额外的内存,请根据实际需求选择是否启用
*/
constructor(canvas: fabric.Canvas, options?: Partial<FabricTextureOptions>);
/**
* 渲染贴图变形效果
*
* 将当前的变形状态渲染到画布上。
*
* @param [dirty=true] - 是否为脏渲染,脏渲染会导致 _dirtyRenderReturnCallback 回调执行
* @param [options] - 渲染配置选项
* @param [options.withoutRecord=false] - 是否跳过记录此次渲染的变形状态
*
* @example
* ```typescript
* // 普通渲染(仅网格分割点位置变化)
* fabricTexture.render(false);
*
* // 脏渲染(网格结构发生变化,如添加或删除了分割点)
* fabricTexture.render(true);
*
* // 临时预览渲染(不记录历史)
* fabricTexture.render(true, { withoutRecord: true });
* ```
*
* @remarks
* 1. 脏渲染会重建整个网格结构,性能消耗较大
* 2. 非脏渲染仅更新现有网格的控制点位置,性能消耗较小
* 3. 如果不需要记录历史,建议设置 withoutRecord 为 true
*
* @see requestRender 性能优化版本的渲染方法
*/
render(dirty?: boolean, options?: Partial<RenderOptions>): void;
/**
* 在下一帧渲染贴图变形效果(性能优化版本)
*
* 使用 requestAnimationFrame 延迟渲染到下一帧,可以:
* 1. 避免短时间内的重复渲染
* 2. 优化连续变形时的性能
* 3. 保持画面流畅度
*
* @param [dirty=true] - 是否为脏渲染,脏渲染会导致 _dirtyRenderReturnCallback 回调执行
* @param [callback] - 渲染完成后的回调函数
* @param [options] - 渲染配置选项
* @param [options.withoutRecord=false] - 是否跳过记录此次渲染的变形状态
*
* @example
* ```typescript
* // 基础用法
* fabricTexture.requestRender();
*
* // 带回调的用法
* fabricTexture.requestRender(true, () => {
* console.log('渲染完成');
* });
*
* // 连续变形时的优化用法
* function onDragging() {
* fabricTexture.requestRender(false, null, {
* withoutRecord: true // 拖拽过程中不记录历史
* });
* }
*
* function onDragEnd() {
* fabricTexture.render(true); // 拖拽结束时记录一次历史
* }
* ```
*
* @remarks
* 1. 此方法会自动取消上一次尚未执行的渲染请求
* 2. 适合用于处理连续的变形操作,如拖拽控制点
* 3. 对于关键状态的保存,建议使用同步的 render 方法
*
* @see render 同步渲染方法
*/
requestRender(dirty?: boolean, callback?: () => void, options?: Partial<RenderOptions>): void;
/**
* 提取当前变形状态的数据
*
* 获取当前图像的变形状态数据。
*
* @returns
* - 如果当前不在编辑状态,返回 null
* - 否则返回包含以下属性的对象:
* - data: 原始变形数据
* - compressedData: 压缩后的字符串形式数据
*/
serialize(): {
data: TransformData;
compressedData: string;
} | null;
/**
* 进入图像编辑模式
*
* 使指定的 Fabric 对象进入变形编辑状态。
*
* @param object - 要编辑的 Fabric 对象(如图片、路径等)
* @param [sourceCanvas] - 可选的源画布,用于特殊渲染需求。如果为 null,将使用 object 生成的画布
* @param mode - 变形模式实例,决定了变形的交互方式和效果
* @param [beforeFirstRender] - 首次渲染前的回调函数,可用于初始化变形引擎的配置
*
* @example
* ```typescript
* fabricTexture.enterEditing(
* image,
* null,
* new GridMode(),
* (texture) => {
* // 设置显示分割网格线
* texture.setRenderOptions({ showGrid: true });
* }
* );
* ```
*
* @see leaveEditing 退出编辑模式
*/
enterEditing(object: fabric.Object, sourceCanvas: HTMLCanvasElement | null, mode: AbstractMode, beforeFirstRender?: (texture: Texture) => void): void;
/**
* 退出图像编辑模式
*
* 结束当前对象的变形编辑状态。
*
* @example
* ```typescript
* // 完成编辑后退出
* fabricTexture.leaveEditing();
*
* // 典型的编辑流程
* try {
* // 1. 进入编辑模式
* fabricTexture.enterEditing(image, null, new GridMode());
*
* // 2. 进行编辑操作...
*
* // 3. 保存编辑结果
* const result = fabricTexture.serialize();
*
* // 4. 退出编辑模式
* fabricTexture.leaveEditing();
* } catch (error) {
* console.error('编辑过程出错:', error);
* fabricTexture.leaveEditing(); // 确保清理资源
* }
* ```
*
* @see enterEditing 进入编辑模式
*/
leaveEditing(): void;
/**
* 记录当前变形状态
*
* 将当前的变形状态保存到历史记录中。
*
* @remarks
* 1. 仅在启用了历史记录功能时生效(options.history = true)
* 2. 每次记录都会创建状态的深拷贝,注意内存占用
*
* @see undo 撤销操作
* @see redo 重做操作
*/
record(): void;
/**
* 撤销上一步变形操作
*
* 将变形状态回退到上一个记录点。
*
* @example
* ```typescript
* // 基础用法
* fabricTexture.undo();
*
* // 配合快捷键使用
* document.addEventListener('keydown', (e) => {
* if (e.ctrlKey && e.key === 'z') {
* fabricTexture.undo();
* }
* });
* ```
*
* @remarks
* 1. 如果撤销栈为空或只有初始状态,此操作无效
* 2. 撤销操作本身不会产生新的历史记录
*
* @see redo 重做已撤销的操作
*/
undo(): void;
/**
* 重做已撤销的变形操作
*
* 重新应用之前撤销的变形状态。
*
* @example
* ```typescript
* // 基础用法
* fabricTexture.redo();
*
* // 配合快捷键使用
* document.addEventListener('keydown', (e) => {
* if (e.ctrlKey && e.key === 'y') {
* fabricTexture.redo();
* }
* });
* ```
*
* @remarks
* 1. 如果重做栈为空,此操作无效
* 2. 重做操作本身不会产生新的历史记录
* 3. 执行新的变形操作会清空重做栈
*
* @see undo 撤销操作
*/
redo(): void;
/**
* 重置变形状态
*
* 将图像重置到指定状态:
* - 当 keepHistory=true 时:清除所有变形效果,但保留操作记录
* - 当 keepHistory=false 时:回退到初始状态,并将后续状态移入重做栈
*
* @param keepHistory - 是否保留历史记录
* - true: 清除变形但保留历史,可用于临时预览原始状态
* - false: 回退到初始状态,后续状态可通过重做恢复
*
* @example
* ```typescript
* // 1. 清除变形但保留历史记录
* fabricTexture.reset(true);
*
* // 2. 回退到初始状态,保留重做可能
* fabricTexture.reset(false);
*
* // 3. 配合撤销/重做使用
* fabricTexture.reset(false);
* if (fabricTexture.canRedo()) {
* // 可以通过 redo() 恢复之前的状态
* fabricTexture.redo();
* }
* ```
*
* @remarks
* 1. keepHistory=true 时:
* - 生成新的历史记录
* - 清空重做栈
* - 适合用于临时预览或确定放弃变形
*
* 2. keepHistory=false 时:
* - 不生成新的历史记录
* - 保留重做可能性
* - 适合用于需要保留恢复可能的场景
*
* 3. 在以下情况下方法无效:
* - 当前不在编辑状态(texture 为 null)
* - 当前已经是初始状态(keepHistory=true 时)
*
* @see undo 单步撤销操作
* @see redo 重做已撤销的操作
* @see serialize 保存当前变形状态
*/
reset(keepHistory?: boolean): void;
}
export {};