合并画布代码
This commit is contained in:
@@ -577,6 +577,49 @@ export class TexturePresetManager {
|
||||
cacheSize: this.textureCache.size,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证纹理文件
|
||||
* @param {File} file 要验证的文件
|
||||
* @returns {Boolean} 是否为有效的纹理文件
|
||||
*/
|
||||
validateTextureFile(file) {
|
||||
if (!file) {
|
||||
console.warn("文件不存在");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查文件类型
|
||||
if (!file.type.startsWith("image/")) {
|
||||
console.warn("文件类型无效,必须是图片文件");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查文件大小(限制为 10MB)
|
||||
const maxSize = 10 * 1024 * 1024; // 10MB
|
||||
if (file.size > maxSize) {
|
||||
console.warn("文件大小超过限制(10MB)");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查支持的图片格式
|
||||
const supportedTypes = [
|
||||
"image/jpeg",
|
||||
"image/jpg",
|
||||
"image/png",
|
||||
"image/webp",
|
||||
"image/svg+xml",
|
||||
"image/bmp",
|
||||
"image/gif",
|
||||
];
|
||||
|
||||
if (!supportedTypes.includes(file.type)) {
|
||||
console.warn("不支持的图片格式");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 创建单例实例
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//import { fabric } from "fabric-with-all";
|
||||
import { fabric } from "fabric-with-all";
|
||||
import "./fabric.brushes.js";
|
||||
import { BrushStore } from "../../store/BrushStore";
|
||||
import { brushRegistry } from "./BrushRegistry";
|
||||
|
||||
@@ -16,7 +17,7 @@ import { MarkerBrush } from "./types/MarkerBrush";
|
||||
import { CustomPenBrush } from "./types/CustomPenBrush";
|
||||
import { RibbonBrush } from "./types/RibbonBrush";
|
||||
import { ShadedBrush } from "./types/ShadedBrush";
|
||||
import { SketchyBrush } from "./types/SketchyBrush";
|
||||
// import { SketchyBrush } from "./types/SketchyBrush";
|
||||
import { SpraypaintBrush } from "./types/SpraypaintBrush";
|
||||
|
||||
/**
|
||||
@@ -42,6 +43,11 @@ export class BrushManager {
|
||||
|
||||
// 初始化笔刷注册
|
||||
this._registerDefaultBrushes();
|
||||
|
||||
// 初始化橡皮擦状态管理器
|
||||
this.eraserStateManager = null;
|
||||
this.isErasingActive = false;
|
||||
this.currentErasedObjects = []; // 当前擦除会话中被影响的对象
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,64 +57,112 @@ export class BrushManager {
|
||||
_registerDefaultBrushes() {
|
||||
// 注册铅笔笔刷
|
||||
brushRegistry.register("pencil", PencilBrush, {
|
||||
name: "铅笔",
|
||||
name: "Pencil",
|
||||
description: "基础铅笔工具,适合精细线条绘制",
|
||||
category: "基础笔刷",
|
||||
});
|
||||
|
||||
// 注册材质笔刷
|
||||
brushRegistry.register("texture", TextureBrush);
|
||||
brushRegistry.register("texture", TextureBrush, {
|
||||
name: "Texture",
|
||||
description: "使用纹理图片作为笔刷,支持缩放和透明度",
|
||||
category: "基础笔刷",
|
||||
});
|
||||
|
||||
// 注册集成的笔刷类型
|
||||
brushRegistry.register("crayon", CrayonBrush);
|
||||
brushRegistry.register("fur", FurBrush);
|
||||
brushRegistry.register("ink", InkBrush);
|
||||
brushRegistry.register("longfur", LongfurBrush);
|
||||
brushRegistry.register("writing", WritingBrush);
|
||||
brushRegistry.register("marker", MarkerBrush);
|
||||
brushRegistry.register("pen", CustomPenBrush);
|
||||
brushRegistry.register("ribbon", RibbonBrush);
|
||||
brushRegistry.register("shaded", ShadedBrush);
|
||||
brushRegistry.register("sketchy", SketchyBrush);
|
||||
brushRegistry.register("spraypaint", SpraypaintBrush);
|
||||
brushRegistry.register("crayon", CrayonBrush, {
|
||||
name: "Crayon",
|
||||
description: "使用纹理图片作为笔刷,支持缩放和透明度",
|
||||
category: "基础笔刷",
|
||||
});
|
||||
brushRegistry.register("fur", FurBrush, {
|
||||
name: "Texture",
|
||||
description: "使用纹理图片作为笔刷,支持缩放和透明度",
|
||||
category: "基础笔刷",
|
||||
});
|
||||
brushRegistry.register("ink", InkBrush, {
|
||||
name: "Ink",
|
||||
description: "墨水笔刷,适合书写和绘图",
|
||||
category: "基础笔刷",
|
||||
});
|
||||
brushRegistry.register("", LongfurBrush, {
|
||||
name: "Longfur",
|
||||
description: "长毛发笔刷,适合绘制动物毛皮、草或头发",
|
||||
category: "基础笔刷",
|
||||
});
|
||||
brushRegistry.register("writing", WritingBrush, {
|
||||
name: "Writing",
|
||||
description: "书法笔刷,模拟中国传统书法毛笔效果,具有笔锋和墨色变化",
|
||||
category: "基础笔刷",
|
||||
});
|
||||
brushRegistry.register("marker", MarkerBrush, {
|
||||
name: "Marker",
|
||||
description: "马克笔笔刷,适合粗线条和填充",
|
||||
category: "基础笔刷",
|
||||
});
|
||||
brushRegistry.register("pen", CustomPenBrush, {
|
||||
name: "Pen",
|
||||
description: "自定义钢笔笔刷,适合书写和绘图",
|
||||
category: "基础笔刷",
|
||||
});
|
||||
brushRegistry.register("ribbon", RibbonBrush, {
|
||||
name: "Ribbon",
|
||||
description: "丝带笔刷,适合创建流动的丝带效果",
|
||||
category: "基础笔刷",
|
||||
});
|
||||
brushRegistry.register("shaded", ShadedBrush, {
|
||||
name: "Shaded",
|
||||
description: "阴影笔刷,适合创建渐变和阴影效果",
|
||||
category: "基础笔刷",
|
||||
});
|
||||
// brushRegistry.register("sketchy", SketchyBrush);
|
||||
brushRegistry.register("spraypaint", SpraypaintBrush, {
|
||||
name: "Spraypaint",
|
||||
description: "喷漆笔刷,模拟喷漆效果",
|
||||
category: "基础笔刷",
|
||||
});
|
||||
|
||||
// 注册喷枪笔刷
|
||||
brushRegistry.register(
|
||||
"spray",
|
||||
class SprayBrush extends PencilBrush {
|
||||
constructor(canvas, options = {}) {
|
||||
super(canvas, {
|
||||
id: "spray",
|
||||
name: "喷枪",
|
||||
description: "模拟喷枪效果,创建散点效果",
|
||||
category: "基础笔刷",
|
||||
...options,
|
||||
});
|
||||
}
|
||||
// // 注册喷枪笔刷
|
||||
// brushRegistry.register(
|
||||
// "spray",
|
||||
// class SprayBrush extends PencilBrush {
|
||||
// constructor(canvas, options = {}) {
|
||||
// super(canvas, {
|
||||
// id: "spray",
|
||||
// name: "喷枪",
|
||||
// description: "模拟喷枪效果,创建散点效果",
|
||||
// category: "基础笔刷",
|
||||
// ...options,
|
||||
// });
|
||||
// }
|
||||
|
||||
create() {
|
||||
this.brush = new fabric.SprayBrush(this.canvas);
|
||||
this.configure(this.brush, this.options);
|
||||
return this.brush;
|
||||
}
|
||||
// create() {
|
||||
// this.brush = new fabric.SprayBrush(this.canvas);
|
||||
// this.configure(this.brush, this.options);
|
||||
// return this.brush;
|
||||
// }
|
||||
|
||||
configure(brush, options = {}) {
|
||||
super.configure(brush, options);
|
||||
// configure(brush, options = {}) {
|
||||
// super.configure(brush, options);
|
||||
|
||||
if (options.density !== undefined) {
|
||||
brush.density = options.density;
|
||||
}
|
||||
// if (options.density !== undefined) {
|
||||
// brush.density = options.density;
|
||||
// }
|
||||
|
||||
if (options.randomOpacity !== undefined) {
|
||||
brush.randomOpacity = options.randomOpacity;
|
||||
}
|
||||
// if (options.randomOpacity !== undefined) {
|
||||
// brush.randomOpacity = options.randomOpacity;
|
||||
// }
|
||||
|
||||
if (options.dotWidth !== undefined) {
|
||||
brush.dotWidth = options.dotWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
// if (options.dotWidth !== undefined) {
|
||||
// brush.dotWidth = options.dotWidth;
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// name: "喷枪",
|
||||
// description: "模拟喷枪效果,创建散点效果",
|
||||
// }
|
||||
// );
|
||||
// 注册橡皮擦笔刷
|
||||
brushRegistry.register(
|
||||
"eraser",
|
||||
@@ -187,87 +241,87 @@ export class BrushManager {
|
||||
}
|
||||
);
|
||||
|
||||
// 注册水彩笔刷
|
||||
brushRegistry.register(
|
||||
"watercolor",
|
||||
class WatercolorBrush extends PencilBrush {
|
||||
constructor(canvas, options = {}) {
|
||||
super(canvas, {
|
||||
id: "watercolor",
|
||||
name: "水彩",
|
||||
description: "模拟水彩效果,带有流动感和透明感",
|
||||
category: "特效笔刷",
|
||||
...options,
|
||||
});
|
||||
}
|
||||
// // 注册水彩笔刷
|
||||
// brushRegistry.register(
|
||||
// "watercolor",
|
||||
// class WatercolorBrush extends PencilBrush {
|
||||
// constructor(canvas, options = {}) {
|
||||
// super(canvas, {
|
||||
// id: "watercolor",
|
||||
// name: "水彩",
|
||||
// description: "模拟水彩效果,带有流动感和透明感",
|
||||
// category: "特效笔刷",
|
||||
// ...options,
|
||||
// });
|
||||
// }
|
||||
|
||||
create() {
|
||||
// 创建一个自定义的PencilBrush来模拟水彩效果
|
||||
this.brush = new fabric.PencilBrush(this.canvas);
|
||||
this.configure(this.brush, this.options);
|
||||
// create() {
|
||||
// // 创建一个自定义的PencilBrush来模拟水彩效果
|
||||
// this.brush = new fabric.PencilBrush(this.canvas);
|
||||
// this.configure(this.brush, this.options);
|
||||
|
||||
// 水彩效果特有的属性
|
||||
this.brush.globalCompositeOperation = "multiply";
|
||||
this.brush.shadow = new fabric.Shadow({
|
||||
color: this.options.color || "#000",
|
||||
blur: 5,
|
||||
offsetX: 0,
|
||||
offsetY: 0,
|
||||
});
|
||||
// // 水彩效果特有的属性
|
||||
// this.brush.globalCompositeOperation = "multiply";
|
||||
// this.brush.shadow = new fabric.Shadow({
|
||||
// color: this.options.color || "#000",
|
||||
// blur: 5,
|
||||
// offsetX: 0,
|
||||
// offsetY: 0,
|
||||
// });
|
||||
|
||||
return this.brush;
|
||||
}
|
||||
// return this.brush;
|
||||
// }
|
||||
|
||||
configure(brush, options = {}) {
|
||||
super.configure(brush, options);
|
||||
// configure(brush, options = {}) {
|
||||
// super.configure(brush, options);
|
||||
|
||||
// 水彩笔刷特有的配置
|
||||
brush.opacity = Math.min(0.5, options.opacity || 0.3); // 默认透明度30%
|
||||
}
|
||||
}
|
||||
);
|
||||
// // 水彩笔刷特有的配置
|
||||
// brush.opacity = Math.min(0.5, options.opacity || 0.3); // 默认透明度30%
|
||||
// }
|
||||
// }
|
||||
// );
|
||||
|
||||
// 注册粉笔笔刷
|
||||
brushRegistry.register(
|
||||
"chalk",
|
||||
class ChalkBrush extends PencilBrush {
|
||||
constructor(canvas, options = {}) {
|
||||
super(canvas, {
|
||||
id: "chalk",
|
||||
name: "粉笔",
|
||||
description: "模拟粉笔效果,有颗粒感和不连续性",
|
||||
category: "特效笔刷",
|
||||
...options,
|
||||
});
|
||||
}
|
||||
// // 注册粉笔笔刷
|
||||
// brushRegistry.register(
|
||||
// "chalk",
|
||||
// class ChalkBrush extends PencilBrush {
|
||||
// constructor(canvas, options = {}) {
|
||||
// super(canvas, {
|
||||
// id: "chalk",
|
||||
// name: "粉笔",
|
||||
// description: "模拟粉笔效果,有颗粒感和不连续性",
|
||||
// category: "特效笔刷",
|
||||
// ...options,
|
||||
// });
|
||||
// }
|
||||
|
||||
create() {
|
||||
this.brush = new fabric.PencilBrush(this.canvas);
|
||||
this.configure(this.brush, this.options);
|
||||
// create() {
|
||||
// this.brush = new fabric.PencilBrush(this.canvas);
|
||||
// this.configure(this.brush, this.options);
|
||||
|
||||
// 自定义绘画方法来模拟粉笔效果
|
||||
const originalOnMouseMove = this.brush.onMouseMove;
|
||||
this.brush.onMouseMove = function (pointer, options) {
|
||||
// 随机调整坐标位置,增加粉笔质感
|
||||
const jitter = 2;
|
||||
pointer.x += (Math.random() - 0.5) * jitter;
|
||||
pointer.y += (Math.random() - 0.5) * jitter;
|
||||
// // 自定义绘画方法来模拟粉笔效果
|
||||
// const originalOnMouseMove = this.brush.onMouseMove;
|
||||
// this.brush.onMouseMove = function (pointer, options) {
|
||||
// // 随机调整坐标位置,增加粉笔质感
|
||||
// const jitter = 2;
|
||||
// pointer.x += (Math.random() - 0.5) * jitter;
|
||||
// pointer.y += (Math.random() - 0.5) * jitter;
|
||||
|
||||
// 调用原始方法
|
||||
originalOnMouseMove.call(this, pointer, options);
|
||||
};
|
||||
// // 调用原始方法
|
||||
// originalOnMouseMove.call(this, pointer, options);
|
||||
// };
|
||||
|
||||
return this.brush;
|
||||
}
|
||||
// return this.brush;
|
||||
// }
|
||||
|
||||
configure(brush, options = {}) {
|
||||
super.configure(brush, options);
|
||||
// configure(brush, options = {}) {
|
||||
// super.configure(brush, options);
|
||||
|
||||
// 粉笔特有的设置
|
||||
brush.strokeDashArray = [5, 5]; // 虚线效果
|
||||
}
|
||||
}
|
||||
);
|
||||
// // 粉笔特有的设置
|
||||
// brush.strokeDashArray = [5, 5]; // 虚线效果
|
||||
// }
|
||||
// }
|
||||
// );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -571,6 +625,148 @@ export class BrushManager {
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置依赖管理器
|
||||
*/
|
||||
setManagers({ layerManager, commandManager }) {
|
||||
this.layerManager = layerManager;
|
||||
this.commandManager = commandManager;
|
||||
|
||||
// 初始化橡皮擦状态管理器
|
||||
if (this.canvas && this.layerManager) {
|
||||
this.eraserStateManager = new EraserStateManager(
|
||||
this.canvas,
|
||||
this.layerManager
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建橡皮擦
|
||||
* @param {Object} options 橡皮擦选项
|
||||
*/
|
||||
createEraser(options = {}) {
|
||||
if (!this.canvas) {
|
||||
console.error("画布未初始化");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
// 直接使用 fabric-with-erasing 库提供的 EraserBrush
|
||||
this.brush = new fabric.EraserBrush(this.canvas);
|
||||
|
||||
// 应用配置
|
||||
this.configure(this.brush, {
|
||||
width: this.brushSize.value,
|
||||
color: this.brushColor.value,
|
||||
opacity: this.brushOpacity.value,
|
||||
inverted: options.inverted || false,
|
||||
...options,
|
||||
});
|
||||
|
||||
// 设置画布为绘图模式
|
||||
this.canvas.isDrawingMode = true;
|
||||
this.canvas.freeDrawingBrush = this.brush;
|
||||
|
||||
// 绑定橡皮擦事件处理器
|
||||
// this._bindEraserEvents();
|
||||
|
||||
console.log("橡皮擦创建成功");
|
||||
return this.brush;
|
||||
} catch (error) {
|
||||
console.error("创建橡皮擦失败:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定橡皮擦事件处理器
|
||||
* @private
|
||||
*/
|
||||
_bindEraserEvents() {
|
||||
if (!this.canvas || !this.eraserStateManager) return;
|
||||
|
||||
// 监听擦除开始事件
|
||||
this.canvas.on("erasing:start", this._handleErasingStart.bind(this));
|
||||
|
||||
// 监听擦除结束事件
|
||||
this.canvas.on("erasing:end", this._handleErasingEnd.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解绑橡皮擦事件处理器
|
||||
* @private
|
||||
*/
|
||||
_unbindEraserEvents() {
|
||||
if (!this.canvas) return;
|
||||
|
||||
this.canvas.off("erasing:start", this._handleErasingStart.bind(this));
|
||||
this.canvas.off("erasing:end", this._handleErasingEnd.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理擦除开始事件
|
||||
* @param {Object} e 事件对象
|
||||
* @private
|
||||
*/
|
||||
_handleErasingStart(e) {
|
||||
console.log("橡皮擦开始擦除");
|
||||
|
||||
if (!this.eraserStateManager) return;
|
||||
|
||||
// 标记擦除状态
|
||||
this.isErasingActive = true;
|
||||
this.currentErasedObjects = [];
|
||||
|
||||
// 捕获擦除前的状态
|
||||
this.eraserStateManager.startErasing();
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理擦除结束事件
|
||||
* @param {Object} e 事件对象
|
||||
* @private
|
||||
*/
|
||||
_handleErasingEnd(e) {
|
||||
console.log("橡皮擦擦除结束", e);
|
||||
|
||||
if (!this.eraserStateManager || !this.isErasingActive) return;
|
||||
|
||||
// 获取被擦除的对象
|
||||
const affectedObjects = e.targets || [];
|
||||
|
||||
// 创建橡皮擦命令
|
||||
const eraserCommand = this.eraserStateManager.endErasing(affectedObjects);
|
||||
|
||||
// 如果有有效的命令且有命令管理器,执行命令
|
||||
if (eraserCommand && this.commandManager) {
|
||||
// 注意:不需要调用 execute(),因为擦除操作已经完成
|
||||
// 只需要将命令添加到历史记录中以支持撤销
|
||||
this.commandManager.addToHistory(eraserCommand);
|
||||
console.log("橡皮擦操作已添加到命令历史");
|
||||
}
|
||||
|
||||
// 重置状态
|
||||
this.isErasingActive = false;
|
||||
this.currentErasedObjects = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消当前擦除操作
|
||||
*/
|
||||
cancelErasing() {
|
||||
if (!this.isErasingActive) return;
|
||||
|
||||
if (this.eraserStateManager) {
|
||||
this.eraserStateManager.cancelErasing();
|
||||
}
|
||||
|
||||
this.isErasingActive = false;
|
||||
this.currentErasedObjects = [];
|
||||
|
||||
console.log("当前擦除操作已取消");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前笔刷类型
|
||||
* @returns {String} 当前笔刷类型ID
|
||||
@@ -646,7 +842,6 @@ export class BrushManager {
|
||||
|
||||
return this.canvas.freeDrawingBrush;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建橡皮擦
|
||||
* @returns {Object} 橡皮擦笔刷
|
||||
@@ -703,9 +898,20 @@ export class BrushManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁资源
|
||||
* 销毁笔刷管理器
|
||||
*/
|
||||
dispose() {
|
||||
// 解绑事件
|
||||
// this._unbindEraserEvents();
|
||||
|
||||
// 取消进行中的擦除操作
|
||||
this.cancelErasing();
|
||||
|
||||
// 清理状态管理器
|
||||
if (this.eraserStateManager) {
|
||||
this.eraserStateManager = null;
|
||||
}
|
||||
|
||||
// 销毁当前笔刷
|
||||
if (this.activeBrush) {
|
||||
this.activeBrush.destroy();
|
||||
|
||||
1748
src/component/Canvas/CanvasEditor/managers/brushes/fabric.brushes.js
Normal file
1748
src/component/Canvas/CanvasEditor/managers/brushes/fabric.brushes.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
import { BaseBrush } from "../BaseBrush";
|
||||
//import { fabric } from "fabric-with-all";
|
||||
import { fabric } from "fabric-with-all";
|
||||
import texturePresetManager from "../TexturePresetManager";
|
||||
|
||||
/**
|
||||
@@ -71,7 +71,72 @@ export class TextureBrush extends BaseBrush {
|
||||
// 创建fabric原生纹理笔刷
|
||||
this.brush = new fabric.PatternBrush(this.canvas);
|
||||
|
||||
// 配置笔刷
|
||||
// 重写 _finalizeAndAddPath 方法,使其调用 convertToImg 而不是创建 Path 对象
|
||||
const originalFinalizeAndAddPath = this.brush._finalizeAndAddPath.bind(
|
||||
this.brush
|
||||
);
|
||||
const self = this; // 保存外部this引用
|
||||
|
||||
this.brush._finalizeAndAddPath = function () {
|
||||
console.log("TextureBrush: _finalizeAndAddPath called");
|
||||
const ctx = this.canvas.contextTop;
|
||||
ctx.closePath();
|
||||
|
||||
// 应用点简化(如果PatternBrush支持)
|
||||
if (this.decimate && this._points) {
|
||||
this._points = this.decimatePoints(this._points, this.decimate);
|
||||
}
|
||||
|
||||
console.log(
|
||||
"TextureBrush: points count =",
|
||||
this._points ? this._points.length : 0
|
||||
);
|
||||
|
||||
// 检查是否有有效的路径数据
|
||||
if (!this._points || this._points.length < 2) {
|
||||
// 如果点数不足,直接请求重新渲染
|
||||
console.log("TextureBrush: Not enough points, skipping");
|
||||
this.canvas.requestRenderAll();
|
||||
return;
|
||||
}
|
||||
|
||||
const pathData = this.convertPointsToSVGPath(this._points);
|
||||
|
||||
const isEmpty = self._isEmptySVGPath(pathData);
|
||||
console.log("TextureBrush: isEmpty =", isEmpty);
|
||||
|
||||
if (isEmpty) {
|
||||
// 如果路径为空,直接请求重新渲染
|
||||
console.log("TextureBrush: Path is empty, skipping");
|
||||
this.canvas.requestRenderAll();
|
||||
return;
|
||||
}
|
||||
|
||||
// 先触发事件,模拟原生行为
|
||||
const path = this.createPath(pathData);
|
||||
this.canvas.fire("before:path:created", { path: path });
|
||||
|
||||
console.log("TextureBrush: Calling convertToImg");
|
||||
|
||||
// 调用 convertToImg 方法将绘制内容转换为图片
|
||||
if (typeof this.convertToImg === "function") {
|
||||
this.convertToImg();
|
||||
console.log("TextureBrush: convertToImg called successfully");
|
||||
} else {
|
||||
console.warn(
|
||||
"convertToImg method not found, falling back to original behavior"
|
||||
);
|
||||
// 如果没有convertToImg方法,回退到原始行为
|
||||
this.canvas.add(path);
|
||||
this.canvas.fire("path:created", { path: path });
|
||||
this.canvas.clearContext(this.canvas.contextTop);
|
||||
}
|
||||
|
||||
// 重置阴影
|
||||
this._resetShadow();
|
||||
};
|
||||
|
||||
// 配置笔刷基本属性
|
||||
this.configure(this.brush, this.options);
|
||||
|
||||
// 如果有选中的材质,则设置纹理
|
||||
@@ -221,6 +286,11 @@ export class TextureBrush extends BaseBrush {
|
||||
canvasTexture.width = width;
|
||||
canvasTexture.height = height;
|
||||
|
||||
// 应用透明度设置
|
||||
if (this.textureOpacity < 1) {
|
||||
ctx.globalAlpha = this.textureOpacity;
|
||||
}
|
||||
|
||||
// 绘制前应用旋转
|
||||
if (this.textureAngle !== 0) {
|
||||
ctx.save();
|
||||
@@ -233,26 +303,16 @@ export class TextureBrush extends BaseBrush {
|
||||
ctx.drawImage(img, 0, 0, width, height);
|
||||
}
|
||||
|
||||
// 应用透明度
|
||||
if (this.textureOpacity < 1) {
|
||||
ctx.globalAlpha = this.textureOpacity;
|
||||
ctx.fillStyle = "#fff";
|
||||
ctx.fillRect(0, 0, width, height);
|
||||
}
|
||||
// 缓存处理后的纹理图像
|
||||
this._processedTextureCanvas = canvasTexture;
|
||||
|
||||
// 创建Pattern对象
|
||||
const pattern = new fabric.Pattern({
|
||||
source: canvasTexture,
|
||||
repeat: this.textureRepeat,
|
||||
});
|
||||
// 使用fabric.js 5.x正确的API方式设置PatternBrush
|
||||
// 直接设置source属性,这是PatternBrush的标准用法
|
||||
this.brush.source = canvasTexture;
|
||||
|
||||
// 设置笔刷源纹理
|
||||
if (typeof this.brush.setSource === "function") {
|
||||
this.brush.setSource(pattern);
|
||||
} else if (typeof this.brush.source === "object") {
|
||||
this.brush.source = pattern;
|
||||
} else if (typeof this.brush.pattern === "object") {
|
||||
this.brush.pattern = pattern;
|
||||
// 通知画布重绘
|
||||
if (this.canvas && this.canvas.requestRenderAll) {
|
||||
this.canvas.requestRenderAll();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -852,4 +912,37 @@ export class TextureBrush extends BaseBrush {
|
||||
getTextureStats() {
|
||||
return texturePresetManager.getStats();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查 SVG 路径是否为空
|
||||
* @private
|
||||
* @param {Array} pathData SVG 路径数据
|
||||
* @returns {Boolean} 是否为空路径
|
||||
*/
|
||||
_isEmptySVGPath(pathData) {
|
||||
if (!pathData || pathData.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查路径是否只包含移动命令或者是一个点
|
||||
let hasDrawing = false;
|
||||
let moveCount = 0;
|
||||
|
||||
for (let i = 0; i < pathData.length; i++) {
|
||||
const command = pathData[i];
|
||||
if (command[0] === "M") {
|
||||
moveCount++;
|
||||
} else if (
|
||||
command[0] === "L" ||
|
||||
command[0] === "Q" ||
|
||||
command[0] === "C"
|
||||
) {
|
||||
hasDrawing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果只有移动命令且超过1个,或者没有绘制命令,则认为是空路径
|
||||
return !hasDrawing || (moveCount > 0 && pathData.length <= moveCount);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user