feat: 裁剪组裁剪跟随选择组移动

This commit is contained in:
bighuixiang
2025-07-14 01:00:23 +08:00
parent 96e13cb22a
commit 24e9ba8ae5
80 changed files with 2052 additions and 4292 deletions

View File

@@ -125,9 +125,7 @@ export class BaseBrush {
_createRGBAColor(color, opacity) {
// 如果已经是rgba颜色先提取RGB部分
if (color.startsWith("rgba")) {
const rgbaMatch = color.match(
/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*[\d.]+)?\)/
);
const rgbaMatch = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*[\d.]+)?\)/);
if (rgbaMatch) {
const [, r, g, b] = rgbaMatch;
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
@@ -258,10 +256,7 @@ export class BaseBrush {
// 过滤掉同名属性(子类优先)
const basePropsFiltered = baseProperties.filter(
(baseProp) =>
!specificProperties.some(
(specificProp) => specificProp.id === baseProp.id
)
(baseProp) => !specificProperties.some((specificProp) => specificProp.id === baseProp.id)
);
return [...basePropsFiltered, ...specificProperties];
@@ -334,10 +329,7 @@ export class BaseBrush {
* @returns {Array} 选项数组
*/
getDynamicOptions(property, currentValues) {
if (
property.dynamicOptions &&
typeof property.dynamicOptions === "function"
) {
if (property.dynamicOptions && typeof property.dynamicOptions === "function") {
return property.dynamicOptions(currentValues);
}
return property.options || [];

View File

@@ -206,9 +206,7 @@ export class TexturePresetManager {
* @returns {Object|null} 材质对象
*/
getTextureById(textureId) {
return (
this.getAllTextures().find((texture) => texture.id === textureId) || null
);
return this.getAllTextures().find((texture) => texture.id === textureId) || null;
}
/**
@@ -217,9 +215,7 @@ export class TexturePresetManager {
* @returns {Array} 材质数组
*/
getTexturesByCategory(category) {
return this.getAllTextures().filter(
(texture) => texture.category === category
);
return this.getAllTextures().filter((texture) => texture.category === category);
}
/**
@@ -241,8 +237,7 @@ export class TexturePresetManager {
*/
addCustomTexture(textureData) {
const textureId =
textureData.id ||
`custom_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
textureData.id || `custom_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
const texture = {
id: textureId,
@@ -286,9 +281,7 @@ export class TexturePresetManager {
* @returns {Boolean} 是否删除成功
*/
removeCustomTexture(textureId) {
const index = this.customTextures.findIndex(
(texture) => texture.id === textureId
);
const index = this.customTextures.findIndex((texture) => texture.id === textureId);
if (index === -1) {
return false;
}
@@ -430,10 +423,7 @@ export class TexturePresetManager {
file: null,
}));
localStorage.setItem(
"canvasEditor_customTextures",
JSON.stringify(customTexturesData)
);
localStorage.setItem("canvasEditor_customTextures", JSON.stringify(customTexturesData));
} catch (error) {
console.error("保存自定义材质失败:", error);
}
@@ -472,9 +462,7 @@ export class TexturePresetManager {
* @returns {String} 预设ID
*/
createTexturePreset(name, settings) {
const presetId = `preset_${Date.now()}_${Math.random()
.toString(36)
.substr(2, 9)}`;
const presetId = `preset_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
const preset = {
id: presetId,

View File

@@ -17,6 +17,7 @@ import { MarkerBrush } from "./types/MarkerBrush";
import { CustomPenBrush } from "./types/CustomPenBrush";
import { RibbonBrush } from "./types/RibbonBrush";
import { ShadedBrush } from "./types/ShadedBrush";
import { EraserStateManager } from "../EraserStateManager";
// import { SketchyBrush } from "./types/SketchyBrush";
// import { SpraypaintBrush } from "./types/SpraypaintBrush";
@@ -379,27 +380,23 @@ export class BrushManager {
}
// 创建新笔刷实例
try {
const brushInstance = brushRegistry.createBrushInstance(
brushId,
this.canvas,
{
color: brushId === "eraser" ? this.brushStore.state.color : undefined,
width: this.brushStore.state.size,
opacity: this.brushStore.state.opacity,
const brushInstance = brushRegistry.createBrushInstance(brushId, this.canvas, {
color: brushId === "eraser" ? this.brushStore.state.color : undefined,
width: this.brushStore.state.size,
opacity: this.brushStore.state.opacity,
// 阴影相关配置
shadowEnabled: this.brushStore.state.shadowEnabled,
shadowColor: this.brushStore.state.shadowColor,
shadowWidth: this.brushStore.state.shadowWidth,
shadowOffsetX: this.brushStore.state.shadowOffsetX,
shadowOffsetY: this.brushStore.state.shadowOffsetY,
// 阴影相关配置
shadowEnabled: this.brushStore.state.shadowEnabled,
shadowColor: this.brushStore.state.shadowColor,
shadowWidth: this.brushStore.state.shadowWidth,
shadowOffsetX: this.brushStore.state.shadowOffsetX,
shadowOffsetY: this.brushStore.state.shadowOffsetY,
// 材质笔刷特有配置
textureEnabled: this.brushStore.state.textureEnabled,
texturePath: this.brushStore.state.texturePath,
textureScale: this.brushStore.state.textureScale,
}
);
// 材质笔刷特有配置
textureEnabled: this.brushStore.state.textureEnabled,
texturePath: this.brushStore.state.texturePath,
textureScale: this.brushStore.state.textureScale,
});
if (brushInstance) {
// 创建笔刷
@@ -648,48 +645,7 @@ export class BrushManager {
// 初始化橡皮擦状态管理器
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;
this.eraserStateManager = new EraserStateManager(this.canvas, this.layerManager);
}
}
@@ -866,6 +822,44 @@ export class BrushManager {
}
}
// /**
// * 创建橡皮擦
// * @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;
// }
// }
/**
* 创建橡皮擦
* @returns {Object} 橡皮擦笔刷
@@ -891,12 +885,7 @@ export class BrushManager {
const imageData = ctx.getImageData(pointer.x, pointer.y, 1, 1).data;
// 将RGB转换为十六进制颜色
const color = `#${(
(1 << 24) +
(imageData[0] << 16) +
(imageData[1] << 8) +
imageData[2]
)
const color = `#${((1 << 24) + (imageData[0] << 16) + (imageData[1] << 8) + imageData[2])
.toString(16)
.slice(1)}`;

View File

@@ -97,9 +97,7 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
}
if (color.indexOf("rgb") === -1) {
// convert named colors
var tempElem = document.body.appendChild(
document.createElement("fictum")
); // intentionally use unknown tag to lower chances of css rule override with !important
var tempElem = document.body.appendChild(document.createElement("fictum")); // intentionally use unknown tag to lower chances of css rule override with !important
var flag = "rgb(1, 2, 3)"; // this flag tested on chrome 59, ff 53, ie9, ie10, ie11, edge 14
tempElem.style.color = flag;
if (tempElem.style.color !== flag) {
@@ -116,7 +114,7 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
if (color.indexOf("rgba") === -1) {
color += ",1"; // convert 'rgb(R,G,B)' to 'rgb(R,G,B)A' which looks awful but will pass the regxep below
}
return color.match(/[\.\d]+/g).map(function (a) {
return color.match(/[.\d]+/g).map(function (a) {
return +a;
});
}
@@ -269,13 +267,7 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
draw: function () {
var ctx = this.ctx;
ctx.save();
this.line(
ctx,
this._lastPoint,
this._point,
this.color,
this._currentLineWidth
);
this.line(ctx, this._lastPoint, this._point, this.color, this._currentLineWidth);
ctx.restore();
},
@@ -319,10 +311,8 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
},
onMouseDown: function (pointer) {
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this.canvas.contextTop.globalAlpha = this.opacity;
this._size = this.width / 2 + this._baseWidth;
this._drawn = false;
@@ -330,10 +320,8 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
},
onMouseMove: function (pointer) {
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this.update(pointer);
this.draw(this.canvas.contextTop);
},
@@ -358,9 +346,7 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
update: function (p) {
this.set(p);
this._latestStrokeLength = this._point
.subtract(this._latest)
.distanceFrom({ x: 0, y: 0 });
this._latestStrokeLength = this._point.subtract(this._latest).distanceFrom({ x: 0, y: 0 });
},
draw: function (ctx) {
@@ -372,12 +358,7 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
v.normalize(s);
dotSize =
this._sep *
fabric.util.clamp(
(this._inkAmount / this._latestStrokeLength) * 3,
1,
0.5
);
this._sep * fabric.util.clamp((this._inkAmount / this._latestStrokeLength) * 3, 1, 0.5);
dotNum = Math.ceil(this._size * this._sep);
range = this._size / 2;
@@ -428,10 +409,8 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
onMouseDown: function (pointer) {
// 添加坐标转换处理画布缩放和偏移
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._points = [pointer];
this._count = 0;
@@ -440,15 +419,7 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
color = fabric.util.colorValues(this.color);
ctx.strokeStyle =
"rgba(" +
color[0] +
"," +
color[1] +
"," +
color[2] +
"," +
0.1 * this.opacity +
")";
"rgba(" + color[0] + "," + color[1] + "," + color[2] + "," + 0.1 * this.opacity + ")";
ctx.lineWidth = this.width;
this._points.push(pointer);
@@ -456,10 +427,8 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
onMouseMove: function (pointer) {
// 添加坐标转换处理画布缩放和偏移
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._points.push(pointer);
@@ -528,10 +497,8 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
},
_render: function (pointer) {
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
var len,
i,
point = this.setPointer(pointer),
@@ -579,21 +546,11 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
for (i = 0; i < num; i++) {
r = fabric.util.getRandom(range, 1);
c = fabric.util.getRandom(Math.PI * 2);
point = new fabric.Point(
pointer.x + r * Math.sin(c),
pointer.y + r * Math.cos(c)
);
point = new fabric.Point(pointer.x + r * Math.sin(c), pointer.y + r * Math.cos(c));
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(
point.x,
point.y,
fabric.util.getRandom(maxSize) / 2,
0,
Math.PI * 2,
false
);
ctx.arc(point.x, point.y, fabric.util.getRandom(maxSize) / 2, 0, Math.PI * 2, false);
ctx.fill();
}
ctx.restore();
@@ -609,10 +566,8 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
},
_resetTip: function (pointer) {
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
var len,
i,
point = this.setPointer(pointer);
@@ -655,10 +610,8 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
},
onMouseDown: function (pointer) {
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._points = [pointer];
this._count = 0;
@@ -667,23 +620,13 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
//ctx.globalCompositeOperation = 'source-over';
ctx.strokeStyle =
"rgba(" +
color[0] +
"," +
color[1] +
"," +
color[2] +
"," +
0.05 * this.opacity +
")";
"rgba(" + color[0] + "," + color[1] + "," + color[2] + "," + 0.05 * this.opacity + ")";
ctx.lineWidth = this.width;
},
onMouseMove: function (pointer) {
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._points.push(pointer);
var i,
@@ -772,10 +715,7 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
this._lastPoint.x - lineWidthDiff + num,
this._lastPoint.y + lineWidthDiff - num
);
ctx.lineTo(
pointer.x - lineWidthDiff + num,
pointer.y + lineWidthDiff - num
);
ctx.lineTo(pointer.x - lineWidthDiff + num, pointer.y + lineWidthDiff - num);
ctx.stroke();
}
@@ -783,10 +723,8 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
},
onMouseDown: function (pointer) {
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._lastPoint = pointer;
this.canvas.contextTop.strokeStyle = this.color;
this.canvas.contextTop.lineWidth = this._lineWidth;
@@ -795,10 +733,8 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
onMouseMove: function (pointer) {
if (this.canvas._isCurrentlyDrawing) {
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._render(pointer);
}
},
@@ -852,10 +788,7 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
this._lastPoint.x + lineWidthDiff - num,
this._lastPoint.y + lineWidthDiff - num
);
ctx.lineTo(
pointer.x + lineWidthDiff - num,
pointer.y + lineWidthDiff - num
);
ctx.lineTo(pointer.x + lineWidthDiff - num, pointer.y + lineWidthDiff - num);
ctx.stroke();
}
@@ -863,10 +796,8 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
},
onMouseDown: function (pointer) {
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._lastPoint = pointer;
this.canvas.contextTop.strokeStyle = this.color;
this.canvas.contextTop.lineWidth = this._lineWidth;
@@ -875,10 +806,8 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
onMouseMove: function (pointer) {
if (this.canvas._isCurrentlyDrawing) {
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._render(pointer);
}
},
@@ -923,10 +852,8 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
},
onMouseDown: function (pointer) {
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._points = [];
this._points.push(["M", pointer.x, pointer.y]);
@@ -938,10 +865,8 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
onMouseMove: function (pointer) {
if (this.canvas._isCurrentlyDrawing) {
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._render(pointer);
}
},
@@ -1010,10 +935,8 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
onMouseDown: function (pointer) {
// 添加坐标转换处理画布缩放和偏移
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._lastPoint = pointer;
this.canvas.contextTop.strokeStyle = this.color;
@@ -1024,10 +947,8 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
onMouseMove: function (pointer) {
if (this.canvas._isCurrentlyDrawing) {
// 添加坐标转换处理画布缩放和偏移
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._render(pointer);
}
@@ -1093,10 +1014,8 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
},
onMouseDown: function (pointer) {
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._lastPoint = pointer;
this.canvas.contextTop.lineWidth = this._lineWidth;
this._size = this.width + this._baseWidth;
@@ -1104,10 +1023,8 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
onMouseMove: function (pointer) {
if (this.canvas._isCurrentlyDrawing) {
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._render(pointer);
}
},
@@ -1158,12 +1075,10 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
ctx.beginPath();
ctx.moveTo(painters[i].dx, painters[i].dy);
painters[i].dx -= painters[i].ax =
(painters[i].ax +
(painters[i].dx - this._lastPoint.x) * painters[i].div) *
(painters[i].ax + (painters[i].dx - this._lastPoint.x) * painters[i].div) *
painters[i].ease;
painters[i].dy -= painters[i].ay =
(painters[i].ay +
(painters[i].dy - this._lastPoint.y) * painters[i].div) *
(painters[i].ay + (painters[i].dy - this._lastPoint.y) * painters[i].div) *
painters[i].ease;
ctx.lineTo(painters[i].dx, painters[i].dy);
ctx.stroke();
@@ -1185,26 +1100,16 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
ease: Math.random() * 0.2 + 0.6,
});
}
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._lastPoint = pointer;
//ctx.globalCompositeOperation = 'source-over';
ctx.strokeStyle =
"rgba(" +
color[0] +
"," +
color[1] +
"," +
color[2] +
"," +
0.05 * this.opacity +
")";
"rgba(" + color[0] + "," + color[1] + "," + color[2] + "," + 0.05 * this.opacity + ")";
ctx.lineWidth = this.width;
for (var i = 0; i < this._nrPainters; i++) {
for (let i = 0; i < this._nrPainters; i++) {
this._painters[i].dx = pointer.x;
this._painters[i].dy = pointer.y;
}
@@ -1216,10 +1121,8 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
},
onMouseMove: function (pointer) {
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._lastPoint = pointer;
},
@@ -1254,34 +1157,22 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
},
onMouseDown: function (pointer) {
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._points = [pointer];
var ctx = this.canvas.contextTop,
color = fabric.util.colorValues(this.color);
ctx.strokeStyle =
"rgba(" +
color[0] +
"," +
color[1] +
"," +
color[2] +
"," +
this.opacity +
")";
"rgba(" + color[0] + "," + color[1] + "," + color[2] + "," + this.opacity + ")";
ctx.lineWidth = this.width;
ctx.lineJoin = ctx.lineCap = "round";
},
onMouseMove: function (pointer) {
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._points.push(pointer);
var ctx = this.canvas.contextTop,
@@ -1346,10 +1237,8 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
this.canvas.contextTop.globalAlpha = this.opacity;
// 坐标转换
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._points = [pointer];
this._count = 0;
@@ -1361,23 +1250,13 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
ctx.lineWidth = this.width;
ctx.strokeStyle =
"rgba(" +
color[0] +
"," +
color[1] +
"," +
color[2] +
"," +
0.3 * this.opacity +
")";
"rgba(" + color[0] + "," + color[1] + "," + color[2] + "," + 0.3 * this.opacity + ")";
},
onMouseMove: function (pointer) {
// 坐标转换
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._points.push(pointer);
@@ -1396,15 +1275,7 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
// 增加透明度设置
var color = fabric.util.colorValues(this.color);
ctx.strokeStyle =
"rgba(" +
color[0] +
"," +
color[1] +
"," +
color[2] +
"," +
0.2 * this.opacity +
")";
"rgba(" + color[0] + "," + color[1] + "," + color[2] + "," + 0.2 * this.opacity + ")";
// 修改循环逻辑,确保在有点时能画出效果
if (this._count > 0) {
@@ -1416,10 +1287,7 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
if (d < 4000 && Math.random() > d / 2000) {
ctx.beginPath();
ctx.moveTo(
points[this._count].x + dx * factor,
points[this._count].y + dy * factor
);
ctx.moveTo(points[this._count].x + dx * factor, points[this._count].y + dy * factor);
ctx.lineTo(points[i].x - dx * factor, points[i].y - dy * factor);
ctx.stroke();
this._drawn = true;
@@ -1494,10 +1362,8 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
onMouseDown: function (pointer) {
this.canvas.contextTop.globalAlpha = this.opacity;
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._point = new fabric.Point(pointer.x, pointer.y);
this._lastPoint = this._point;
@@ -1510,10 +1376,8 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
},
onMouseMove: function (pointer) {
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._lastPoint = this._point;
this._point = new fabric.Point(pointer.x, pointer.y);
},
@@ -1542,13 +1406,7 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
x = self._lastPoint.x + Math.sin(angle) - self.size / 2;
y = self._lastPoint.y + Math.cos(angle) - self.size / 2;
self.canvas.contextTop.drawImage(
self.brush._element,
x,
y,
self.size,
self.size
);
self.canvas.contextTop.drawImage(self.brush._element, x, y, self.size, self.size);
if (self.canvas._isCurrentlyDrawing) {
setTimeout(draw, self._interval);
@@ -1594,43 +1452,22 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
var ctx = this.canvas.contextTop,
color = fabric.util.colorValues(this.color),
bgColor = fabric.util.colorValues(this.bgColor);
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._lastPoint = pointer;
this._drawn = false;
//ctx.globalCompositeOperation = 'source-over';
this.canvas.contextTop.globalAlpha = this.opacity;
ctx.fillStyle =
"rgba(" +
bgColor[0] +
"," +
bgColor[1] +
"," +
bgColor[2] +
"," +
bgColor[3] +
")";
ctx.strokeStyle =
"rgba(" +
color[0] +
"," +
color[1] +
"," +
color[2] +
"," +
color[3] +
")";
"rgba(" + bgColor[0] + "," + bgColor[1] + "," + bgColor[2] + "," + bgColor[3] + ")";
ctx.strokeStyle = "rgba(" + color[0] + "," + color[1] + "," + color[2] + "," + color[3] + ")";
ctx.lineWidth = this.width;
},
onMouseMove: function (pointer) {
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
var ctx = this.canvas.contextTop,
dx = pointer.x - this._lastPoint.x,
dy = pointer.y - this._lastPoint.y,
@@ -1683,20 +1520,16 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
},
onMouseDown: function (pointer) {
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._points = [pointer];
this._count = 0;
this._colorValues = fabric.util.colorValues(this.color);
},
onMouseMove: function (pointer) {
pointer.x =
pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y =
pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
pointer.x = pointer.x * this.canvas.getZoom() + this.canvas.viewportTransform[4];
pointer.y = pointer.y * this.canvas.getZoom() + this.canvas.viewportTransform[5];
this._points.push(pointer);
var ctx = this.canvas.contextTop,

View File

@@ -350,9 +350,7 @@ export class RainbowBrush extends BaseBrush {
];
// 移除基础属性中的颜色选择器,因为彩虹笔不需要颜色选择
const filteredBaseProps = baseProperties.filter(
(prop) => prop.id !== "color"
);
const filteredBaseProps = baseProperties.filter((prop) => prop.id !== "color");
// 合并并返回所有属性
return [...filteredBaseProps, ...rainbowProperties];
@@ -432,11 +430,7 @@ export class CustomBrushExample extends BaseBrush {
this.dashPattern = options.dashPattern || [0, 0]; // 实线
this.noiseAmount = options.noiseAmount || 0;
this.gradientEnabled = options.gradientEnabled || false;
this.gradientColors = options.gradientColors || [
"#ff0000",
"#ffff00",
"#00ff00",
];
this.gradientColors = options.gradientColors || ["#ff0000", "#ffff00", "#00ff00"];
this.angle = options.angle || 0;
// 材质相关属性
@@ -885,8 +879,7 @@ export class CustomBrushExample extends BaseBrush {
description: "选择图案类型",
category: "特效设置",
order: 130,
visibleWhen: (values) =>
values.effectType === "pattern" || values.patternType === "dashed",
visibleWhen: (values) => values.effectType === "pattern" || values.patternType === "dashed",
},
// 虚线特有属性
@@ -1184,7 +1177,7 @@ export class CustomBrushExample extends BaseBrush {
return true;
case "dashPattern1":
case "dashPattern2":
case "dashPattern2": {
// 更新虚线模式
const idx = propId === "dashPattern1" ? 0 : 1;
this.dashPattern[idx] = value;
@@ -1192,6 +1185,7 @@ export class CustomBrushExample extends BaseBrush {
this.brush.strokeDashArray = this.dashPattern;
}
return true;
}
case "noiseAmount":
this.noiseAmount = value;
@@ -1206,13 +1200,14 @@ export class CustomBrushExample extends BaseBrush {
case "gradientColor1":
case "gradientColor2":
case "gradientColor3":
case "gradientColor3": {
const colorIdx = parseInt(propId.slice(-1)) - 1;
this.gradientColors[colorIdx] = value;
if (this.gradientEnabled && this.brush) {
this._configureGradient(this.brush);
}
return true;
}
case "angle":
this.angle = value;

View File

@@ -24,8 +24,7 @@ export class InkBrush extends BaseBrush {
this._baseWidth = options._baseWidth || 15;
this._inkAmount = options._inkAmount || 7;
this._range = options._range || 10;
this.splashEnabled =
options.splashEnabled !== undefined ? options.splashEnabled : true;
this.splashEnabled = options.splashEnabled !== undefined ? options.splashEnabled : true;
this.splashSize = options.splashSize || 5;
this.splashDistance = options.splashDistance || 30;
}

View File

@@ -26,9 +26,7 @@ export class LongfurBrush extends BaseBrush {
this.furFlowFactor = options.furFlowFactor || 0.5;
this.furCurvature = options.furCurvature || 0.3;
this.randomizeDirection =
options.randomizeDirection !== undefined
? options.randomizeDirection
: true;
options.randomizeDirection !== undefined ? options.randomizeDirection : true;
}
/**

View File

@@ -39,9 +39,7 @@ export class PencilBrush extends BaseBrush {
this.brush = new fabric.PencilBrush(this.canvas);
// 重写 _finalizeAndAddPath 方法,使其调用 convertToImg 而不是创建 Path 对象
const originalFinalizeAndAddPath = this.brush._finalizeAndAddPath.bind(
this.brush
);
const originalFinalizeAndAddPath = this.brush._finalizeAndAddPath.bind(this.brush);
const self = this; // 保存外部this引用
this.brush._finalizeAndAddPath = function () {
@@ -54,10 +52,7 @@ export class PencilBrush extends BaseBrush {
this._points = this.decimatePoints(this._points, this.decimate);
}
console.log(
"PencilBrush: points count =",
this._points ? this._points.length : 0
);
console.log("PencilBrush: points count =", this._points ? this._points.length : 0);
// 检查是否有有效的路径数据
if (!this._points || this._points.length < 2) {
@@ -97,9 +92,7 @@ export class PencilBrush extends BaseBrush {
// 恢复透明度
ctx.globalAlpha = currentAlpha;
} else {
console.warn(
"convertToImg method not found, falling back to original behavior"
);
console.warn("convertToImg method not found, falling back to original behavior");
// 如果没有convertToImg方法回退到原始行为
this.canvas.add(path);
this.canvas.fire("path:created", { path: path });
@@ -135,11 +128,7 @@ export class PencilBrush extends BaseBrush {
const command = pathData[i];
if (command[0] === "M") {
moveCount++;
} else if (
command[0] === "L" ||
command[0] === "Q" ||
command[0] === "C"
) {
} else if (command[0] === "L" || command[0] === "Q" || command[0] === "C") {
hasDrawing = true;
break;
}
@@ -210,9 +199,7 @@ export class PencilBrush extends BaseBrush {
_createRGBAColor(color, opacity) {
// 如果已经是rgba颜色先提取RGB部分
if (color.startsWith("rgba")) {
const rgbaMatch = color.match(
/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*[\d.]+)?\)/
);
const rgbaMatch = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*[\d.]+)?\)/);
if (rgbaMatch) {
const [, r, g, b] = rgbaMatch;
return `rgba(${r}, ${g}, ${b}, ${opacity})`;

View File

@@ -75,10 +75,7 @@ export class RibbonBrush extends BaseBrush {
brush.opacity = options.opacity;
// 如果启用渐变,更新渐变的第一个颜色
if (this.gradient && this.gradientColors.length > 0) {
this.gradientColors[0] = this._createRGBAColor(
brush.color,
options.opacity
);
this.gradientColors[0] = this._createRGBAColor(brush.color, options.opacity);
this.updateGradient();
}
brush.canvas.freeDrawingBrush.opacity = options.opacity;

View File

@@ -23,8 +23,7 @@ export class SpraypaintBrush extends BaseBrush {
// 喷漆笔刷特有属性
this.density = options.density || 20;
this.sprayRadius = options.sprayRadius || 10;
this.randomOpacity =
options.randomOpacity !== undefined ? options.randomOpacity : true;
this.randomOpacity = options.randomOpacity !== undefined ? options.randomOpacity : true;
this.dotSize = options.dotSize || 1;
this.dotShape = options.dotShape || "circle";
}

View File

@@ -71,9 +71,7 @@ export class TextureBrush extends BaseBrush {
this.brush = new fabric.PatternBrush(this.canvas);
// 重写 _finalizeAndAddPath 方法,使其调用 convertToImg 而不是创建 Path 对象
const originalFinalizeAndAddPath = this.brush._finalizeAndAddPath.bind(
this.brush
);
const originalFinalizeAndAddPath = this.brush._finalizeAndAddPath.bind(this.brush);
const self = this; // 保存外部this引用
this.brush._finalizeAndAddPath = function () {
@@ -86,10 +84,7 @@ export class TextureBrush extends BaseBrush {
this._points = this.decimatePoints(this._points, this.decimate);
}
console.log(
"TextureBrush: points count =",
this._points ? this._points.length : 0
);
console.log("TextureBrush: points count =", this._points ? this._points.length : 0);
// 检查是否有有效的路径数据
if (!this._points || this._points.length < 2) {
@@ -122,9 +117,7 @@ export class TextureBrush extends BaseBrush {
this.convertToImg();
console.log("TextureBrush: convertToImg called successfully");
} else {
console.warn(
"convertToImg method not found, falling back to original behavior"
);
console.warn("convertToImg method not found, falling back to original behavior");
// 如果没有convertToImg方法回退到原始行为
this.canvas.add(path);
this.canvas.fire("path:created", { path: path });
@@ -254,10 +247,7 @@ export class TextureBrush extends BaseBrush {
this._applyTextureToPatternBrush(img);
resolve(img);
});
} else if (
source instanceof Image ||
source instanceof HTMLCanvasElement
) {
} else if (source instanceof Image || source instanceof HTMLCanvasElement) {
// 如果已经是Image或Canvas对象直接使用
this._applyTextureToPatternBrush(source);
resolve(source);
@@ -425,9 +415,7 @@ export class TextureBrush extends BaseBrush {
if (textures.length === 0) return Promise.resolve();
this.currentTextureIndex =
this.currentTextureIndex === 0
? textures.length - 1
: this.currentTextureIndex - 1;
this.currentTextureIndex === 0 ? textures.length - 1 : this.currentTextureIndex - 1;
const prevTexture = textures[this.currentTextureIndex];
return this.setTextureById(prevTexture.id);
@@ -943,11 +931,7 @@ export class TextureBrush extends BaseBrush {
const command = pathData[i];
if (command[0] === "M") {
moveCount++;
} else if (
command[0] === "L" ||
command[0] === "Q" ||
command[0] === "C"
) {
} else if (command[0] === "L" || command[0] === "Q" || command[0] === "C") {
hasDrawing = true;
break;
}

View File

@@ -25,9 +25,7 @@ export class WritingBrush extends BaseBrush {
this.inkAmount = options.inkAmount || 20;
this.brushTaperFactor = options.brushTaperFactor || 0.6;
this.enableInkDripping =
options.enableInkDripping !== undefined
? options.enableInkDripping
: true;
options.enableInkDripping !== undefined ? options.enableInkDripping : true;
}
/**