合并画布
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
# fabric-with-erasing 库的 erasable 属性功能使用指南
|
||||
|
||||
## 库功能概述
|
||||
|
||||
`fabric-with-erasing` 库提供了强大的基于属性的擦除控制功能,无需手动实现复杂的图层检查逻辑。
|
||||
|
||||
## 核心功能
|
||||
|
||||
### 1. erasable 属性的三种模式
|
||||
|
||||
- **`true`** (默认): 对象可以被擦除
|
||||
- **`false`**: 对象不能被擦除
|
||||
- **`'deep'`**: 对于组合对象,可以对内部可擦除的子对象进行细粒度控制
|
||||
|
||||
### 2. 选择性擦除机制
|
||||
|
||||
库内置了选择性擦除机制:
|
||||
- 橡皮擦会自动检测对象的 `erasable` 属性
|
||||
- 只有 `erasable !== false` 的对象才会被擦除
|
||||
- 支持复杂的嵌套对象结构
|
||||
|
||||
### 3. 反向擦除功能
|
||||
|
||||
- 设置 `brush.inverted = true` 可以实现"撤销擦除"效果
|
||||
- 恢复已被擦除的内容
|
||||
|
||||
## 项目中的优化实现
|
||||
|
||||
### LayerManager 优化
|
||||
|
||||
```javascript
|
||||
// 基于图层状态自动设置 erasable 属性
|
||||
obj.erasable = isInActiveLayer && layer.visible && !layer.locked && !layer.isBackground;
|
||||
```
|
||||
|
||||
**优势:**
|
||||
- 只有活动图层、可见、非锁定、非背景的对象才可擦除
|
||||
- 自动处理复杂的权限逻辑
|
||||
- 性能优秀,无需手动遍历检查
|
||||
|
||||
### BrushManager 简化
|
||||
|
||||
```javascript
|
||||
// 直接使用库的 EraserBrush
|
||||
this.brush = new fabric.EraserBrush(this.canvas);
|
||||
this.brush.inverted = this.options.inverted || false;
|
||||
```
|
||||
|
||||
**优势:**
|
||||
- 移除了复杂的手动图层检查逻辑
|
||||
- 直接利用库的内置功能
|
||||
- 支持反向擦除(恢复功能)
|
||||
- 代码更简洁、更可靠
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 基础用法
|
||||
|
||||
```javascript
|
||||
// 设置对象不可擦除
|
||||
fabricObject.erasable = false;
|
||||
|
||||
// 设置对象可擦除
|
||||
fabricObject.erasable = true;
|
||||
|
||||
// 组合对象的深度擦除控制
|
||||
group.erasable = 'deep';
|
||||
```
|
||||
|
||||
### 高级用法
|
||||
|
||||
```javascript
|
||||
// 启用反向擦除模式
|
||||
eraserBrush.inverted = true;
|
||||
|
||||
// 监听擦除事件
|
||||
canvas.on('erasing:start', () => {
|
||||
console.log('开始擦除');
|
||||
});
|
||||
|
||||
canvas.on('erasing:end', (e) => {
|
||||
console.log('擦除完成', e.targets);
|
||||
});
|
||||
```
|
||||
|
||||
## 性能优势
|
||||
|
||||
1. **内置优化**: 库已经进行了性能优化,避免重复计算
|
||||
2. **事件驱动**: 基于事件的架构,响应更快
|
||||
3. **选择性渲染**: 只重新渲染需要更新的部分
|
||||
4. **内存效率**: 合理的对象管理和清理机制
|
||||
|
||||
## 兼容性说明
|
||||
|
||||
- 完全兼容标准的 fabric.js API
|
||||
- 新增的 `erasable` 属性不会影响现有功能
|
||||
- 可以逐步迁移现有代码
|
||||
|
||||
## 建议
|
||||
|
||||
1. **简化现有实现**: 移除手动的图层检查逻辑,直接使用 `erasable` 属性
|
||||
2. **利用内置事件**: 使用库提供的擦除事件进行状态管理
|
||||
3. **测试反向擦除**: 尝试使用 `inverted` 属性实现撤销功能
|
||||
4. **性能测试**: 在大量对象的场景下测试性能表现
|
||||
|
||||
通过这些优化,你的项目可以获得更好的性能和更简洁的代码结构。
|
||||
280
src/component/Canvas/CanvasEditor/managers/brushes/README.md
Normal file
280
src/component/Canvas/CanvasEditor/managers/brushes/README.md
Normal file
@@ -0,0 +1,280 @@
|
||||
<!-- https://github.com/tennisonchan/fabric-brush?tab=readme-ov-file -->
|
||||
<!-- eraser_brush:https://unpkg.com/fabric@5.5.2/src/mixins/eraser_brush.mixin.js -->
|
||||
# 笔刷系统使用指南
|
||||
|
||||
## 概述
|
||||
|
||||
这是一个基于插件架构的笔刷系统,允许轻松扩展和添加新的笔刷类型。整个系统由以下几个关键部分组成:
|
||||
|
||||
1. `BaseBrush` - 所有笔刷的基类
|
||||
2. `BrushRegistry` - 笔刷注册表,用于管理所有笔刷
|
||||
3. `BrushManager` - 笔刷管理器,处理笔刷的实例化和切换
|
||||
4. `BrushStore` - 笔刷状态存储
|
||||
|
||||
## 如何添加新笔刷
|
||||
|
||||
添加新笔刷只需简单几步:
|
||||
|
||||
### 1. 创建新的笔刷类
|
||||
|
||||
最简单的方法是继承 `BaseBrush` 类。在 `types` 目录下创建你的笔刷文件:
|
||||
|
||||
```javascript
|
||||
import { BaseBrush } from '../BaseBrush';
|
||||
|
||||
/**
|
||||
* 我的自定义笔刷
|
||||
*/
|
||||
export class MyCustomBrush extends BaseBrush {
|
||||
constructor(canvas, options = {}) {
|
||||
super(canvas, {
|
||||
id: 'my-custom-brush',
|
||||
name: '我的笔刷',
|
||||
description: '这是我自定义的笔刷',
|
||||
category: '自定义笔刷',
|
||||
...options
|
||||
});
|
||||
}
|
||||
|
||||
// 创建笔刷实例
|
||||
create() {
|
||||
// 创建底层fabric.js笔刷
|
||||
this.brush = new fabric.PencilBrush(this.canvas);
|
||||
// 配置笔刷
|
||||
this.configure(this.brush, this.options);
|
||||
return this.brush;
|
||||
}
|
||||
|
||||
// 配置笔刷
|
||||
configure(brush, options = {}) {
|
||||
// 设置基本属性
|
||||
if (options.color) brush.color = options.color;
|
||||
if (options.width !== undefined) brush.width = options.width;
|
||||
if (options.opacity !== undefined) brush.opacity = options.opacity;
|
||||
|
||||
// 设置自定义属性
|
||||
brush.strokeLineCap = 'round';
|
||||
brush.strokeLineJoin = 'round';
|
||||
// ...更多自定义设置
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 注册笔刷
|
||||
|
||||
有两种方式注册笔刷:
|
||||
|
||||
#### 方式一:使用BrushRegistry直接注册
|
||||
|
||||
```javascript
|
||||
import { brushRegistry } from '../BrushRegistry';
|
||||
import { MyCustomBrush } from './MyCustomBrush';
|
||||
|
||||
// 注册笔刷
|
||||
brushRegistry.register('my-custom-brush', MyCustomBrush, {
|
||||
name: '我的笔刷',
|
||||
description: '这是我自定义的笔刷',
|
||||
category: '自定义笔刷'
|
||||
});
|
||||
```
|
||||
|
||||
#### 方式二:通过BrushManager注册
|
||||
|
||||
```javascript
|
||||
import { BrushManager } from '../brushManager';
|
||||
import { MyCustomBrush } from './MyCustomBrush';
|
||||
|
||||
// 获取BrushManager实例
|
||||
const brushManager = new BrushManager({ canvas });
|
||||
|
||||
// 注册笔刷
|
||||
brushManager.registerBrush('my-custom-brush', MyCustomBrush, {
|
||||
name: '我的笔刷',
|
||||
description: '这是我自定义的笔刷',
|
||||
category: '自定义笔刷'
|
||||
});
|
||||
```
|
||||
|
||||
### 3. 使用笔刷
|
||||
|
||||
注册笔刷后,可以在应用中使用它:
|
||||
|
||||
```javascript
|
||||
// 切换到你的自定义笔刷
|
||||
brushManager.setBrushType('my-custom-brush');
|
||||
```
|
||||
|
||||
## 笔刷生命周期
|
||||
|
||||
每个笔刷有以下生命周期方法:
|
||||
|
||||
1. `constructor` - 创建笔刷类实例
|
||||
2. `create` - 创建底层fabric.js笔刷实例
|
||||
3. `configure` - 配置笔刷属性
|
||||
4. `onSelected` - 笔刷被选中时调用
|
||||
5. `onDeselected` - 笔刷被取消选中时调用
|
||||
6. `destroy` - 销毁笔刷实例释放资源
|
||||
|
||||
## 示例:创建具有独特行为的笔刷
|
||||
|
||||
这个例子创建了一个"脉冲笔刷",线条宽度会自动脉动变化:
|
||||
|
||||
```javascript
|
||||
import { BaseBrush } from '../BaseBrush';
|
||||
|
||||
export class PulseBrush extends BaseBrush {
|
||||
constructor(canvas, options = {}) {
|
||||
super(canvas, {
|
||||
id: 'pulse',
|
||||
name: '脉动笔刷',
|
||||
description: '线条宽度会自动脉动变化',
|
||||
category: '特效笔刷',
|
||||
...options
|
||||
});
|
||||
|
||||
this.originalWidth = options.width || 5;
|
||||
this.pulseRate = options.pulseRate || 0.1;
|
||||
this.pulseAmount = options.pulseAmount || 3;
|
||||
this.pulseTimer = null;
|
||||
}
|
||||
|
||||
create() {
|
||||
this.brush = new fabric.PencilBrush(this.canvas);
|
||||
this.configure(this.brush, this.options);
|
||||
|
||||
// 覆盖鼠标按下方法,开始脉冲效果
|
||||
const originalMouseDown = this.brush.onMouseDown;
|
||||
this.brush.onMouseDown = (pointer, options) => {
|
||||
this.startPulse();
|
||||
return originalMouseDown.call(this.brush, pointer, options);
|
||||
};
|
||||
|
||||
// 覆盖鼠标松开方法,停止脉冲效果
|
||||
const originalMouseUp = this.brush.onMouseUp;
|
||||
this.brush.onMouseUp = (options) => {
|
||||
this.stopPulse();
|
||||
return originalMouseUp.call(this.brush, options);
|
||||
};
|
||||
|
||||
return this.brush;
|
||||
}
|
||||
|
||||
configure(brush, options = {}) {
|
||||
if (options.width !== undefined) {
|
||||
this.originalWidth = options.width;
|
||||
brush.width = this.originalWidth;
|
||||
}
|
||||
|
||||
if (options.color) {
|
||||
brush.color = options.color;
|
||||
}
|
||||
|
||||
if (options.opacity !== undefined) {
|
||||
brush.opacity = options.opacity;
|
||||
}
|
||||
|
||||
if (options.pulseRate !== undefined) {
|
||||
this.pulseRate = options.pulseRate;
|
||||
}
|
||||
|
||||
if (options.pulseAmount !== undefined) {
|
||||
this.pulseAmount = options.pulseAmount;
|
||||
}
|
||||
}
|
||||
|
||||
startPulse() {
|
||||
this.stopPulse();
|
||||
|
||||
let phase = 0;
|
||||
this.pulseTimer = setInterval(() => {
|
||||
phase += this.pulseRate;
|
||||
const pulseFactor = Math.sin(phase) * this.pulseAmount;
|
||||
|
||||
if (this.brush) {
|
||||
this.brush.width = Math.max(1, this.originalWidth + pulseFactor);
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
|
||||
stopPulse() {
|
||||
if (this.pulseTimer) {
|
||||
clearInterval(this.pulseTimer);
|
||||
this.pulseTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
onDeselected() {
|
||||
this.stopPulse();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.stopPulse();
|
||||
super.destroy();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 使用预设笔刷类型
|
||||
|
||||
系统内置了几种笔刷类型,可以直接使用:
|
||||
|
||||
- `pencil` - 基础铅笔笔刷
|
||||
- `spray` - 喷枪笔刷
|
||||
- `marker` - 马克笔笔刷
|
||||
- `eraser` - 橡皮擦笔刷
|
||||
- `texture` - 材质笔刷
|
||||
- `watercolor` - 水彩笔刷
|
||||
- `chalk` - 粉笔笔刷
|
||||
|
||||
## 高级功能
|
||||
|
||||
### 1. 使用分类组织笔刷
|
||||
|
||||
注册笔刷时可以指定类别,便于在UI中分组展示:
|
||||
|
||||
```javascript
|
||||
brushRegistry.register('my-brush', MyBrushClass, {
|
||||
category: '艺术笔刷'
|
||||
});
|
||||
```
|
||||
|
||||
### 2. 自定义笔刷参数
|
||||
|
||||
可以为笔刷添加特殊参数,例如:
|
||||
|
||||
```javascript
|
||||
// 笔刷类中
|
||||
setGlowIntensity(intensity) {
|
||||
this.glowIntensity = intensity;
|
||||
// 更新笔刷效果
|
||||
}
|
||||
|
||||
// 使用时
|
||||
const neonBrush = brushManager.setBrushType('neon');
|
||||
if (neonBrush && typeof neonBrush.setGlowIntensity === 'function') {
|
||||
neonBrush.setGlowIntensity(15);
|
||||
}
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 如何创建复杂的自定义笔刷效果?
|
||||
|
||||
对于复杂的效果,可以:
|
||||
|
||||
1. 覆盖fabric.js笔刷的关键方法,如`onMouseMove`
|
||||
2. 使用自定义渲染器处理绘制
|
||||
3. 结合Canvas API创建特殊效果
|
||||
|
||||
### 如何获取所有注册的笔刷?
|
||||
|
||||
```javascript
|
||||
// 获取所有笔刷
|
||||
const allBrushes = brushRegistry.getAllBrushes();
|
||||
|
||||
// 获取所有分类
|
||||
const categories = brushRegistry.getCategories();
|
||||
|
||||
// 获取指定分类的笔刷
|
||||
const artisticBrushes = brushRegistry.getBrushesByCategory('艺术笔刷');
|
||||
```
|
||||
@@ -76,7 +76,7 @@ export class BrushManager {
|
||||
category: "基础笔刷",
|
||||
});
|
||||
brushRegistry.register("fur", FurBrush, {
|
||||
name: "Texture",
|
||||
name: "Fur",
|
||||
description: "使用纹理图片作为笔刷,支持缩放和透明度",
|
||||
category: "基础笔刷",
|
||||
});
|
||||
|
||||
@@ -12,12 +12,11 @@
|
||||
* - https://mrdoob.com/projects/harmony/
|
||||
* - http://perfectionkills.com/exploring-canvas-drawing-techniques/
|
||||
*/
|
||||
import { fabric } from "fabric-with-all";
|
||||
import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
|
||||
|
||||
(function (fabric) {
|
||||
/**
|
||||
* Trim a canvas. Returns the lezft-top coordinate where trimming began.
|
||||
* Trim a canvas. Returns the left-top coordinate where trimming began.
|
||||
* @param {canvas} canvas A canvas element to trim. This element will be trimmed (reference).
|
||||
* @returns {Object} Left-top coordinate of trimmed area. Example: {x:65, y:104}
|
||||
* @see: https://stackoverflow.com/a/22267731/3360038
|
||||
@@ -1744,5 +1743,4 @@ import { sprayBrushDataUrl } from "./data/sprayBrushData.js";
|
||||
|
||||
_render: function () {},
|
||||
}); // End WebBrush
|
||||
})(fabric);
|
||||
// })(typeof fabric !== "undefined" ? fabric : require("fabric").fabric);
|
||||
})(typeof fabric !== "undefined" ? fabric : require("fabric").fabric);
|
||||
|
||||
Reference in New Issue
Block a user