feat: 添加笔刷指示器功能,支持动态显示当前笔刷大小和颜色;更新图层可擦除状态逻辑
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
|||||||
provide,
|
provide,
|
||||||
defineExpose,
|
defineExpose,
|
||||||
nextTick,
|
nextTick,
|
||||||
|
watchEffect,
|
||||||
} from "vue";
|
} from "vue";
|
||||||
import { CanvasManager } from "./managers/CanvasManager";
|
import { CanvasManager } from "./managers/CanvasManager";
|
||||||
import { LayerManager } from "./managers/LayerManager";
|
import { LayerManager } from "./managers/LayerManager";
|
||||||
@@ -76,6 +77,14 @@ const props = defineProps({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
isFixedErasable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false, // 是否允许擦除固定图层
|
||||||
|
},
|
||||||
|
isBackgroundErasable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false, // 是否允许擦除背景图层
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 引用和状态
|
// 引用和状态
|
||||||
@@ -344,6 +353,32 @@ onMounted(async () => {
|
|||||||
canvasManager.canvas.height
|
canvasManager.canvas.height
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// // 设置固定图层是否可擦除
|
||||||
|
// canvasManager.setFixedLayerErasable({
|
||||||
|
// type: "isFixed",
|
||||||
|
// flag: !props.isFixedErasable, // 设置操作类型为可擦除
|
||||||
|
// });
|
||||||
|
// // 设置背景图层是否可擦除
|
||||||
|
// canvasManager.setFixedLayerErasable({
|
||||||
|
// type: "isBackground",
|
||||||
|
// flag: !props.isBackgroundErasable, // 设置操作类型为可擦除
|
||||||
|
// });
|
||||||
|
});
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
// 设置固定图层是否可擦除
|
||||||
|
if (canvasManagerLoaded.value) {
|
||||||
|
canvasManager?.setFixedLayerErasable({
|
||||||
|
type: "isFixed",
|
||||||
|
flag: !props.isFixedErasable, // 设置操作类型为可擦除
|
||||||
|
});
|
||||||
|
// 设置背景图层是否可擦除
|
||||||
|
canvasManager?.setFixedLayerErasable({
|
||||||
|
type: "isBackground",
|
||||||
|
flag: !props.isBackgroundErasable, // 设置操作类型为可擦除
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
@@ -640,7 +675,15 @@ const changeCanvas = (command) => {
|
|||||||
|
|
||||||
// 提供外部ref实例方法
|
// 提供外部ref实例方法
|
||||||
defineExpose({
|
defineExpose({
|
||||||
|
layers, // 图层数据
|
||||||
getCanvasManager: () => canvasManager, // 获取画布管理器实例
|
getCanvasManager: () => canvasManager, // 获取画布管理器实例
|
||||||
|
// type : isBackground isFixed flag: 是否可擦除图层
|
||||||
|
setFixedLayerErasable: ({ type = "isFixed", flag = false }) => {
|
||||||
|
canvasManager?.setFixedLayerErasable({
|
||||||
|
type,
|
||||||
|
flag, // 设置操作类型为可擦除
|
||||||
|
});
|
||||||
|
}, // 获取fabric画布实例
|
||||||
canvasManagerLoaded,
|
canvasManagerLoaded,
|
||||||
// 加载新数据到画布
|
// 加载新数据到画布
|
||||||
loadJSON: (json, calllBack) => {
|
loadJSON: (json, calllBack) => {
|
||||||
|
|||||||
483
src/component/Canvas/CanvasEditor/managers/BrushIndicator.js
Normal file
483
src/component/Canvas/CanvasEditor/managers/BrushIndicator.js
Normal file
@@ -0,0 +1,483 @@
|
|||||||
|
import { fabric } from "fabric-with-all";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 笔刷指示器
|
||||||
|
* 在画笔模式下显示当前笔刷大小的圆圈指示器
|
||||||
|
*/
|
||||||
|
export class BrushIndicator {
|
||||||
|
/**
|
||||||
|
* 构造函数
|
||||||
|
* @param {Object} canvas fabric.js画布实例
|
||||||
|
* @param {Object} options 配置选项
|
||||||
|
*/
|
||||||
|
constructor(canvas, options = {}) {
|
||||||
|
this.canvas = canvas;
|
||||||
|
this.options = {
|
||||||
|
strokeColor: options.strokeColor || "rgba(0, 0, 0, 0.5)",
|
||||||
|
strokeWidth: options.strokeWidth || 1,
|
||||||
|
fillColor: options.fillColor || "rgba(0, 0, 0, 0.1)",
|
||||||
|
...options,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 指示器圆圈对象
|
||||||
|
this.indicator = null;
|
||||||
|
|
||||||
|
// 事件处理器
|
||||||
|
this._mouseEnterHandler = null;
|
||||||
|
this._mouseLeaveHandler = null;
|
||||||
|
this._mouseMoveHandler = null;
|
||||||
|
|
||||||
|
// 当前状态
|
||||||
|
this.isVisible = false;
|
||||||
|
this.currentSize = 10;
|
||||||
|
this.isEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启用笔刷指示器
|
||||||
|
* @param {Number} brushSize 笔刷大小
|
||||||
|
*/
|
||||||
|
enable(brushSize) {
|
||||||
|
if (this.isEnabled) return;
|
||||||
|
|
||||||
|
this.isEnabled = true;
|
||||||
|
this.currentSize = brushSize;
|
||||||
|
|
||||||
|
// 绑定事件
|
||||||
|
this._bindEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 禁用笔刷指示器
|
||||||
|
*/
|
||||||
|
disable() {
|
||||||
|
if (!this.isEnabled) return;
|
||||||
|
|
||||||
|
this.isEnabled = false;
|
||||||
|
|
||||||
|
// 隐藏指示器
|
||||||
|
this.hide();
|
||||||
|
|
||||||
|
// 重置颜色配置为默认值
|
||||||
|
this.options.strokeColor = "";
|
||||||
|
this.options.fillColor = "";
|
||||||
|
|
||||||
|
// 解绑事件
|
||||||
|
this._unbindEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新笔刷大小
|
||||||
|
* @param {Number} size 新的笔刷大小
|
||||||
|
*/
|
||||||
|
updateSize(size) {
|
||||||
|
this.currentSize = size;
|
||||||
|
|
||||||
|
// 如果指示器正在显示,更新其大小
|
||||||
|
if (this.isVisible && this.indicator) {
|
||||||
|
this._updateIndicatorSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新指示器颜色
|
||||||
|
* @param {String} color 新的颜色值
|
||||||
|
*/
|
||||||
|
updateColor(color) {
|
||||||
|
// 更新配置选项中的颜色
|
||||||
|
if (color) {
|
||||||
|
this.options.strokeColor = color;
|
||||||
|
// 将颜色转换为半透明填充色
|
||||||
|
// this.options.fillColor = this._convertToTransparentFill(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果指示器正在显示,更新其颜色
|
||||||
|
if (this.isVisible && this.indicator) {
|
||||||
|
this.indicator.set({
|
||||||
|
stroke: this.options.strokeColor,
|
||||||
|
fill: this.options.fillColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 重新渲染画布
|
||||||
|
this.canvas.requestRenderAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示指示器
|
||||||
|
* @param {Object} pointer 鼠标位置
|
||||||
|
*/
|
||||||
|
show(pointer) {
|
||||||
|
if (!this.isEnabled || this.isVisible) return;
|
||||||
|
|
||||||
|
this.isVisible = true;
|
||||||
|
|
||||||
|
// 创建指示器圆圈
|
||||||
|
this._createIndicator(pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 隐藏指示器
|
||||||
|
*/
|
||||||
|
hide() {
|
||||||
|
if (!this.isVisible || !this.indicator) return;
|
||||||
|
|
||||||
|
this.isVisible = false;
|
||||||
|
|
||||||
|
// 从画布移除指示器
|
||||||
|
this.canvas.remove(this.indicator);
|
||||||
|
this.indicator = null;
|
||||||
|
|
||||||
|
// 重新渲染画布
|
||||||
|
this.canvas.renderAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新指示器位置
|
||||||
|
* @param {Object} pointer 鼠标位置
|
||||||
|
*/
|
||||||
|
updatePosition(pointer) {
|
||||||
|
if (!this.isVisible || !this.indicator) return;
|
||||||
|
|
||||||
|
// 转换坐标考虑画布变换
|
||||||
|
const canvasPointer = this.canvas.getPointer(pointer);
|
||||||
|
|
||||||
|
// 批量更新位置属性
|
||||||
|
this.indicator.set({
|
||||||
|
left: canvasPointer.x,
|
||||||
|
top: canvasPointer.y,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 更新坐标系
|
||||||
|
this.indicator.setCoords();
|
||||||
|
|
||||||
|
// 使用requestRenderAll优化渲染性能
|
||||||
|
this.canvas.requestRenderAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定事件处理器
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_bindEvents() {
|
||||||
|
if (!this.canvas) return;
|
||||||
|
|
||||||
|
// 鼠标进入画布
|
||||||
|
this._mouseEnterHandler = (e) => {
|
||||||
|
// 只在画笔相关模式下显示
|
||||||
|
if (this._shouldShowIndicator()) {
|
||||||
|
this.show(e.e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 鼠标离开画布
|
||||||
|
this._mouseLeaveHandler = () => {
|
||||||
|
this.hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 鼠标在画布上移动 - 修改事件处理逻辑
|
||||||
|
this._mouseMoveHandler = (e) => {
|
||||||
|
// 如果正在绘图,不处理指示器更新,避免干扰绘图
|
||||||
|
if (this.canvas._isCurrentlyDrawing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._shouldShowIndicator()) {
|
||||||
|
if (!this.isVisible) {
|
||||||
|
this.show(e.e);
|
||||||
|
} else {
|
||||||
|
this.updatePosition(e.e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.hide();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听绘图开始事件,隐藏指示器并模拟微小移动
|
||||||
|
this._drawingStartHandler = (e) => {
|
||||||
|
if (this.isVisible) {
|
||||||
|
this.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模拟1px的微小移动来确保笔刷能正常启动绘画
|
||||||
|
this._simulateTinyMovement(e);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听绘图结束事件,重新显示指示器
|
||||||
|
this._drawingEndHandler = () => {
|
||||||
|
// 延迟一点重新显示,确保绘图完全结束
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this._shouldShowIndicator() && !this.isVisible) {
|
||||||
|
// 重新检查鼠标位置并显示指示器
|
||||||
|
this._checkAndShowIndicator();
|
||||||
|
}
|
||||||
|
}, 50);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 画布缩放变化处理器
|
||||||
|
this._zoomHandler = () => {
|
||||||
|
if (this.isVisible && this.indicator) {
|
||||||
|
// 立即更新指示器大小
|
||||||
|
this._updateIndicatorSize();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 画布视口变化处理器
|
||||||
|
this._viewportHandler = () => {
|
||||||
|
if (this.isVisible && this.indicator) {
|
||||||
|
// 视口变化时也需要更新指示器
|
||||||
|
this._updateIndicatorSize();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 绑定事件
|
||||||
|
this.canvas.on("mouse:over", this._mouseEnterHandler);
|
||||||
|
this.canvas.on("mouse:out", this._mouseLeaveHandler);
|
||||||
|
this.canvas.on("mouse:move", this._mouseMoveHandler);
|
||||||
|
|
||||||
|
// 监听绘图状态变化
|
||||||
|
this.canvas.on("path:created", this._drawingEndHandler);
|
||||||
|
this.canvas.on("mouse:down", this._drawingStartHandler);
|
||||||
|
this.canvas.on("mouse:up", this._drawingEndHandler);
|
||||||
|
|
||||||
|
// 监听画布缩放和视口变化
|
||||||
|
this.canvas.on("after:render", this._zoomHandler);
|
||||||
|
this.canvas.on("canvas:zoomed", this._zoomHandler);
|
||||||
|
this.canvas.on("viewport:changed", this._viewportHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解绑事件处理器
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_unbindEvents() {
|
||||||
|
if (!this.canvas) return;
|
||||||
|
|
||||||
|
if (this._mouseEnterHandler) {
|
||||||
|
this.canvas.off("mouse:over", this._mouseEnterHandler);
|
||||||
|
this._mouseEnterHandler = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._mouseLeaveHandler) {
|
||||||
|
this.canvas.off("mouse:out", this._mouseLeaveHandler);
|
||||||
|
this._mouseLeaveHandler = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._mouseMoveHandler) {
|
||||||
|
this.canvas.off("mouse:move", this._mouseMoveHandler);
|
||||||
|
this._mouseMoveHandler = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理绘图相关事件
|
||||||
|
if (this._drawingStartHandler) {
|
||||||
|
this.canvas.off("mouse:down", this._drawingStartHandler);
|
||||||
|
this.canvas.off("path:created", this._drawingEndHandler);
|
||||||
|
this.canvas.off("mouse:up", this._drawingEndHandler);
|
||||||
|
this._drawingStartHandler = null;
|
||||||
|
this._drawingEndHandler = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理缩放相关事件
|
||||||
|
if (this._zoomHandler) {
|
||||||
|
this.canvas.off("after:render", this._zoomHandler);
|
||||||
|
this.canvas.off("canvas:zoomed", this._zoomHandler);
|
||||||
|
this._zoomHandler = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._viewportHandler) {
|
||||||
|
this.canvas.off("viewport:changed", this._viewportHandler);
|
||||||
|
this._viewportHandler = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建指示器圆圈
|
||||||
|
* @private
|
||||||
|
* @param {Object} pointer 鼠标位置
|
||||||
|
*/
|
||||||
|
_createIndicator(pointer) {
|
||||||
|
// 转换坐标考虑画布变换
|
||||||
|
const canvasPointer = this.canvas.getPointer(pointer);
|
||||||
|
|
||||||
|
// 计算考虑画布缩放的半径
|
||||||
|
const radius = this._getIndicatorRadius();
|
||||||
|
|
||||||
|
// 创建圆圈
|
||||||
|
this.indicator = new fabric.Circle({
|
||||||
|
left: canvasPointer.x,
|
||||||
|
top: canvasPointer.y,
|
||||||
|
radius: radius,
|
||||||
|
fill: this.options.fillColor,
|
||||||
|
stroke: this.options.strokeColor,
|
||||||
|
strokeWidth: this.options.strokeWidth / this.canvas.getZoom(), // 线宽不受缩放影响
|
||||||
|
originX: "center",
|
||||||
|
originY: "center",
|
||||||
|
selectable: false,
|
||||||
|
evented: false,
|
||||||
|
excludeFromExport: true, // 导出时排除
|
||||||
|
isTemp: true, // 标记为临时对象
|
||||||
|
pointer: true, // 标记为鼠标指示器
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加到画布
|
||||||
|
this.canvas.add(this.indicator);
|
||||||
|
|
||||||
|
// 确保指示器在最顶层
|
||||||
|
this.canvas.bringToFront(this.indicator);
|
||||||
|
|
||||||
|
// 重新渲染画布
|
||||||
|
this.canvas.renderAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新指示器大小
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_updateIndicatorSize() {
|
||||||
|
if (!this.indicator) return;
|
||||||
|
|
||||||
|
// 获取当前画布缩放比例
|
||||||
|
const zoom = this.canvas.getZoom();
|
||||||
|
const radius = this._getIndicatorRadius();
|
||||||
|
const strokeWidth = this.options.strokeWidth / zoom;
|
||||||
|
|
||||||
|
// 批量更新属性,减少重绘次数
|
||||||
|
this.indicator.set({
|
||||||
|
radius: radius,
|
||||||
|
strokeWidth: strokeWidth,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 标记指示器需要重绘
|
||||||
|
this.indicator.setCoords();
|
||||||
|
|
||||||
|
// 重新渲染画布
|
||||||
|
this.canvas.requestRenderAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指示器半径(与笔刷实际绘制大小一致)
|
||||||
|
* @private
|
||||||
|
* @returns {Number} 半径值
|
||||||
|
*/
|
||||||
|
_getIndicatorRadius() {
|
||||||
|
// 指示器大小应该与笔刷实际绘制大小一致
|
||||||
|
// 笔刷的实际绘制大小不受画布缩放影响,所以指示器也不应该受缩放影响
|
||||||
|
return this.currentSize / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否应该显示指示器
|
||||||
|
* @private
|
||||||
|
* @returns {Boolean} 是否显示
|
||||||
|
*/
|
||||||
|
_shouldShowIndicator() {
|
||||||
|
// 检查画布是否在绘图模式
|
||||||
|
if (!this.canvas.isDrawingMode) return false;
|
||||||
|
|
||||||
|
// 检查是否有笔刷
|
||||||
|
if (!this.canvas.freeDrawingBrush) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查并显示指示器(如果鼠标在画布内)
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_checkAndShowIndicator() {
|
||||||
|
// 这个方法用于在绘图结束后重新显示指示器
|
||||||
|
// 由于无法直接获取当前鼠标位置,我们依赖下一次鼠标移动事件
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模拟微小移动
|
||||||
|
* @private
|
||||||
|
* @param {Object} e 鼠标事件对象
|
||||||
|
*/
|
||||||
|
_simulateTinyMovement(e) {
|
||||||
|
// 获取当前鼠标位置
|
||||||
|
const pointer = this.canvas.getPointer(e.e);
|
||||||
|
|
||||||
|
// 模拟移动1px
|
||||||
|
this.canvas.fire("mouse:move", {
|
||||||
|
...e,
|
||||||
|
e: {
|
||||||
|
...e.e,
|
||||||
|
clientX: pointer.x + 1,
|
||||||
|
clientY: pointer.y + 1,
|
||||||
|
pointer: {
|
||||||
|
x: pointer.x + 1,
|
||||||
|
y: pointer.y + 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 再模拟移动回原位置
|
||||||
|
this.canvas.fire("mouse:move", {
|
||||||
|
...e,
|
||||||
|
e: {
|
||||||
|
...e.e,
|
||||||
|
clientX: pointer.x,
|
||||||
|
clientY: pointer.y,
|
||||||
|
pointer: {
|
||||||
|
x: pointer.x,
|
||||||
|
y: pointer.y,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 销毁指示器
|
||||||
|
*/
|
||||||
|
dispose() {
|
||||||
|
this.disable();
|
||||||
|
this.canvas = null;
|
||||||
|
this.indicator = null;
|
||||||
|
this.options = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将颜色转换为半透明填充色
|
||||||
|
* @private
|
||||||
|
* @param {String} color 原始颜色值
|
||||||
|
* @returns {String} 半透明填充色
|
||||||
|
*/
|
||||||
|
_convertToTransparentFill(color) {
|
||||||
|
// 如果已经是 rgba 格式,直接使用但降低透明度
|
||||||
|
if (color.startsWith("rgba")) {
|
||||||
|
return color.replace(/[\d\.]+\)$/, "0.1)");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是 rgb 格式,转换为 rgba
|
||||||
|
if (color.startsWith("rgb")) {
|
||||||
|
return color.replace("rgb", "rgba").replace(")", ", 0.1)");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是十六进制格式,转换为 rgba
|
||||||
|
if (color.startsWith("#")) {
|
||||||
|
const hex = color.slice(1);
|
||||||
|
let r, g, b;
|
||||||
|
|
||||||
|
if (hex.length === 3) {
|
||||||
|
// 处理 #RGB 格式
|
||||||
|
r = parseInt(hex[0] + hex[0], 16);
|
||||||
|
g = parseInt(hex[1] + hex[1], 16);
|
||||||
|
b = parseInt(hex[2] + hex[2], 16);
|
||||||
|
} else if (hex.length === 6) {
|
||||||
|
// 处理 #RRGGBB 格式
|
||||||
|
r = parseInt(hex.slice(0, 2), 16);
|
||||||
|
g = parseInt(hex.slice(2, 4), 16);
|
||||||
|
b = parseInt(hex.slice(4, 6), 16);
|
||||||
|
} else {
|
||||||
|
// 无法解析的格式,返回默认半透明黑色
|
||||||
|
return "rgba(0, 0, 0, 0.1)";
|
||||||
|
}
|
||||||
|
|
||||||
|
return `rgba(${r}, ${g}, ${b}, 0.1)`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理命名颜色或其他格式,使用默认半透明效果
|
||||||
|
return "rgba(0, 0, 0, 0.1)";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -328,6 +328,26 @@ export class CanvasManager {
|
|||||||
this.canvas.renderAll();
|
this.canvas.renderAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置固定图层可擦除状态
|
||||||
|
setFixedLayerErasable({ type = "isFixed", flag = false }) {
|
||||||
|
const layer = this.layers.value.find((layer) => layer[type]);
|
||||||
|
if (layer) {
|
||||||
|
// 设置固定图层的可擦除状态
|
||||||
|
layer.locked = flag;
|
||||||
|
// 更新画布对象的erasable属性
|
||||||
|
const fabricObject = this.canvas
|
||||||
|
.getObjects()
|
||||||
|
.find((obj) => obj.id === layer.id);
|
||||||
|
if (fabricObject) {
|
||||||
|
fabricObject.erasable = flag;
|
||||||
|
fabricObject.set("erasable", flag);
|
||||||
|
fabricObject.setCoords(); // 更新控制点坐标
|
||||||
|
this.canvas.renderAll(); // 重新渲染画布
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setCanvasSize(width, height) {
|
setCanvasSize(width, height) {
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
|
|||||||
@@ -225,10 +225,11 @@ export class LayerManager {
|
|||||||
|
|
||||||
// 图层状态决定交互性
|
// 图层状态决定交互性
|
||||||
if (layer.isBackground || obj.isBackground || layer.isFixed) {
|
if (layer.isBackground || obj.isBackground || layer.isFixed) {
|
||||||
|
//|| layer.isFixed
|
||||||
// 背景层永远不可选择和擦除
|
// 背景层永远不可选择和擦除
|
||||||
obj.selectable = false;
|
obj.selectable = false;
|
||||||
obj.evented = false;
|
obj.evented = false;
|
||||||
obj.erasable = false;
|
obj.erasable = !layer.locked;
|
||||||
} else if (layer.locked) {
|
} else if (layer.locked) {
|
||||||
// 锁定图层不可交互和擦除
|
// 锁定图层不可交互和擦除
|
||||||
obj.selectable = false;
|
obj.selectable = false;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { BrushStore } from "../store/BrushStore";
|
import { BrushStore } from "../store/BrushStore";
|
||||||
import { BrushManager } from "./brushes/brushManager";
|
import { BrushManager } from "./brushes/brushManager";
|
||||||
|
import { BrushIndicator } from "./BrushIndicator";
|
||||||
import { ToolCommand } from "../commands/ToolCommands";
|
import { ToolCommand } from "../commands/ToolCommands";
|
||||||
import { CreateTextCommand } from "../commands/TextCommands";
|
import { CreateTextCommand } from "../commands/TextCommands";
|
||||||
import { OperationType } from "../utils/layerHelper";
|
import { OperationType } from "../utils/layerHelper";
|
||||||
@@ -47,6 +48,16 @@ export class ToolManager {
|
|||||||
layerManager: this.layerManager, // 传入图层管理器引用
|
layerManager: this.layerManager, // 传入图层管理器引用
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 初始化笔刷指示器
|
||||||
|
this.brushIndicator = null;
|
||||||
|
if (this.canvas) {
|
||||||
|
this.brushIndicator = new BrushIndicator(this.canvas, {
|
||||||
|
strokeColor: "rgba(0, 0, 0, 0.6)",
|
||||||
|
strokeWidth: 1,
|
||||||
|
fillColor: "rgba(0, 0, 0, 0.1)",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 观察者列表
|
// 观察者列表
|
||||||
this.observers = [];
|
this.observers = [];
|
||||||
|
|
||||||
@@ -337,6 +348,11 @@ export class ToolManager {
|
|||||||
// 保存先前的工具
|
// 保存先前的工具
|
||||||
this.previousTool = this.activeTool.value;
|
this.previousTool = this.activeTool.value;
|
||||||
|
|
||||||
|
// 如果切换到非画笔工具,禁用笔刷指示器
|
||||||
|
if (!this._shouldShowBrushIndicator(toolId)) {
|
||||||
|
this._disableBrushIndicator();
|
||||||
|
}
|
||||||
|
|
||||||
// 设置新工具
|
// 设置新工具
|
||||||
this.activeTool.value = toolId;
|
this.activeTool.value = toolId;
|
||||||
|
|
||||||
@@ -465,6 +481,9 @@ export class ToolManager {
|
|||||||
// 更新应用到画布
|
// 更新应用到画布
|
||||||
this.brushManager.updateBrush();
|
this.brushManager.updateBrush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 启用笔刷指示器并同步颜色
|
||||||
|
this._enableBrushIndicator();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -479,6 +498,9 @@ export class ToolManager {
|
|||||||
if (this.brushManager) {
|
if (this.brushManager) {
|
||||||
this.brushManager.createEraser();
|
this.brushManager.createEraser();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 启用笔刷指示器
|
||||||
|
this._enableBrushIndicator();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -953,6 +975,9 @@ export class ToolManager {
|
|||||||
|
|
||||||
// 更新应用到画布
|
// 更新应用到画布
|
||||||
this.brushManager.updateBrush();
|
this.brushManager.updateBrush();
|
||||||
|
|
||||||
|
// 更新笔刷指示器大小
|
||||||
|
this.updateBrushIndicatorSize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1046,6 +1071,9 @@ export class ToolManager {
|
|||||||
|
|
||||||
// 更新应用到画布
|
// 更新应用到画布
|
||||||
this.brushManager.updateBrush();
|
this.brushManager.updateBrush();
|
||||||
|
|
||||||
|
// 更新笔刷指示器颜色
|
||||||
|
this.updateBrushIndicatorColor(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1126,6 +1154,12 @@ export class ToolManager {
|
|||||||
this.brushManager.dispose();
|
this.brushManager.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 清理笔刷指示器
|
||||||
|
if (this.brushIndicator) {
|
||||||
|
this.brushIndicator.dispose();
|
||||||
|
this.brushIndicator = null;
|
||||||
|
}
|
||||||
|
|
||||||
// 移除文本编辑相关事件监听器
|
// 移除文本编辑相关事件监听器
|
||||||
if (this.canvas) {
|
if (this.canvas) {
|
||||||
this.canvas.off("mouse:dblclick", this._textEditHandler);
|
this.canvas.off("mouse:dblclick", this._textEditHandler);
|
||||||
@@ -1160,10 +1194,12 @@ export class ToolManager {
|
|||||||
this.canvas.isDrawingMode = true;
|
this.canvas.isDrawingMode = true;
|
||||||
this.canvas.selection = false;
|
this.canvas.selection = false;
|
||||||
|
|
||||||
|
const redColor = "#FF0000";
|
||||||
|
|
||||||
// 确保有笔刷管理器
|
// 确保有笔刷管理器
|
||||||
if (this.brushManager) {
|
if (this.brushManager) {
|
||||||
// 设置红色笔刷
|
// 设置红色笔刷
|
||||||
this.brushManager.setBrushColor("#FF0000"); // 纯红色
|
this.brushManager.setBrushColor(redColor); // 纯红色
|
||||||
this.brushManager.setBrushOpacity(1.0); // 完全不透明
|
this.brushManager.setBrushOpacity(1.0); // 完全不透明
|
||||||
this.brushManager.setBrushType("pencil"); // 铅笔类型
|
this.brushManager.setBrushType("pencil"); // 铅笔类型
|
||||||
|
|
||||||
@@ -1175,6 +1211,9 @@ export class ToolManager {
|
|||||||
// 更新应用到画布
|
// 更新应用到画布
|
||||||
this.brushManager.updateBrush();
|
this.brushManager.updateBrush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 启用笔刷指示器并设置红色
|
||||||
|
this._enableBrushIndicator(redColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1186,10 +1225,12 @@ export class ToolManager {
|
|||||||
this.canvas.isDrawingMode = true;
|
this.canvas.isDrawingMode = true;
|
||||||
this.canvas.selection = false;
|
this.canvas.selection = false;
|
||||||
|
|
||||||
|
const greenColor = "#00FF00";
|
||||||
|
|
||||||
// 确保有笔刷管理器
|
// 确保有笔刷管理器
|
||||||
if (this.brushManager) {
|
if (this.brushManager) {
|
||||||
// 设置绿色笔刷
|
// 设置绿色笔刷
|
||||||
this.brushManager.setBrushColor("#00FF00"); // 纯绿色
|
this.brushManager.setBrushColor(greenColor); // 纯绿色
|
||||||
this.brushManager.setBrushOpacity(1.0); // 完全不透明
|
this.brushManager.setBrushOpacity(1.0); // 完全不透明
|
||||||
this.brushManager.setBrushType("pencil"); // 铅笔类型
|
this.brushManager.setBrushType("pencil"); // 铅笔类型
|
||||||
|
|
||||||
@@ -1201,6 +1242,9 @@ export class ToolManager {
|
|||||||
// 更新应用到画布
|
// 更新应用到画布
|
||||||
this.brushManager.updateBrush();
|
this.brushManager.updateBrush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 启用笔刷指示器并设置绿色
|
||||||
|
this._enableBrushIndicator(greenColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1264,4 +1308,135 @@ export class ToolManager {
|
|||||||
const tool = this.tools[toolId];
|
const tool = this.tools[toolId];
|
||||||
return tool && tool.redGreenOnly === true;
|
return tool && tool.redGreenOnly === true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启用笔刷指示器
|
||||||
|
* @param {String} color 笔刷颜色(可选)
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_enableBrushIndicator(color) {
|
||||||
|
if (!this.brushIndicator) return;
|
||||||
|
|
||||||
|
// 获取当前笔刷大小
|
||||||
|
const brushSize = this._getCurrentBrushSize();
|
||||||
|
|
||||||
|
// 获取当前笔刷颜色
|
||||||
|
const brushColor = color || this._getCurrentBrushColor();
|
||||||
|
|
||||||
|
// 启用指示器
|
||||||
|
this.brushIndicator.enable(brushSize);
|
||||||
|
|
||||||
|
// 更新指示器颜色
|
||||||
|
this.brushIndicator.updateColor(brushColor);
|
||||||
|
|
||||||
|
console.log(`笔刷指示器已启用,大小: ${brushSize}, 颜色: ${brushColor}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 禁用笔刷指示器
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_disableBrushIndicator() {
|
||||||
|
if (!this.brushIndicator) return;
|
||||||
|
|
||||||
|
this.brushIndicator.disable();
|
||||||
|
console.log("笔刷指示器已禁用");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新笔刷指示器大小
|
||||||
|
* @param {Number} size 新的笔刷大小
|
||||||
|
*/
|
||||||
|
updateBrushIndicatorSize(size) {
|
||||||
|
if (!this.brushIndicator) return;
|
||||||
|
|
||||||
|
this.brushIndicator.updateSize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新笔刷指示器颜色
|
||||||
|
* @param {String} color 新的笔刷颜色
|
||||||
|
*/
|
||||||
|
updateBrushIndicatorColor(color) {
|
||||||
|
if (!this.brushIndicator) return;
|
||||||
|
|
||||||
|
this.brushIndicator.updateColor(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前笔刷大小
|
||||||
|
* @private
|
||||||
|
* @returns {Number} 当前笔刷大小
|
||||||
|
*/
|
||||||
|
_getCurrentBrushSize() {
|
||||||
|
// 优先从 BrushStore 获取
|
||||||
|
if (BrushStore && BrushStore.state.size) {
|
||||||
|
return BrushStore.state.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从笔刷管理器获取
|
||||||
|
if (this.brushManager && this.brushManager.getBrushSize) {
|
||||||
|
return this.brushManager.getBrushSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从画布笔刷获取
|
||||||
|
if (
|
||||||
|
this.canvas &&
|
||||||
|
this.canvas.freeDrawingBrush &&
|
||||||
|
this.canvas.freeDrawingBrush.width
|
||||||
|
) {
|
||||||
|
return this.canvas.freeDrawingBrush.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 默认值
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前笔刷颜色
|
||||||
|
* @private
|
||||||
|
* @returns {String} 当前笔刷颜色
|
||||||
|
*/
|
||||||
|
_getCurrentBrushColor() {
|
||||||
|
// 优先从 BrushStore 获取
|
||||||
|
if (BrushStore && BrushStore.state.color) {
|
||||||
|
return BrushStore.state.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从笔刷管理器获取
|
||||||
|
if (this.brushManager && this.brushManager.getBrushColor) {
|
||||||
|
return this.brushManager.getBrushColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从画布笔刷获取
|
||||||
|
if (
|
||||||
|
this.canvas &&
|
||||||
|
this.canvas.freeDrawingBrush &&
|
||||||
|
this.canvas.freeDrawingBrush.color
|
||||||
|
) {
|
||||||
|
return this.canvas.freeDrawingBrush.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 默认值
|
||||||
|
return "#000000";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查当前工具是否需要显示笔刷指示器
|
||||||
|
* @param {String} toolId 工具ID(可选,不传则使用当前工具)
|
||||||
|
* @returns {Boolean} 是否需要显示
|
||||||
|
*/
|
||||||
|
_shouldShowBrushIndicator(toolId) {
|
||||||
|
const currentTool = toolId || this.activeTool.value;
|
||||||
|
|
||||||
|
// 画笔相关工具需要显示指示器
|
||||||
|
const brushTools = [
|
||||||
|
OperationType.DRAW,
|
||||||
|
OperationType.ERASER,
|
||||||
|
OperationType.RED_BRUSH,
|
||||||
|
OperationType.GREEN_BRUSH,
|
||||||
|
];
|
||||||
|
|
||||||
|
return brushTools.includes(currentTool);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user