添加画布粘贴外部文字和图片

This commit is contained in:
李志鹏
2025-11-11 17:35:00 +08:00
parent 9c6dd126e0
commit e5fc07e5e3
9 changed files with 84 additions and 19 deletions

View File

@@ -321,6 +321,7 @@ export class CreateTextCommand extends Command {
this.x = options.x;
this.y = options.y;
this.textOptions = options.textOptions || {};
this.options = options;
// 生成唯一ID
this.textId = options?.textId || generateId("text_");
this.layerId = options?.layerId || generateId("text_layer_");
@@ -331,7 +332,7 @@ export class CreateTextCommand extends Command {
// 默认文本属性
this.defaultOptions = {
text: t('Canvas.DoubleClickText'),
text: options.text || t('Canvas.DoubleClickText'),
fontFamily: "Arial",
fontSize: 24,
fontWeight: "normal",
@@ -373,8 +374,8 @@ export class CreateTextCommand extends Command {
originY: "center",
});
// 创建文本图层
const layerName = this.textOptions.layerName || "文本图层";
// 创建文本图层 取15
const layerName = this.options.text?.substring(0, 25) || t('Canvas.TextLayer');
const layer = createLayer({
id: this.layerId,
name: layerName,

View File

@@ -619,10 +619,13 @@ export default {
onMounted(() => {
// 监听显示文本编辑面板事件
document.addEventListener("showTextEditor", showEditor);
document.addEventListener("hideTextEditor", close);
});
onUnmounted(() => {
document.removeEventListener("showTextEditor", showEditor);
document.removeEventListener("hideTextEditor", close);
});
// 返回所有需要在模板中使用的数据和方法

View File

@@ -303,6 +303,19 @@ onMounted(async () => {
commandManager,
layerManager,
toolManager,
pasteText: (text) => {
// console.log("粘贴的文本:", text);
handleAddText(text);
},
pasteImage: (file) => {
// console.log("粘贴的图片:", file);
uploadImageAndCreateLayer({
file,
layerManager,
toolManager,
canvas: canvasManager.canvas,
});
},
});
// 绑定快捷键事件
@@ -786,11 +799,11 @@ function triggerLibrary() {
}
}
function handleAddText() {
function handleAddText(text) {
if (toolManager && canvasManager && canvasManager.canvas) {
// 在画布中央创建文本
const canvasCenter = canvasManager.canvas.getCenter();
toolManager.createText(canvasCenter.left, canvasCenter.top);
toolManager.createText(canvasCenter.left, canvasCenter.top, text);
}
}

View File

@@ -1818,7 +1818,12 @@ export class LayerManager {
// 存储到剪贴板
this.clipboardData = layerCopy;
const input = document.createElement("input");
input.value = "aida_copy_canvas_layer: " + layer.name;
document.body.appendChild(input);
input.select();
document.execCommand("copy");
document.body.removeChild(input);
console.log(`已复制图层:${layer.name}`);
return this.clipboardData;
@@ -1917,7 +1922,8 @@ export class LayerManager {
* 粘贴图层
* @returns {string} 新创建的图层ID
*/
async pasteLayer() {
async pasteLayer(event) {
console.log("剪贴板数据:", this.clipboardData,event);
if (!this.clipboardData) {
console.error("剪贴板中没有图层数据");
return null;

View File

@@ -357,6 +357,9 @@ export class ToolManager {
this.canvasManager?.layerManager?.updateLayersObjectsInteractivity?.();
this.canvas?.renderAll();
// 隐藏文本编辑面板
this.hideTextEditor();
// 如果切换到非画笔工具,禁用笔刷指示器
if (!this._shouldShowBrushIndicator(toolId)) {
this._disableBrushIndicator();
@@ -1014,9 +1017,10 @@ export class ToolManager {
* 创建文字对象并添加到画布
* @param {Number} x 文本位置x坐标
* @param {Number} y 文本位置y坐标
* @param {Object} options 文本选项
* @param {String} [text] 文本内容
* @param {Object} [options] 文本选项
*/
async createText(x, y, options = {}) {
async createText(x, y, text, options = {}) {
// 使用命令模式创建文本
if (!this.canvas || !this.layerManager) return null;
if (this.commandManager) {
@@ -1025,6 +1029,7 @@ export class ToolManager {
layerManager: this.layerManager,
x,
y,
text,
textOptions: options,
});
// 执行命令
@@ -1179,6 +1184,19 @@ export class ToolManager {
})
);
}
/**
* 隐藏文本编辑面板
*/
hideTextEditor() {
// 这个方法将在TextEditorPanel组件实现后调用
console.log("隐藏文本编辑面板");
// 将发出一个事件让Vue组件捕获并隐藏编辑面板
document.dispatchEvent(
new CustomEvent("hideTextEditor", {
detail: {},
})
);
}
/**
* 清理资源

View File

@@ -10,6 +10,8 @@ export class KeyboardManager {
* @param {Object} options.toolManager 工具管理器实例
* @param {Object} options.commandManager 命令管理器实例
* @param {Object} options.layerManager 图层管理器实例
* @param {Function} options.pasteText 粘贴文本回调函数
* @param {Function} options.pasteImage 粘贴图片回调函数
* @param {HTMLElement} options.container 容器元素,用于添加事件监听
*/
constructor(options = {}) {
@@ -17,6 +19,8 @@ export class KeyboardManager {
this.commandManager = options.commandManager;
this.layerManager = options.layerManager;
this.container = options.container || document;
this.pasteText = options.pasteText || (() => {});
this.pasteImage = options.pasteImage || (() => {});
// 检测平台类型
this.platform = this.detectPlatform();
@@ -63,6 +67,7 @@ export class KeyboardManager {
// 事件绑定
this._handleKeyDown = this.handleKeyDown.bind(this);
this._handleKeyUp = this.handleKeyUp.bind(this);
this._handlePaste = this.handlePaste.bind(this);
this._handleTouchStart = this.handleTouchStart.bind(this);
this._handleTouchMove = this.handleTouchMove.bind(this);
this._handleTouchEnd = this.handleTouchEnd.bind(this);
@@ -112,7 +117,7 @@ export class KeyboardManager {
// 复制/粘贴
[`${cmdOrCtrl}+c`]: { action: "copy", description: "复制" },
[`${cmdOrCtrl}+v`]: { action: "paste", description: "粘贴" },
[`${cmdOrCtrl}+v`]: { action: "paste", description: "粘贴", noStop: true },
[`${cmdOrCtrl}+x`]: { action: "cut", description: "剪切" },
// 删除
@@ -196,6 +201,28 @@ export class KeyboardManager {
};
}
/**
* 处理粘贴事件
* @param {ClipboardEvent} event 粘贴事件
*/
handlePaste(event) {
event.preventDefault(); // 阻止默认粘贴行为
const text = event.clipboardData?.getData("text/plain") || "";
if(/^aida_copy_canvas_layer/.test(text)) return;
const items = event.clipboardData?.items || [];
console.log(this);
for (const item of items) {
if (item.type.indexOf("text/plain") !== -1) {
item.getAsString((text) => {
this.pasteText(text);
});
} else if (item.type.indexOf("image") !== -1) {
const blob = item.getAsFile();
this.pasteImage(blob);
}
}
}
/**
* 初始化并开始监听键盘事件
*/
@@ -203,6 +230,7 @@ export class KeyboardManager {
// 添加键盘事件监听
this.container.addEventListener("keydown", this._handleKeyDown);
this.container.addEventListener("keyup", this._handleKeyUp);
this.container.addEventListener("paste", this._handlePaste);
// 如果是触摸设备,添加触摸事件监听
if (this.isTouchDevice) {
@@ -222,6 +250,7 @@ export class KeyboardManager {
// 移除键盘事件监听
this.container.removeEventListener("keydown", this._handleKeyDown);
this.container.removeEventListener("keyup", this._handleKeyUp);
this.container.removeEventListener("paste", this._handlePaste);
// 如果是触摸设备,移除触摸事件监听
if (this.isTouchDevice) {
@@ -251,7 +280,7 @@ export class KeyboardManager {
const shortcut = this.shortcuts[shortcutKey];
if (shortcut) {
// 阻止默认行为,例如浏览器的保存对话框等
if (shortcutKey.includes(`${this.modifierKeys.cmdOrCtrl}+`)) {
if (shortcutKey.includes(`${this.modifierKeys.cmdOrCtrl}+`) && !shortcut.noStop) {
event.preventDefault();
}
@@ -701,6 +730,7 @@ export class KeyboardManager {
// 移除事件监听
this.container.removeEventListener("keydown", this._handleKeyDown);
this.container.removeEventListener("keyup", this._handleKeyUp);
this.container.removeEventListener("paste", this._handlePaste);
// 如果有触摸事件,也移除它们
if (this.isTouchDevice) {

View File

@@ -278,14 +278,6 @@ const isShowLeft = ref(true);
<span></span>
<div class="tool-tooltip">更换底图</div>
</div>
<div class="custom-tool-btn" @click="saveCanvas">
<span></span>
<div class="tool-tooltip">保存画布</div>
</div>
<div class="custom-tool-btn" @click="canvasProject">
<span></span>
<div class="tool-tooltip">读取画布</div>
</div>
<div class="custom-tool-btn" @click="exportJSON">
<span></span>
<div class="tool-tooltip">导出JSON</div>

View File

@@ -1367,6 +1367,7 @@ export default {
liquefactionEnvironment: '准备液化环境',
liquefactionEnvironmentLoading: '正在准备液化环境,请稍候...',
LiqueficationFailed: '液化工具启动失败',
TextLayer: '文本图层',
DoubleClickText: '双击编辑文本',
LiquidationcuoError: '未选择有效图像或图层不适合液化操作',
ErrorMessage: '错误提示',

View File

@@ -1409,6 +1409,7 @@ export default {
liquefactionEnvironmentLoading:
'The liquefaction environment is being prepared. Please wait a moment...',
LiqueficationFailed: 'Liquefication tool failed to start.',
TextLayer: 'Text Layer',
DoubleClickText: 'Double-click to edit the text',
LiquidationError:
'No valid image selected or the layer does not fit the liquefaction operation.',