canvas-drawing-editor 2.0.1 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canvas-drawing-editor.umd.js","sources":["../src/core/CanvasDrawingEditor.ts"],"sourcesContent":["/**\n * Canvas Drawing Editor - 纯 JavaScript Web Component\n * 无任何框架依赖\n */\n\n// 类型定义\nexport type ToolType = 'SELECT' | 'PENCIL' | 'RECTANGLE' | 'CIRCLE' | 'TEXT' | 'IMAGE';\n\nexport interface Point {\n x: number;\n y: number;\n}\n\nexport interface BaseObject {\n id: string;\n type: string;\n x: number;\n y: number;\n color: string;\n lineWidth: number;\n}\n\nexport interface RectObject extends BaseObject {\n type: 'RECTANGLE';\n width: number;\n height: number;\n}\n\nexport interface CircleObject extends BaseObject {\n type: 'CIRCLE';\n radius: number;\n}\n\nexport interface PathObject extends BaseObject {\n type: 'PATH';\n points: Point[];\n}\n\nexport interface TextObject extends BaseObject {\n type: 'TEXT';\n text: string;\n fontSize: number;\n}\n\nexport interface ImageObject extends BaseObject {\n type: 'IMAGE';\n width: number;\n height: number;\n dataUrl: string;\n imageElement?: HTMLImageElement;\n}\n\nexport type CanvasObject = RectObject | CircleObject | PathObject | TextObject | ImageObject;\n\nexport interface EditorConfig {\n title?: string;\n showPencil?: boolean;\n showRectangle?: boolean;\n showCircle?: boolean;\n showText?: boolean;\n showImage?: boolean;\n showZoom?: boolean;\n showDownload?: boolean;\n showExport?: boolean;\n showImport?: boolean;\n showColor?: boolean;\n showMinimap?: boolean;\n}\n\n// 默认配置\nconst defaultConfig: EditorConfig = {\n title: 'Canvas Editor',\n showPencil: true,\n showRectangle: true,\n showCircle: true,\n showText: true,\n showImage: true,\n showZoom: true,\n showDownload: true,\n showExport: true,\n showImport: true,\n showColor: true,\n showMinimap: true,\n};\n\n/**\n * Canvas Drawing Editor Web Component\n */\nexport class CanvasDrawingEditor extends HTMLElement {\n // Shadow DOM\n private shadow: ShadowRoot;\n\n // DOM 元素\n private container!: HTMLDivElement;\n private toolbar!: HTMLDivElement;\n private topBar!: HTMLDivElement;\n private canvasContainer!: HTMLDivElement;\n private canvas!: HTMLCanvasElement;\n private ctx!: CanvasRenderingContext2D;\n private minimapCanvas!: HTMLCanvasElement;\n private minimapCtx!: CanvasRenderingContext2D;\n private textInput!: HTMLInputElement;\n private textInputContainer!: HTMLDivElement;\n\n // 配置\n private config: EditorConfig = { ...defaultConfig };\n\n // 状态\n private objects: CanvasObject[] = [];\n private selectedId: string | null = null;\n private tool: ToolType = 'SELECT';\n private color: string = '#000000';\n private lineWidth: number = 3;\n\n // 交互状态\n private isDragging: boolean = false;\n private dragStart: Point | null = null;\n private currentObject: CanvasObject | null = null;\n private dragOffset: Point = { x: 0, y: 0 };\n\n // 文本输入状态\n private isTextInputVisible: boolean = false;\n private textInputPos: Point = { x: 0, y: 0 };\n private textInputScreenPos: Point = { x: 0, y: 0 };\n private editingTextId: string | null = null;\n\n // 调整大小状态\n private isResizing: boolean = false;\n private resizeHandle: string | null = null;\n private resizeStartBounds: { x: number; y: number; width: number; height: number } | null = null;\n private resizeOriginalObject: CanvasObject | null = null;\n\n // 历史记录\n private history: CanvasObject[][] = [];\n private clipboard: CanvasObject | null = null;\n\n // 缩放状态\n private scale: number = 1;\n private panOffset: Point = { x: 0, y: 0 };\n\n // 平移状态\n private isPanning: boolean = false;\n private panStart: Point = { x: 0, y: 0 };\n\n // 绑定的事件处理器(用于移除监听)\n private boundHandleResize: () => void;\n private boundHandleKeyDown: (e: KeyboardEvent) => void;\n private boundHandleWheel: (e: WheelEvent) => void;\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n \n // 绑定事件处理器\n this.boundHandleResize = this.handleResize.bind(this);\n this.boundHandleKeyDown = this.handleKeyDown.bind(this);\n this.boundHandleWheel = this.handleWheel.bind(this);\n }\n\n // 观察的属性\n static get observedAttributes(): string[] {\n return [\n 'title', 'show-pencil', 'show-rectangle', 'show-circle', 'show-text',\n 'show-image', 'show-zoom', 'show-download', 'show-export', 'show-import',\n 'show-color', 'show-minimap'\n ];\n }\n\n // 生命周期:连接到 DOM\n connectedCallback(): void {\n this.parseAttributes();\n this.render();\n this.setupEventListeners();\n this.initCanvas();\n }\n\n // 生命周期:从 DOM 断开\n disconnectedCallback(): void {\n this.removeEventListeners();\n }\n\n // 生命周期:属性变化\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n this.parseAttributes();\n if (this.container) {\n this.updateUI();\n }\n }\n\n // 解析 HTML 属性\n private parseAttributes(): void {\n this.config = {\n title: this.getAttribute('title') || defaultConfig.title,\n showPencil: this.getAttribute('show-pencil') !== 'false',\n showRectangle: this.getAttribute('show-rectangle') !== 'false',\n showCircle: this.getAttribute('show-circle') !== 'false',\n showText: this.getAttribute('show-text') !== 'false',\n showImage: this.getAttribute('show-image') !== 'false',\n showZoom: this.getAttribute('show-zoom') !== 'false',\n showDownload: this.getAttribute('show-download') !== 'false',\n showExport: this.getAttribute('show-export') !== 'false',\n showImport: this.getAttribute('show-import') !== 'false',\n showColor: this.getAttribute('show-color') !== 'false',\n showMinimap: this.getAttribute('show-minimap') !== 'false',\n };\n }\n\n // 生成唯一 ID\n private generateId(): string {\n return Math.random().toString(36).substr(2, 9);\n }\n\n // 设置事件监听\n private setupEventListeners(): void {\n window.addEventListener('resize', this.boundHandleResize);\n window.addEventListener('keydown', this.boundHandleKeyDown);\n }\n\n // 移除事件监听\n private removeEventListeners(): void {\n window.removeEventListener('resize', this.boundHandleResize);\n window.removeEventListener('keydown', this.boundHandleKeyDown);\n if (this.canvas) {\n this.canvas.removeEventListener('wheel', this.boundHandleWheel);\n }\n }\n\n // 窗口大小变化处理\n private handleResize(): void {\n this.initCanvas();\n }\n\n // 初始化画布\n private initCanvas(): void {\n if (!this.canvasContainer || !this.canvas) return;\n\n // 使用 requestAnimationFrame 确保 DOM 已经渲染\n requestAnimationFrame(() => {\n this.canvas.width = this.canvasContainer.clientWidth;\n this.canvas.height = this.canvasContainer.clientHeight;\n this.renderCanvas();\n this.renderMinimap();\n });\n }\n\n // 获取鼠标在画布上的位置(考虑缩放和平移)\n private getMousePos(e: MouseEvent | TouchEvent): Point {\n const rect = this.canvas.getBoundingClientRect();\n let clientX: number, clientY: number;\n\n if ('touches' in e && e.touches.length > 0) {\n clientX = e.touches[0].clientX;\n clientY = e.touches[0].clientY;\n } else if ('clientX' in e) {\n clientX = e.clientX;\n clientY = e.clientY;\n } else {\n return { x: 0, y: 0 };\n }\n\n const x = (clientX - rect.left - this.panOffset.x) / this.scale;\n const y = (clientY - rect.top - this.panOffset.y) / this.scale;\n return { x, y };\n }\n\n // 获取屏幕坐标(不考虑缩放和平移)\n private getScreenPos(e: MouseEvent | TouchEvent): Point {\n const rect = this.canvas.getBoundingClientRect();\n let clientX: number, clientY: number;\n\n if ('touches' in e && e.touches.length > 0) {\n clientX = e.touches[0].clientX;\n clientY = e.touches[0].clientY;\n } else if ('clientX' in e) {\n clientX = e.clientX;\n clientY = e.clientY;\n } else {\n return { x: 0, y: 0 };\n }\n\n return { x: clientX - rect.left, y: clientY - rect.top };\n }\n\n // 获取对象边界\n private getObjectBounds(obj: CanvasObject): { x: number; y: number; width: number; height: number } {\n switch (obj.type) {\n case 'RECTANGLE':\n case 'IMAGE': {\n const r = obj as RectObject | ImageObject;\n return { x: r.x, y: r.y, width: r.width, height: r.height };\n }\n case 'CIRCLE': {\n const c = obj as CircleObject;\n return { x: c.x - c.radius, y: c.y - c.radius, width: c.radius * 2, height: c.radius * 2 };\n }\n case 'TEXT': {\n const t = obj as TextObject;\n const width = t.text.length * t.fontSize * 0.6;\n return { x: t.x, y: t.y - t.fontSize, width, height: t.fontSize };\n }\n case 'PATH': {\n const p = obj as PathObject;\n if (p.points.length === 0) return { x: 0, y: 0, width: 0, height: 0 };\n const minX = Math.min(...p.points.map(pt => pt.x));\n const maxX = Math.max(...p.points.map(pt => pt.x));\n const minY = Math.min(...p.points.map(pt => pt.y));\n const maxY = Math.max(...p.points.map(pt => pt.y));\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n }\n }\n return { x: 0, y: 0, width: 0, height: 0 };\n }\n\n // 检查调整大小手柄\n private getResizeHandleAtPoint(obj: CanvasObject, x: number, y: number): string | null {\n const bounds = this.getObjectBounds(obj);\n const handleSize = 8;\n\n const handles = [\n { name: 'nw', x: bounds.x, y: bounds.y },\n { name: 'ne', x: bounds.x + bounds.width, y: bounds.y },\n { name: 'sw', x: bounds.x, y: bounds.y + bounds.height },\n { name: 'se', x: bounds.x + bounds.width, y: bounds.y + bounds.height },\n ];\n\n for (const handle of handles) {\n if (Math.abs(x - handle.x) <= handleSize && Math.abs(y - handle.y) <= handleSize) {\n return handle.name;\n }\n }\n return null;\n }\n\n // 碰撞检测\n private isHit(obj: CanvasObject, x: number, y: number): boolean {\n switch (obj.type) {\n case 'RECTANGLE': {\n const r = obj as RectObject;\n return x >= r.x && x <= r.x + r.width && y >= r.y && y <= r.y + r.height;\n }\n case 'CIRCLE': {\n const c = obj as CircleObject;\n const dist = Math.sqrt(Math.pow(x - c.x, 2) + Math.pow(y - c.y, 2));\n return dist <= c.radius;\n }\n case 'IMAGE': {\n const img = obj as ImageObject;\n return x >= img.x && x <= img.x + img.width && y >= img.y && y <= img.y + img.height;\n }\n case 'TEXT': {\n const t = obj as TextObject;\n return x >= t.x && x <= t.x + (t.text.length * t.fontSize * 0.6) && y >= t.y - t.fontSize && y <= t.y;\n }\n case 'PATH': {\n const p = obj as PathObject;\n if (p.points.length === 0) return false;\n const minX = Math.min(...p.points.map(pt => pt.x));\n const maxX = Math.max(...p.points.map(pt => pt.x));\n const minY = Math.min(...p.points.map(pt => pt.y));\n const maxY = Math.max(...p.points.map(pt => pt.y));\n return x >= minX && x <= maxX && y >= minY && y <= maxY;\n }\n }\n return false;\n }\n\n // 保存历史\n private saveHistory(): void {\n this.history.push(JSON.parse(JSON.stringify(this.objects)));\n }\n\n // 撤销\n private undo(): void {\n if (this.history.length === 0) return;\n const previousState = this.history.pop();\n if (previousState) {\n this.objects = previousState;\n this.selectedId = null;\n this.renderCanvas();\n this.renderMinimap();\n this.dispatchChangeEvent();\n }\n }\n\n // 删除选中对象\n private deleteSelected(): void {\n if (this.selectedId) {\n this.saveHistory();\n this.objects = this.objects.filter(o => o.id !== this.selectedId);\n this.selectedId = null;\n this.renderCanvas();\n this.renderMinimap();\n this.updateUI();\n this.dispatchChangeEvent();\n }\n }\n\n // 复制选中对象\n private copySelected(): void {\n if (this.selectedId) {\n const selectedObj = this.objects.find(o => o.id === this.selectedId);\n if (selectedObj) {\n this.clipboard = JSON.parse(JSON.stringify(selectedObj));\n }\n }\n }\n\n // 粘贴对象\n private pasteObject(): void {\n if (this.clipboard) {\n this.saveHistory();\n const newObj = {\n ...JSON.parse(JSON.stringify(this.clipboard)),\n id: this.generateId(),\n x: this.clipboard.x + 20,\n y: this.clipboard.y + 20\n };\n if (newObj.type === 'PATH' && newObj.points) {\n newObj.points = newObj.points.map((pt: Point) => ({\n x: pt.x + 20,\n y: pt.y + 20\n }));\n }\n this.objects.push(newObj);\n this.selectedId = newObj.id;\n this.clipboard = newObj;\n this.renderCanvas();\n this.renderMinimap();\n this.updateUI();\n this.dispatchChangeEvent();\n }\n }\n\n // 派发变化事件\n private dispatchChangeEvent(): void {\n this.dispatchEvent(new CustomEvent('editor-change', {\n bubbles: true,\n composed: true,\n detail: { objects: this.objects }\n }));\n }\n\n // 键盘事件处理\n private handleKeyDown(e: KeyboardEvent): void {\n if (this.isTextInputVisible) return;\n\n // Ctrl+Z: 撤销\n if ((e.ctrlKey || e.metaKey) && e.key === 'z') {\n e.preventDefault();\n this.undo();\n return;\n }\n\n // Ctrl+C: 复制\n if ((e.ctrlKey || e.metaKey) && e.key === 'c') {\n if (this.selectedId) {\n e.preventDefault();\n this.copySelected();\n }\n return;\n }\n\n // Ctrl+V: 粘贴\n if ((e.ctrlKey || e.metaKey) && e.key === 'v') {\n if (this.clipboard) {\n e.preventDefault();\n this.pasteObject();\n }\n return;\n }\n\n // Delete/Backspace: 删除\n if ((e.key === 'Delete' || e.key === 'Backspace') && this.selectedId) {\n e.preventDefault();\n this.deleteSelected();\n return;\n }\n\n // 快捷键切换工具\n if (!e.ctrlKey && !e.metaKey) {\n switch (e.key.toLowerCase()) {\n case 'v':\n this.setTool('SELECT');\n break;\n case 'p':\n case 'b':\n this.setTool('PENCIL');\n break;\n case 'r':\n this.setTool('RECTANGLE');\n break;\n case 'o':\n this.setTool('CIRCLE');\n break;\n case 't':\n this.setTool('TEXT');\n break;\n case 'escape':\n this.selectedId = null;\n this.hideTextInput();\n this.renderCanvas();\n this.updateUI();\n break;\n }\n }\n }\n\n // 滚轮缩放\n private handleWheel(e: WheelEvent): void {\n e.preventDefault();\n const rect = this.canvas.getBoundingClientRect();\n const mouseX = e.clientX - rect.left;\n const mouseY = e.clientY - rect.top;\n\n const delta = e.deltaY > 0 ? 0.9 : 1.1;\n const newScale = this.scale * delta;\n\n this.zoomAtPoint(newScale, mouseX, mouseY);\n }\n\n // 以指定点为中心缩放\n private zoomAtPoint(newScale: number, centerX: number, centerY: number): void {\n const clampedScale = Math.min(Math.max(newScale, 0.2), 5);\n\n const mouseXBeforeZoom = (centerX - this.panOffset.x) / this.scale;\n const mouseYBeforeZoom = (centerY - this.panOffset.y) / this.scale;\n\n const newPanOffsetX = centerX - mouseXBeforeZoom * clampedScale;\n const newPanOffsetY = centerY - mouseYBeforeZoom * clampedScale;\n\n this.scale = clampedScale;\n this.panOffset = { x: newPanOffsetX, y: newPanOffsetY };\n\n this.renderCanvas();\n this.renderMinimap();\n this.updateZoomDisplay();\n }\n\n // 放大\n private zoomIn(): void {\n const centerX = this.canvas.width / 2;\n const centerY = this.canvas.height / 2;\n this.zoomAtPoint(this.scale * 1.2, centerX, centerY);\n }\n\n // 缩小\n private zoomOut(): void {\n const centerX = this.canvas.width / 2;\n const centerY = this.canvas.height / 2;\n this.zoomAtPoint(this.scale / 1.2, centerX, centerY);\n }\n\n // 重置缩放\n private resetZoom(): void {\n this.scale = 1;\n this.panOffset = { x: 0, y: 0 };\n this.renderCanvas();\n this.renderMinimap();\n this.updateZoomDisplay();\n }\n\n // 更新缩放显示\n private updateZoomDisplay(): void {\n const zoomText = this.shadow.querySelector('.zoom-text');\n if (zoomText) {\n zoomText.textContent = `${Math.round(this.scale * 100)}%`;\n }\n }\n\n // 设置工具\n private setTool(tool: ToolType): void {\n this.tool = tool;\n this.updateToolButtons();\n }\n\n // 更新工具按钮状态\n private updateToolButtons(): void {\n const buttons = this.shadow.querySelectorAll('.tool-btn');\n buttons.forEach(btn => {\n const btnTool = btn.getAttribute('data-tool');\n if (btnTool === this.tool) {\n btn.classList.add('active');\n } else {\n btn.classList.remove('active');\n }\n });\n }\n\n // 隐藏文本输入\n private hideTextInput(): void {\n this.isTextInputVisible = false;\n if (this.textInputContainer) {\n this.textInputContainer.style.display = 'none';\n }\n this.editingTextId = null;\n }\n\n // 显示文本输入\n private showTextInput(screenX: number, screenY: number, text: string = ''): void {\n this.isTextInputVisible = true;\n this.textInputScreenPos = { x: screenX, y: screenY };\n\n if (this.textInputContainer && this.textInput) {\n this.textInputContainer.style.display = 'block';\n this.textInputContainer.style.left = `${screenX}px`;\n this.textInputContainer.style.top = `${screenY - 30}px`;\n this.textInput.value = text;\n this.textInput.style.color = this.color;\n setTimeout(() => {\n this.textInput.focus();\n if (text) this.textInput.select();\n }, 0);\n }\n }\n\n // 提交文本\n private submitText(): void {\n const value = this.textInput?.value?.trim();\n if (value) {\n if (this.editingTextId) {\n const existingObj = this.objects.find(o => o.id === this.editingTextId) as TextObject | undefined;\n if (existingObj && existingObj.text !== value) {\n this.saveHistory();\n existingObj.text = value;\n }\n this.selectedId = this.editingTextId;\n } else {\n this.saveHistory();\n const newObj: TextObject = {\n id: this.generateId(),\n type: 'TEXT',\n x: this.textInputPos.x,\n y: this.textInputPos.y,\n text: value,\n fontSize: 24,\n color: this.color,\n lineWidth: this.lineWidth\n };\n this.objects.push(newObj);\n this.selectedId = newObj.id;\n }\n this.dispatchChangeEvent();\n }\n this.hideTextInput();\n this.setTool('SELECT');\n this.renderCanvas();\n this.renderMinimap();\n this.updateUI();\n }\n\n // 画布鼠标按下\n private handleCanvasPointerDown(e: MouseEvent | TouchEvent): void {\n const { x, y } = this.getMousePos(e);\n const screenPos = this.getScreenPos(e);\n this.dragStart = { x, y };\n this.isDragging = true;\n\n // 如果文本输入可见且不是文本工具,先保存文本\n if (this.isTextInputVisible && this.tool !== 'TEXT') {\n this.submitText();\n }\n\n if (this.tool === 'SELECT') {\n // 检查是否点击调整大小手柄\n if (this.selectedId) {\n const selectedObj = this.objects.find(o => o.id === this.selectedId);\n if (selectedObj) {\n const handle = this.getResizeHandleAtPoint(selectedObj, x, y);\n if (handle) {\n this.saveHistory();\n this.isResizing = true;\n this.resizeHandle = handle;\n this.resizeStartBounds = this.getObjectBounds(selectedObj);\n this.resizeOriginalObject = JSON.parse(JSON.stringify(selectedObj));\n return;\n }\n }\n }\n\n // 查找点击的对象\n const clickedObject = [...this.objects].reverse().find(obj => this.isHit(obj, x, y));\n\n if (clickedObject) {\n this.selectedId = clickedObject.id;\n this.dragOffset = { x: x - clickedObject.x, y: y - clickedObject.y };\n this.saveHistory();\n this.updateUI();\n } else {\n // 开始拖拽画布\n this.selectedId = null;\n this.isPanning = true;\n this.panStart = screenPos;\n this.updateUI();\n }\n } else if (this.tool === 'TEXT') {\n // 显示文本输入\n this.textInputPos = { x, y };\n this.showTextInput(screenPos.x, screenPos.y);\n this.isDragging = false;\n } else {\n // 开始绘制图形\n this.saveHistory();\n const id = this.generateId();\n if (this.tool === 'RECTANGLE') {\n this.currentObject = { id, type: 'RECTANGLE', x, y, width: 0, height: 0, color: this.color, lineWidth: this.lineWidth };\n } else if (this.tool === 'CIRCLE') {\n this.currentObject = { id, type: 'CIRCLE', x, y, radius: 0, color: this.color, lineWidth: this.lineWidth };\n } else if (this.tool === 'PENCIL') {\n this.currentObject = { id, type: 'PATH', x, y, points: [{ x, y }], color: this.color, lineWidth: this.lineWidth };\n }\n }\n\n this.renderCanvas();\n }\n\n // 画布鼠标移动\n private handleCanvasPointerMove(e: MouseEvent | TouchEvent): void {\n // 处理画布拖拽\n if (this.isPanning) {\n const screenPos = this.getScreenPos(e);\n const dx = screenPos.x - this.panStart.x;\n const dy = screenPos.y - this.panStart.y;\n this.panOffset = { x: this.panOffset.x + dx, y: this.panOffset.y + dy };\n this.panStart = screenPos;\n this.renderCanvas();\n this.renderMinimap();\n return;\n }\n\n if (!this.isDragging || !this.dragStart) return;\n const { x, y } = this.getMousePos(e);\n\n // 处理调整大小\n if (this.isResizing && this.selectedId && this.resizeHandle && this.resizeStartBounds && this.resizeOriginalObject) {\n const obj = this.objects.find(o => o.id === this.selectedId);\n if (!obj) return;\n\n const dx = x - this.dragStart.x;\n const dy = y - this.dragStart.y;\n let newX = this.resizeStartBounds.x;\n let newY = this.resizeStartBounds.y;\n let newWidth = this.resizeStartBounds.width;\n let newHeight = this.resizeStartBounds.height;\n\n if (this.resizeHandle.includes('e')) newWidth = this.resizeStartBounds.width + dx;\n if (this.resizeHandle.includes('w')) {\n newX = this.resizeStartBounds.x + dx;\n newWidth = this.resizeStartBounds.width - dx;\n }\n if (this.resizeHandle.includes('s')) newHeight = this.resizeStartBounds.height + dy;\n if (this.resizeHandle.includes('n')) {\n newY = this.resizeStartBounds.y + dy;\n newHeight = this.resizeStartBounds.height - dy;\n }\n\n newWidth = Math.max(10, newWidth);\n newHeight = Math.max(10, newHeight);\n\n // 根据对象类型应用变化\n switch (obj.type) {\n case 'RECTANGLE':\n case 'IMAGE':\n (obj as RectObject | ImageObject).x = newX;\n (obj as RectObject | ImageObject).y = newY;\n (obj as RectObject | ImageObject).width = newWidth;\n (obj as RectObject | ImageObject).height = newHeight;\n break;\n case 'CIRCLE': {\n const radius = Math.max(newWidth, newHeight) / 2;\n (obj as CircleObject).x = newX + radius;\n (obj as CircleObject).y = newY + radius;\n (obj as CircleObject).radius = radius;\n break;\n }\n case 'TEXT': {\n const origT = this.resizeOriginalObject as TextObject;\n const scaleFactor = newWidth / this.resizeStartBounds.width;\n (obj as TextObject).x = newX;\n (obj as TextObject).y = newY + newHeight;\n (obj as TextObject).fontSize = Math.max(8, Math.round(origT.fontSize * scaleFactor));\n break;\n }\n case 'PATH': {\n const origP = this.resizeOriginalObject as PathObject;\n const scaleX = newWidth / this.resizeStartBounds.width;\n const scaleY = newHeight / this.resizeStartBounds.height;\n (obj as PathObject).points = origP.points.map(pt => ({\n x: newX + (pt.x - this.resizeStartBounds!.x) * scaleX,\n y: newY + (pt.y - this.resizeStartBounds!.y) * scaleY\n }));\n break;\n }\n }\n\n this.renderCanvas();\n this.renderMinimap();\n return;\n }\n\n // 移动选中对象\n if (this.tool === 'SELECT' && this.selectedId) {\n const obj = this.objects.find(o => o.id === this.selectedId);\n if (obj) {\n if (obj.type === 'PATH') {\n const p = obj as PathObject;\n const dx = x - this.dragStart.x;\n const dy = y - this.dragStart.y;\n p.points = p.points.map(pt => ({ x: pt.x + dx, y: pt.y + dy }));\n this.dragStart = { x, y };\n } else {\n obj.x = x - this.dragOffset.x;\n obj.y = y - this.dragOffset.y;\n }\n this.renderCanvas();\n this.renderMinimap();\n }\n } else if (this.currentObject) {\n // 更新正在绘制的图形\n if (this.currentObject.type === 'RECTANGLE') {\n (this.currentObject as RectObject).width = x - this.currentObject.x;\n (this.currentObject as RectObject).height = y - this.currentObject.y;\n } else if (this.currentObject.type === 'CIRCLE') {\n const radius = Math.sqrt(Math.pow(x - this.currentObject.x, 2) + Math.pow(y - this.currentObject.y, 2));\n (this.currentObject as CircleObject).radius = radius;\n } else if (this.currentObject.type === 'PATH') {\n (this.currentObject as PathObject).points.push({ x, y });\n }\n this.renderCanvas();\n }\n }\n\n // 画布鼠标抬起\n private handleCanvasPointerUp(): void {\n this.isDragging = false;\n this.dragStart = null;\n this.isResizing = false;\n this.resizeHandle = null;\n this.resizeStartBounds = null;\n this.resizeOriginalObject = null;\n this.isPanning = false;\n\n if (this.currentObject) {\n this.objects.push(this.currentObject);\n this.currentObject = null;\n this.dispatchChangeEvent();\n }\n\n this.renderCanvas();\n this.renderMinimap();\n }\n\n // 双击编辑文本\n private handleCanvasDoubleClick(e: MouseEvent): void {\n e.preventDefault();\n const { x, y } = this.getMousePos(e);\n\n const clickedObject = [...this.objects].reverse().find(obj => this.isHit(obj, x, y));\n\n if (clickedObject && clickedObject.type === 'TEXT') {\n const textObj = clickedObject as TextObject;\n this.editingTextId = textObj.id;\n this.textInputPos = { x: textObj.x, y: textObj.y };\n const screenX = textObj.x * this.scale + this.panOffset.x;\n const screenY = textObj.y * this.scale + this.panOffset.y;\n this.showTextInput(screenX, screenY, textObj.text);\n this.setTool('SELECT');\n }\n }\n\n // 渲染画布\n private renderCanvas(): void {\n if (!this.ctx) return;\n\n // 清空画布\n this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n\n // 绘制背景\n this.ctx.fillStyle = '#ffffff';\n this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);\n\n // 应用缩放和平移\n this.ctx.save();\n this.ctx.translate(this.panOffset.x, this.panOffset.y);\n this.ctx.scale(this.scale, this.scale);\n\n // 绘制所有对象\n this.objects.forEach(obj => this.drawObject(this.ctx, obj, false));\n\n // 绘制正在创建的对象\n if (this.currentObject) {\n this.drawObject(this.ctx, this.currentObject, false);\n }\n\n // 绘制选中对象的调整手柄\n if (this.selectedId && this.tool === 'SELECT') {\n const selectedObj = this.objects.find(o => o.id === this.selectedId);\n if (selectedObj) {\n this.drawSelectionHandles(this.ctx, selectedObj);\n }\n }\n\n this.ctx.restore();\n }\n\n // 绘制单个对象\n private drawObject(ctx: CanvasRenderingContext2D, obj: CanvasObject, isMinimap: boolean): void {\n ctx.beginPath();\n ctx.strokeStyle = obj.color;\n ctx.lineWidth = obj.lineWidth;\n ctx.fillStyle = obj.color;\n\n // 选中高亮(仅主画布)\n if (!isMinimap && obj.id === this.selectedId) {\n ctx.shadowColor = 'rgba(0, 100, 255, 0.5)';\n ctx.shadowBlur = 10;\n } else {\n ctx.shadowBlur = 0;\n }\n\n switch (obj.type) {\n case 'RECTANGLE': {\n const r = obj as RectObject;\n ctx.strokeRect(r.x, r.y, r.width, r.height);\n break;\n }\n case 'CIRCLE': {\n const c = obj as CircleObject;\n ctx.beginPath();\n ctx.arc(c.x, c.y, c.radius, 0, 2 * Math.PI);\n ctx.stroke();\n break;\n }\n case 'PATH': {\n const p = obj as PathObject;\n if (p.points.length < 2) break;\n ctx.beginPath();\n ctx.lineCap = 'round';\n ctx.lineJoin = 'round';\n ctx.moveTo(p.points[0].x, p.points[0].y);\n for (let i = 1; i < p.points.length; i++) {\n ctx.lineTo(p.points[i].x, p.points[i].y);\n }\n ctx.stroke();\n break;\n }\n case 'TEXT': {\n const t = obj as TextObject;\n ctx.font = `${t.fontSize}px sans-serif`;\n ctx.fillText(t.text, t.x, t.y);\n break;\n }\n case 'IMAGE': {\n const imgObj = obj as ImageObject;\n if (imgObj.imageElement && imgObj.imageElement.complete) {\n ctx.drawImage(imgObj.imageElement, imgObj.x, imgObj.y, imgObj.width, imgObj.height);\n } else if (imgObj.dataUrl) {\n // 加载图片\n const img = new Image();\n img.onload = () => {\n imgObj.imageElement = img;\n this.renderCanvas();\n };\n img.src = imgObj.dataUrl;\n }\n break;\n }\n }\n }\n\n // 绘制选中手柄\n private drawSelectionHandles(ctx: CanvasRenderingContext2D, obj: CanvasObject): void {\n const bounds = this.getObjectBounds(obj);\n const handleSize = 8;\n\n ctx.shadowBlur = 0;\n ctx.fillStyle = '#3b82f6';\n ctx.strokeStyle = '#ffffff';\n ctx.lineWidth = 2;\n\n // 绘制角落手柄\n const corners = [\n { x: bounds.x, y: bounds.y },\n { x: bounds.x + bounds.width, y: bounds.y },\n { x: bounds.x, y: bounds.y + bounds.height },\n { x: bounds.x + bounds.width, y: bounds.y + bounds.height },\n ];\n\n corners.forEach(corner => {\n ctx.beginPath();\n ctx.rect(corner.x - handleSize / 2, corner.y - handleSize / 2, handleSize, handleSize);\n ctx.fill();\n ctx.stroke();\n });\n\n // 绘制选择边框\n ctx.strokeStyle = '#3b82f6';\n ctx.lineWidth = 1;\n ctx.setLineDash([5, 5]);\n ctx.strokeRect(bounds.x, bounds.y, bounds.width, bounds.height);\n ctx.setLineDash([]);\n }\n\n // 渲染小地图\n private renderMinimap(): void {\n if (!this.minimapCtx || !this.config.showMinimap) return;\n\n const minimap = this.minimapCanvas;\n const mainCanvas = this.canvas;\n\n this.minimapCtx.clearRect(0, 0, minimap.width, minimap.height);\n\n // 计算缩放比例\n const scaleX = minimap.width / mainCanvas.width;\n const scaleY = minimap.height / mainCanvas.height;\n const minimapScale = Math.min(scaleX, scaleY) * 0.92;\n\n const canvasW = mainCanvas.width * minimapScale;\n const canvasH = mainCanvas.height * minimapScale;\n const offsetX = (minimap.width - canvasW) / 2;\n const offsetY = (minimap.height - canvasH) / 2;\n\n // 绘制画布区域背景\n this.minimapCtx.fillStyle = '#ffffff';\n this.minimapCtx.fillRect(offsetX, offsetY, canvasW, canvasH);\n\n // 应用主画布的缩放和平移变换\n this.minimapCtx.save();\n this.minimapCtx.translate(offsetX, offsetY);\n this.minimapCtx.scale(minimapScale, minimapScale);\n this.minimapCtx.translate(this.panOffset.x, this.panOffset.y);\n this.minimapCtx.scale(this.scale, this.scale);\n\n // 绘制所有对象\n const allObjects = this.currentObject ? [...this.objects, this.currentObject] : this.objects;\n allObjects.forEach(obj => {\n this.minimapCtx.fillStyle = obj.color;\n this.minimapCtx.strokeStyle = obj.color;\n this.minimapCtx.lineWidth = Math.max(obj.lineWidth, 1);\n this.minimapCtx.setLineDash([]);\n\n switch (obj.type) {\n case 'RECTANGLE': {\n const r = obj as RectObject;\n this.minimapCtx.strokeRect(r.x, r.y, r.width, r.height);\n break;\n }\n case 'CIRCLE': {\n const c = obj as CircleObject;\n this.minimapCtx.beginPath();\n this.minimapCtx.arc(c.x, c.y, c.radius, 0, Math.PI * 2);\n this.minimapCtx.stroke();\n break;\n }\n case 'PATH': {\n const p = obj as PathObject;\n if (p.points.length > 0) {\n this.minimapCtx.beginPath();\n this.minimapCtx.lineCap = 'round';\n this.minimapCtx.lineJoin = 'round';\n this.minimapCtx.moveTo(p.points[0].x, p.points[0].y);\n p.points.forEach(pt => this.minimapCtx.lineTo(pt.x, pt.y));\n this.minimapCtx.stroke();\n }\n break;\n }\n case 'TEXT': {\n const t = obj as TextObject;\n this.minimapCtx.font = `${t.fontSize}px sans-serif`;\n this.minimapCtx.fillText(t.text, t.x, t.y);\n break;\n }\n case 'IMAGE': {\n const img = obj as ImageObject;\n if (img.imageElement) {\n this.minimapCtx.drawImage(img.imageElement, img.x, img.y, img.width, img.height);\n }\n break;\n }\n }\n });\n\n this.minimapCtx.restore();\n\n // 绘制画布边框\n this.minimapCtx.strokeStyle = '#94a3b8';\n this.minimapCtx.lineWidth = 1;\n this.minimapCtx.strokeRect(offsetX, offsetY, canvasW, canvasH);\n }\n\n // 小地图点击定位\n private handleMinimapClick(e: MouseEvent): void {\n const rect = this.minimapCanvas.getBoundingClientRect();\n const clickX = e.clientX - rect.left;\n const clickY = e.clientY - rect.top;\n\n const scaleX = this.minimapCanvas.width / this.canvas.width;\n const scaleY = this.minimapCanvas.height / this.canvas.height;\n const minimapScale = Math.min(scaleX, scaleY) * 0.92;\n\n const canvasW = this.canvas.width * minimapScale;\n const canvasH = this.canvas.height * minimapScale;\n const offsetX = (this.minimapCanvas.width - canvasW) / 2;\n const offsetY = (this.minimapCanvas.height - canvasH) / 2;\n\n const relX = clickX - offsetX;\n const relY = clickY - offsetY;\n\n const canvasX = (relX / minimapScale - this.panOffset.x) / this.scale;\n const canvasY = (relY / minimapScale - this.panOffset.y) / this.scale;\n\n const viewportCenterX = this.canvas.width / 2;\n const viewportCenterY = this.canvas.height / 2;\n\n this.panOffset = {\n x: viewportCenterX / this.scale - canvasX,\n y: viewportCenterY / this.scale - canvasY\n };\n\n this.renderCanvas();\n this.renderMinimap();\n }\n\n // 图片上传处理\n private handleImageUpload(e: Event): void {\n const input = e.target as HTMLInputElement;\n if (!input.files || input.files.length === 0) return;\n\n const file = input.files[0];\n const reader = new FileReader();\n\n reader.onload = (event) => {\n const dataUrl = event.target?.result as string;\n const img = new Image();\n img.onload = () => {\n this.saveHistory();\n const maxSize = 300;\n let width = img.width;\n let height = img.height;\n if (width > maxSize || height > maxSize) {\n const ratio = Math.min(maxSize / width, maxSize / height);\n width *= ratio;\n height *= ratio;\n }\n\n const newObj: ImageObject = {\n id: this.generateId(),\n type: 'IMAGE',\n x: 100,\n y: 100,\n width,\n height,\n color: '#000000',\n lineWidth: 1,\n dataUrl,\n imageElement: img\n };\n this.objects.push(newObj);\n this.selectedId = newObj.id;\n this.setTool('SELECT');\n this.renderCanvas();\n this.renderMinimap();\n this.updateUI();\n this.dispatchChangeEvent();\n };\n img.src = dataUrl;\n };\n\n reader.readAsDataURL(file);\n input.value = '';\n }\n\n // 保存 JSON\n private saveJson(): void {\n const data = {\n version: '1.0',\n objects: this.objects.map(obj => {\n const { imageElement, ...rest } = obj as ImageObject;\n return rest;\n })\n };\n const json = JSON.stringify(data, null, 2);\n const blob = new Blob([json], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = 'canvas-project.json';\n a.click();\n URL.revokeObjectURL(url);\n }\n\n // 加载 JSON\n private loadJson(e: Event): void {\n const input = e.target as HTMLInputElement;\n if (!input.files || input.files.length === 0) return;\n\n const file = input.files[0];\n const reader = new FileReader();\n\n reader.onload = (event) => {\n try {\n const data = JSON.parse(event.target?.result as string);\n if (data.objects && Array.isArray(data.objects)) {\n this.saveHistory();\n this.objects = data.objects;\n this.selectedId = null;\n\n // 重新加载图片\n this.objects.forEach(obj => {\n if (obj.type === 'IMAGE' && (obj as ImageObject).dataUrl) {\n const img = new Image();\n img.onload = () => {\n (obj as ImageObject).imageElement = img;\n this.renderCanvas();\n this.renderMinimap();\n };\n img.src = (obj as ImageObject).dataUrl;\n }\n });\n\n this.renderCanvas();\n this.renderMinimap();\n this.updateUI();\n this.dispatchChangeEvent();\n }\n } catch (err) {\n console.error('Failed to load JSON:', err);\n }\n };\n\n reader.readAsText(file);\n input.value = '';\n }\n\n // 导出 PNG\n private exportPng(): void {\n // 创建临时画布\n const tempCanvas = document.createElement('canvas');\n tempCanvas.width = this.canvas.width;\n tempCanvas.height = this.canvas.height;\n const tempCtx = tempCanvas.getContext('2d')!;\n\n // 绘制白色背景\n tempCtx.fillStyle = '#ffffff';\n tempCtx.fillRect(0, 0, tempCanvas.width, tempCanvas.height);\n\n // 应用缩放和平移\n tempCtx.translate(this.panOffset.x, this.panOffset.y);\n tempCtx.scale(this.scale, this.scale);\n\n // 绘制所有对象\n this.objects.forEach(obj => this.drawObject(tempCtx, obj, true));\n\n // 下载\n const url = tempCanvas.toDataURL('image/png');\n const a = document.createElement('a');\n a.href = url;\n a.download = 'canvas-export.png';\n a.click();\n }\n\n // 更新 UI\n private updateUI(): void {\n // 更新选中状态显示\n const selectionInfo = this.shadow.querySelector('.selection-info');\n if (selectionInfo) {\n if (this.selectedId) {\n const selectedObj = this.objects.find(o => o.id === this.selectedId);\n if (selectedObj) {\n const typeLabels: Record<string, string> = {\n 'RECTANGLE': '矩形',\n 'CIRCLE': '圆形',\n 'PATH': '画笔',\n 'TEXT': '文本',\n 'IMAGE': '图片'\n };\n const typeLabel = typeLabels[selectedObj.type] || selectedObj.type;\n selectionInfo.innerHTML = `\n <span class=\"selection-label\">已选择: ${typeLabel}</span>\n <button class=\"delete-btn\" title=\"删除\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M3 6h18M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2\"/>\n </svg>\n </button>\n `;\n selectionInfo.classList.add('visible');\n const deleteBtn = selectionInfo.querySelector('.delete-btn');\n if (deleteBtn) {\n deleteBtn.addEventListener('click', () => this.deleteSelected());\n }\n }\n } else {\n selectionInfo.classList.remove('visible');\n selectionInfo.innerHTML = '';\n }\n }\n\n // 更新撤销按钮状态\n const undoBtn = this.shadow.querySelector('.undo-btn') as HTMLButtonElement;\n if (undoBtn) {\n undoBtn.disabled = this.history.length === 0;\n }\n\n // 更新空画布提示显示\n const emptyHint = this.shadow.querySelector('.empty-hint') as HTMLElement;\n if (emptyHint) {\n emptyHint.style.display = this.objects.length === 0 ? 'flex' : 'none';\n }\n }\n\n // 渲染 DOM 结构\n private render(): void {\n this.shadow.innerHTML = `\n <style>${this.getStyles()}</style>\n <div class=\"editor-container\">\n <!-- 左侧工具栏 -->\n <div class=\"toolbar\">\n ${this.createToolButton('SELECT', 'select-icon', '选择 (V)')}\n <div class=\"divider\"></div>\n ${this.config.showPencil ? this.createToolButton('PENCIL', 'pencil-icon', '画笔 (P)') : ''}\n ${this.config.showRectangle ? this.createToolButton('RECTANGLE', 'rect-icon', '矩形 (R)') : ''}\n ${this.config.showCircle ? this.createToolButton('CIRCLE', 'circle-icon', '圆形 (O)') : ''}\n ${this.config.showText ? this.createToolButton('TEXT', 'text-icon', '文本 (T)') : ''}\n ${this.config.showImage ? `\n <label class=\"tool-btn\" title=\"插入图片\">\n <svg class=\"icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"/>\n <circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"/>\n <path d=\"M21 15l-5-5L5 21\"/>\n </svg>\n <input type=\"file\" accept=\"image/*\" class=\"hidden image-input\" />\n </label>\n ` : ''}\n <div class=\"divider\"></div>\n <button class=\"tool-btn undo-btn\" title=\"撤销 (Ctrl+Z)\" disabled>\n <svg class=\"icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M1 4v6h6\"/>\n <path d=\"M3.51 15a9 9 0 1 0 2.13-9.36L1 10\"/>\n </svg>\n </button>\n <div class=\"spacer\"></div>\n ${this.config.showColor ? `\n <input type=\"color\" class=\"color-picker\" value=\"${this.color}\" title=\"颜色\" />\n ` : ''}\n </div>\n\n <!-- 主区域 -->\n <div class=\"main-area\">\n <!-- 顶部栏 -->\n <div class=\"top-bar\">\n <div class=\"top-bar-left\">\n <h2 class=\"title\">${this.config.title}</h2>\n <div class=\"selection-info\"></div>\n </div>\n <div class=\"top-bar-right\">\n ${this.config.showZoom ? `\n <div class=\"zoom-controls\">\n <button class=\"zoom-btn zoom-out-btn\" title=\"缩小\">\n <svg class=\"icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"M21 21l-4.35-4.35M8 11h6\"/>\n </svg>\n </button>\n <button class=\"zoom-text\" title=\"重置缩放\">100%</button>\n <button class=\"zoom-btn zoom-in-btn\" title=\"放大\">\n <svg class=\"icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"M21 21l-4.35-4.35M11 8v6M8 11h6\"/>\n </svg>\n </button>\n </div>\n ` : ''}\n ${(this.config.showExport || this.config.showImport || this.config.showDownload) ? `\n <div class=\"file-controls\">\n ${this.config.showExport ? `\n <button class=\"file-btn save-json-btn\" title=\"保存项目 (JSON)\">\n <svg class=\"icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M19 21H5a2 2 0 01-2-2V5a2 2 0 012-2h11l5 5v11a2 2 0 01-2 2z\"/>\n <polyline points=\"17 21 17 13 7 13 7 21\"/><polyline points=\"7 3 7 8 15 8\"/>\n </svg>\n </button>\n ` : ''}\n ${this.config.showImport ? `\n <label class=\"file-btn\" title=\"加载项目 (JSON)\">\n <svg class=\"icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M22 19a2 2 0 01-2 2H4a2 2 0 01-2-2V5a2 2 0 012-2h5l2 3h9a2 2 0 012 2z\"/>\n </svg>\n <input type=\"file\" accept=\".json\" class=\"hidden load-json-input\" />\n </label>\n ` : ''}\n ${this.config.showDownload ? `\n <button class=\"file-btn export-png-btn\" title=\"导出 PNG\">\n <svg class=\"icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3\"/>\n </svg>\n </button>\n ` : ''}\n </div>\n ` : ''}\n </div>\n </div>\n\n <!-- 画布容器 -->\n <div class=\"canvas-container\">\n <canvas class=\"main-canvas\"></canvas>\n\n ${this.config.showMinimap ? `\n <div class=\"minimap-wrapper\">\n <div class=\"minimap-header\">\n <svg class=\"minimap-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"/>\n <path d=\"M3 9h18M9 21V9\"/>\n </svg>\n <span>导航</span>\n </div>\n <canvas class=\"minimap-canvas\" width=\"220\" height=\"140\"></canvas>\n </div>\n ` : ''}\n\n <!-- 文本输入 -->\n <div class=\"text-input-container\" style=\"display: none;\">\n <input type=\"text\" class=\"text-input\" placeholder=\"输入文本...\" />\n </div>\n\n <!-- 空画布提示 -->\n <div class=\"empty-hint\">\n <h3>开始创作</h3>\n <p>选择左侧的工具开始绘制</p>\n </div>\n </div>\n </div>\n </div>\n `;\n\n // 获取 DOM 引用\n this.container = this.shadow.querySelector('.editor-container')!;\n this.toolbar = this.shadow.querySelector('.toolbar')!;\n this.topBar = this.shadow.querySelector('.top-bar')!;\n this.canvasContainer = this.shadow.querySelector('.canvas-container')!;\n this.canvas = this.shadow.querySelector('.main-canvas')!;\n this.ctx = this.canvas.getContext('2d')!;\n\n if (this.config.showMinimap) {\n this.minimapCanvas = this.shadow.querySelector('.minimap-canvas')!;\n this.minimapCtx = this.minimapCanvas.getContext('2d')!;\n }\n\n this.textInputContainer = this.shadow.querySelector('.text-input-container')!;\n this.textInput = this.shadow.querySelector('.text-input')!;\n\n // 绑定事件\n this.bindEvents();\n }\n\n // 绑定事件\n private bindEvents(): void {\n // 画布事件\n this.canvas.addEventListener('mousedown', (e) => this.handleCanvasPointerDown(e));\n this.canvas.addEventListener('mousemove', (e) => this.handleCanvasPointerMove(e));\n this.canvas.addEventListener('mouseup', () => this.handleCanvasPointerUp());\n this.canvas.addEventListener('mouseleave', () => this.handleCanvasPointerUp());\n this.canvas.addEventListener('dblclick', (e) => this.handleCanvasDoubleClick(e));\n this.canvas.addEventListener('touchstart', (e) => this.handleCanvasPointerDown(e));\n this.canvas.addEventListener('touchmove', (e) => this.handleCanvasPointerMove(e));\n this.canvas.addEventListener('touchend', () => this.handleCanvasPointerUp());\n this.canvas.addEventListener('wheel', this.boundHandleWheel, { passive: false });\n\n // 工具按钮\n this.shadow.querySelectorAll('.tool-btn[data-tool]').forEach(btn => {\n btn.addEventListener('click', () => {\n const tool = btn.getAttribute('data-tool') as ToolType;\n this.setTool(tool);\n });\n });\n\n // 撤销按钮\n const undoBtn = this.shadow.querySelector('.undo-btn');\n if (undoBtn) {\n undoBtn.addEventListener('click', () => this.undo());\n }\n\n // 颜色选择器\n const colorPicker = this.shadow.querySelector('.color-picker') as HTMLInputElement;\n if (colorPicker) {\n colorPicker.addEventListener('input', (e) => {\n this.color = (e.target as HTMLInputElement).value;\n });\n }\n\n // 图片上传\n const imageInput = this.shadow.querySelector('.image-input');\n if (imageInput) {\n imageInput.addEventListener('change', (e) => this.handleImageUpload(e));\n }\n\n // 缩放按钮\n const zoomInBtn = this.shadow.querySelector('.zoom-in-btn');\n const zoomOutBtn = this.shadow.querySelector('.zoom-out-btn');\n const zoomText = this.shadow.querySelector('.zoom-text');\n if (zoomInBtn) zoomInBtn.addEventListener('click', () => this.zoomIn());\n if (zoomOutBtn) zoomOutBtn.addEventListener('click', () => this.zoomOut());\n if (zoomText) zoomText.addEventListener('click', () => this.resetZoom());\n\n // 文件操作\n const saveJsonBtn = this.shadow.querySelector('.save-json-btn');\n const loadJsonInput = this.shadow.querySelector('.load-json-input');\n const exportPngBtn = this.shadow.querySelector('.export-png-btn');\n if (saveJsonBtn) saveJsonBtn.addEventListener('click', () => this.saveJson());\n if (loadJsonInput) loadJsonInput.addEventListener('change', (e) => this.loadJson(e));\n if (exportPngBtn) exportPngBtn.addEventListener('click', () => this.exportPng());\n\n // 小地图点击\n if (this.minimapCanvas) {\n this.minimapCanvas.addEventListener('click', (e) => this.handleMinimapClick(e));\n }\n\n // 文本输入\n if (this.textInput) {\n this.textInput.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n this.submitText();\n } else if (e.key === 'Escape') {\n this.hideTextInput();\n }\n });\n this.textInput.addEventListener('blur', () => {\n if (this.isTextInputVisible) {\n this.submitText();\n }\n });\n }\n }\n\n // 创建工具按钮 HTML\n private createToolButton(tool: ToolType, iconClass: string, title: string): string {\n const icons: Record<string, string> = {\n 'select-icon': '<path d=\"M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z\"/><path d=\"M13 13l6 6\"/>',\n 'pencil-icon': '<path d=\"M17 3a2.85 2.85 0 114 4L7.5 20.5 2 22l1.5-5.5L17 3z\"/>',\n 'rect-icon': '<rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"/>',\n 'circle-icon': '<circle cx=\"12\" cy=\"12\" r=\"10\"/>',\n 'text-icon': '<path d=\"M4 7V4h16v3M9 20h6M12 4v16\"/>',\n };\n const isActive = this.tool === tool;\n return `\n <button class=\"tool-btn ${isActive ? 'active' : ''}\" data-tool=\"${tool}\" title=\"${title}\">\n <svg class=\"icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n ${icons[iconClass]}\n </svg>\n </button>\n `;\n }\n\n // 获取样式\n private getStyles(): string {\n return `\n :host {\n display: block;\n width: 100%;\n height: 100%;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n\n * {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n }\n\n .hidden {\n display: none !important;\n }\n\n .editor-container {\n display: flex;\n width: 100%;\n height: 100%;\n background: #f1f5f9;\n }\n\n /* 工具栏 */\n .toolbar {\n width: 64px;\n background: #ffffff;\n border-right: 1px solid #e2e8f0;\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 12px 8px;\n gap: 4px;\n }\n\n .tool-btn {\n width: 44px;\n height: 44px;\n border: none;\n background: transparent;\n border-radius: 12px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #64748b;\n transition: all 0.2s;\n }\n\n .tool-btn:hover {\n background: #f1f5f9;\n color: #4f46e5;\n }\n\n .tool-btn.active {\n background: #4f46e5;\n color: #ffffff;\n box-shadow: 0 4px 12px rgba(79, 70, 229, 0.3);\n transform: scale(1.05);\n }\n\n .tool-btn:disabled {\n color: #cbd5e1;\n cursor: not-allowed;\n }\n\n .tool-btn:disabled:hover {\n background: transparent;\n color: #cbd5e1;\n }\n\n .icon {\n width: 20px;\n height: 20px;\n }\n\n .divider {\n width: 32px;\n height: 1px;\n background: #e2e8f0;\n margin: 8px 0;\n }\n\n .spacer {\n flex: 1;\n }\n\n .color-picker {\n width: 32px;\n height: 32px;\n border: 2px solid #e2e8f0;\n border-radius: 50%;\n cursor: pointer;\n padding: 0;\n overflow: hidden;\n -webkit-appearance: none;\n }\n\n .color-picker::-webkit-color-swatch-wrapper {\n padding: 0;\n }\n\n .color-picker::-webkit-color-swatch {\n border: none;\n border-radius: 50%;\n }\n\n /* 主区域 */\n .main-area {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n /* 顶部栏 */\n .top-bar {\n height: 56px;\n background: #ffffff;\n border-bottom: 1px solid #e2e8f0;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0 16px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);\n }\n\n .top-bar-left, .top-bar-right {\n display: flex;\n align-items: center;\n gap: 16px;\n }\n\n .title {\n font-size: 16px;\n font-weight: 600;\n color: #334155;\n }\n\n .selection-info {\n display: none;\n align-items: center;\n gap: 8px;\n background: #eef2ff;\n padding: 4px 12px;\n border-radius: 20px;\n border: 1px solid #c7d2fe;\n }\n\n .selection-info.visible {\n display: flex;\n }\n\n .selection-label {\n font-size: 12px;\n font-weight: 600;\n color: #4f46e5;\n text-transform: uppercase;\n }\n\n .delete-btn {\n background: none;\n border: none;\n color: #ef4444;\n cursor: pointer;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .delete-btn:hover {\n color: #dc2626;\n }\n\n .zoom-controls, .file-controls {\n display: flex;\n align-items: center;\n background: #f1f5f9;\n border-radius: 8px;\n padding: 4px;\n }\n\n .zoom-btn, .file-btn {\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #475569;\n transition: all 0.2s;\n }\n\n .zoom-btn:hover, .file-btn:hover {\n color: #4f46e5;\n }\n\n .zoom-text {\n padding: 4px 8px;\n font-size: 12px;\n font-weight: 500;\n color: #475569;\n background: transparent;\n border: none;\n cursor: pointer;\n min-width: 50px;\n text-align: center;\n }\n\n .zoom-text:hover {\n color: #4f46e5;\n }\n\n /* 画布容器 */\n .canvas-container {\n flex: 1;\n position: relative;\n background: #f1f5f9;\n overflow: hidden;\n }\n\n .main-canvas {\n position: absolute;\n inset: 0;\n display: block;\n cursor: crosshair;\n touch-action: none;\n }\n\n /* 小地图 */\n .minimap-wrapper {\n position: absolute;\n top: 16px;\n right: 16px;\n z-index: 30;\n border-radius: 12px;\n overflow: hidden;\n box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n padding: 2px;\n }\n\n .minimap-wrapper > * {\n background: #ffffff;\n }\n\n .minimap-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: linear-gradient(to right, #f8fafc, #f1f5f9);\n border-bottom: 1px solid #e2e8f0;\n font-size: 12px;\n font-weight: 600;\n color: #475569;\n border-radius: 10px 10px 0 0;\n }\n\n .minimap-icon {\n width: 12px;\n height: 12px;\n color: #4f46e5;\n }\n\n .minimap-canvas {\n cursor: pointer;\n background: #f8fafc;\n border-radius: 0 0 10px 10px;\n display: block;\n }\n\n .minimap-canvas:hover {\n filter: brightness(1.05);\n }\n\n /* 文本输入 */\n .text-input-container {\n position: absolute;\n z-index: 20;\n }\n\n .text-input {\n padding: 8px 12px;\n border: 2px solid #4f46e5;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n outline: none;\n min-width: 200px;\n font-size: 16px;\n }\n\n /* 空画布提示 */\n .empty-hint {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n pointer-events: none;\n opacity: 0.4;\n }\n\n .empty-hint h3 {\n font-size: 24px;\n font-weight: 700;\n color: #94a3b8;\n margin-bottom: 8px;\n }\n\n .empty-hint p {\n color: #94a3b8;\n }\n `;\n }\n}\n\n// 注册 Web Component\nif (typeof window !== 'undefined' && !customElements.get('canvas-drawing-editor')) {\n customElements.define('canvas-drawing-editor', CanvasDrawingEditor);\n}\n"],"names":["defaultConfig","CanvasDrawingEditor","name","oldValue","newValue","e","rect","clientX","clientY","x","y","obj","r","c","t","width","p","minX","pt","maxX","minY","maxY","bounds","handleSize","handles","handle","img","previousState","o","selectedObj","newObj","mouseX","mouseY","delta","newScale","centerX","centerY","clampedScale","mouseXBeforeZoom","mouseYBeforeZoom","newPanOffsetX","newPanOffsetY","zoomText","tool","btn","screenX","screenY","text","value","_b","_a","existingObj","screenPos","clickedObject","id","dx","dy","newX","newY","newWidth","newHeight","radius","origT","scaleFactor","origP","scaleX","scaleY","textObj","ctx","isMinimap","i","imgObj","corner","minimap","mainCanvas","minimapScale","canvasW","canvasH","offsetX","offsetY","clickX","clickY","relX","relY","canvasX","canvasY","viewportCenterX","viewportCenterY","input","file","reader","event","dataUrl","maxSize","height","ratio","data","imageElement","rest","json","blob","url","a","err","tempCanvas","tempCtx","selectionInfo","typeLabel","deleteBtn","undoBtn","emptyHint","colorPicker","imageInput","zoomInBtn","zoomOutBtn","saveJsonBtn","loadJsonInput","exportPngBtn","iconClass","title","icons"],"mappings":"4OAsEA,MAAMA,EAA8B,CAClC,MAAO,gBACP,WAAY,GACZ,cAAe,GACf,WAAY,GACZ,SAAU,GACV,UAAW,GACX,SAAU,GACV,aAAc,GACd,WAAY,GACZ,WAAY,GACZ,UAAW,GACX,YAAa,EACf,EAKO,MAAMC,UAA4B,WAAY,CA6DnD,aAAc,CACZ,MAAA,EA7CF,KAAQ,OAAuB,CAAE,GAAGD,CAAA,EAGpC,KAAQ,QAA0B,CAAA,EAClC,KAAQ,WAA4B,KACpC,KAAQ,KAAiB,SACzB,KAAQ,MAAgB,UACxB,KAAQ,UAAoB,EAG5B,KAAQ,WAAsB,GAC9B,KAAQ,UAA0B,KAClC,KAAQ,cAAqC,KAC7C,KAAQ,WAAoB,CAAE,EAAG,EAAG,EAAG,CAAA,EAGvC,KAAQ,mBAA8B,GACtC,KAAQ,aAAsB,CAAE,EAAG,EAAG,EAAG,CAAA,EACzC,KAAQ,mBAA4B,CAAE,EAAG,EAAG,EAAG,CAAA,EAC/C,KAAQ,cAA+B,KAGvC,KAAQ,WAAsB,GAC9B,KAAQ,aAA8B,KACtC,KAAQ,kBAAoF,KAC5F,KAAQ,qBAA4C,KAGpD,KAAQ,QAA4B,CAAA,EACpC,KAAQ,UAAiC,KAGzC,KAAQ,MAAgB,EACxB,KAAQ,UAAmB,CAAE,EAAG,EAAG,EAAG,CAAA,EAGtC,KAAQ,UAAqB,GAC7B,KAAQ,SAAkB,CAAE,EAAG,EAAG,EAAG,CAAA,EASnC,KAAK,OAAS,KAAK,aAAa,CAAE,KAAM,OAAQ,EAGhD,KAAK,kBAAoB,KAAK,aAAa,KAAK,IAAI,EACpD,KAAK,mBAAqB,KAAK,cAAc,KAAK,IAAI,EACtD,KAAK,iBAAmB,KAAK,YAAY,KAAK,IAAI,CACpD,CAGA,WAAW,oBAA+B,CACxC,MAAO,CACL,QAAS,cAAe,iBAAkB,cAAe,YACzD,aAAc,YAAa,gBAAiB,cAAe,cAC3D,aAAc,cAAA,CAElB,CAGA,mBAA0B,CACxB,KAAK,gBAAA,EACL,KAAK,OAAA,EACL,KAAK,oBAAA,EACL,KAAK,WAAA,CACP,CAGA,sBAA6B,CAC3B,KAAK,qBAAA,CACP,CAGA,yBAAyBE,EAAcC,EAAyBC,EAA+B,CACzFD,IAAaC,IACjB,KAAK,gBAAA,EACD,KAAK,WACP,KAAK,SAAA,EAET,CAGQ,iBAAwB,CAC9B,KAAK,OAAS,CACZ,MAAO,KAAK,aAAa,OAAO,GAAKJ,EAAc,MACnD,WAAY,KAAK,aAAa,aAAa,IAAM,QACjD,cAAe,KAAK,aAAa,gBAAgB,IAAM,QACvD,WAAY,KAAK,aAAa,aAAa,IAAM,QACjD,SAAU,KAAK,aAAa,WAAW,IAAM,QAC7C,UAAW,KAAK,aAAa,YAAY,IAAM,QAC/C,SAAU,KAAK,aAAa,WAAW,IAAM,QAC7C,aAAc,KAAK,aAAa,eAAe,IAAM,QACrD,WAAY,KAAK,aAAa,aAAa,IAAM,QACjD,WAAY,KAAK,aAAa,aAAa,IAAM,QACjD,UAAW,KAAK,aAAa,YAAY,IAAM,QAC/C,YAAa,KAAK,aAAa,cAAc,IAAM,OAAA,CAEvD,CAGQ,YAAqB,CAC3B,OAAO,KAAK,SAAS,SAAS,EAAE,EAAE,OAAO,EAAG,CAAC,CAC/C,CAGQ,qBAA4B,CAClC,OAAO,iBAAiB,SAAU,KAAK,iBAAiB,EACxD,OAAO,iBAAiB,UAAW,KAAK,kBAAkB,CAC5D,CAGQ,sBAA6B,CACnC,OAAO,oBAAoB,SAAU,KAAK,iBAAiB,EAC3D,OAAO,oBAAoB,UAAW,KAAK,kBAAkB,EACzD,KAAK,QACP,KAAK,OAAO,oBAAoB,QAAS,KAAK,gBAAgB,CAElE,CAGQ,cAAqB,CAC3B,KAAK,WAAA,CACP,CAGQ,YAAmB,CACrB,CAAC,KAAK,iBAAmB,CAAC,KAAK,QAGnC,sBAAsB,IAAM,CAC1B,KAAK,OAAO,MAAQ,KAAK,gBAAgB,YACzC,KAAK,OAAO,OAAS,KAAK,gBAAgB,aAC1C,KAAK,aAAA,EACL,KAAK,cAAA,CACP,CAAC,CACH,CAGQ,YAAYK,EAAmC,CACrD,MAAMC,EAAO,KAAK,OAAO,sBAAA,EACzB,IAAIC,EAAiBC,EAErB,GAAI,YAAaH,GAAKA,EAAE,QAAQ,OAAS,EACvCE,EAAUF,EAAE,QAAQ,CAAC,EAAE,QACvBG,EAAUH,EAAE,QAAQ,CAAC,EAAE,gBACd,YAAaA,EACtBE,EAAUF,EAAE,QACZG,EAAUH,EAAE,YAEZ,OAAO,CAAE,EAAG,EAAG,EAAG,CAAA,EAGpB,MAAMI,GAAKF,EAAUD,EAAK,KAAO,KAAK,UAAU,GAAK,KAAK,MACpDI,GAAKF,EAAUF,EAAK,IAAM,KAAK,UAAU,GAAK,KAAK,MACzD,MAAO,CAAE,EAAAG,EAAG,EAAAC,CAAA,CACd,CAGQ,aAAaL,EAAmC,CACtD,MAAMC,EAAO,KAAK,OAAO,sBAAA,EACzB,IAAIC,EAAiBC,EAErB,GAAI,YAAaH,GAAKA,EAAE,QAAQ,OAAS,EACvCE,EAAUF,EAAE,QAAQ,CAAC,EAAE,QACvBG,EAAUH,EAAE,QAAQ,CAAC,EAAE,gBACd,YAAaA,EACtBE,EAAUF,EAAE,QACZG,EAAUH,EAAE,YAEZ,OAAO,CAAE,EAAG,EAAG,EAAG,CAAA,EAGpB,MAAO,CAAE,EAAGE,EAAUD,EAAK,KAAM,EAAGE,EAAUF,EAAK,GAAA,CACrD,CAGQ,gBAAgBK,EAA4E,CAClG,OAAQA,EAAI,KAAA,CACV,IAAK,YACL,IAAK,QAAS,CACZ,MAAMC,EAAID,EACV,MAAO,CAAE,EAAGC,EAAE,EAAG,EAAGA,EAAE,EAAG,MAAOA,EAAE,MAAO,OAAQA,EAAE,MAAA,CACrD,CACA,IAAK,SAAU,CACb,MAAMC,EAAIF,EACV,MAAO,CAAE,EAAGE,EAAE,EAAIA,EAAE,OAAQ,EAAGA,EAAE,EAAIA,EAAE,OAAQ,MAAOA,EAAE,OAAS,EAAG,OAAQA,EAAE,OAAS,CAAA,CACzF,CACA,IAAK,OAAQ,CACX,MAAMC,EAAIH,EACJI,EAAQD,EAAE,KAAK,OAASA,EAAE,SAAW,GAC3C,MAAO,CAAE,EAAGA,EAAE,EAAG,EAAGA,EAAE,EAAIA,EAAE,SAAU,MAAAC,EAAO,OAAQD,EAAE,QAAA,CACzD,CACA,IAAK,OAAQ,CACX,MAAME,EAAIL,EACV,GAAIK,EAAE,OAAO,SAAW,EAAG,MAAO,CAAE,EAAG,EAAG,EAAG,EAAG,MAAO,EAAG,OAAQ,CAAA,EAClE,MAAMC,EAAO,KAAK,IAAI,GAAGD,EAAE,OAAO,IAAIE,GAAMA,EAAG,CAAC,CAAC,EAC3CC,EAAO,KAAK,IAAI,GAAGH,EAAE,OAAO,IAAIE,GAAMA,EAAG,CAAC,CAAC,EAC3CE,EAAO,KAAK,IAAI,GAAGJ,EAAE,OAAO,IAAIE,GAAMA,EAAG,CAAC,CAAC,EAC3CG,EAAO,KAAK,IAAI,GAAGL,EAAE,OAAO,IAAIE,GAAMA,EAAG,CAAC,CAAC,EACjD,MAAO,CAAE,EAAGD,EAAM,EAAGG,EAAM,MAAOD,EAAOF,EAAM,OAAQI,EAAOD,CAAA,CAChE,CAAA,CAEF,MAAO,CAAE,EAAG,EAAG,EAAG,EAAG,MAAO,EAAG,OAAQ,CAAA,CACzC,CAGQ,uBAAuBT,EAAmBF,EAAWC,EAA0B,CACrF,MAAMY,EAAS,KAAK,gBAAgBX,CAAG,EACjCY,EAAa,EAEbC,EAAU,CACd,CAAE,KAAM,KAAM,EAAGF,EAAO,EAAG,EAAGA,EAAO,CAAA,EACrC,CAAE,KAAM,KAAM,EAAGA,EAAO,EAAIA,EAAO,MAAO,EAAGA,EAAO,CAAA,EACpD,CAAE,KAAM,KAAM,EAAGA,EAAO,EAAG,EAAGA,EAAO,EAAIA,EAAO,MAAA,EAChD,CAAE,KAAM,KAAM,EAAGA,EAAO,EAAIA,EAAO,MAAO,EAAGA,EAAO,EAAIA,EAAO,MAAA,CAAO,EAGxE,UAAWG,KAAUD,EACnB,GAAI,KAAK,IAAIf,EAAIgB,EAAO,CAAC,GAAKF,GAAc,KAAK,IAAIb,EAAIe,EAAO,CAAC,GAAKF,EACpE,OAAOE,EAAO,KAGlB,OAAO,IACT,CAGQ,MAAMd,EAAmBF,EAAWC,EAAoB,CAC9D,OAAQC,EAAI,KAAA,CACV,IAAK,YAAa,CAChB,MAAMC,EAAID,EACV,OAAOF,GAAKG,EAAE,GAAKH,GAAKG,EAAE,EAAIA,EAAE,OAASF,GAAKE,EAAE,GAAKF,GAAKE,EAAE,EAAIA,EAAE,MACpE,CACA,IAAK,SAAU,CACb,MAAMC,EAAIF,EAEV,OADa,KAAK,KAAK,KAAK,IAAIF,EAAII,EAAE,EAAG,CAAC,EAAI,KAAK,IAAIH,EAAIG,EAAE,EAAG,CAAC,CAAC,GACnDA,EAAE,MACnB,CACA,IAAK,QAAS,CACZ,MAAMa,EAAMf,EACZ,OAAOF,GAAKiB,EAAI,GAAKjB,GAAKiB,EAAI,EAAIA,EAAI,OAAShB,GAAKgB,EAAI,GAAKhB,GAAKgB,EAAI,EAAIA,EAAI,MAChF,CACA,IAAK,OAAQ,CACX,MAAMZ,EAAIH,EACV,OAAOF,GAAKK,EAAE,GAAKL,GAAKK,EAAE,EAAKA,EAAE,KAAK,OAASA,EAAE,SAAW,IAAQJ,GAAKI,EAAE,EAAIA,EAAE,UAAYJ,GAAKI,EAAE,CACtG,CACA,IAAK,OAAQ,CACX,MAAME,EAAIL,EACV,GAAIK,EAAE,OAAO,SAAW,EAAG,MAAO,GAClC,MAAMC,EAAO,KAAK,IAAI,GAAGD,EAAE,OAAO,IAAIE,GAAMA,EAAG,CAAC,CAAC,EAC3CC,EAAO,KAAK,IAAI,GAAGH,EAAE,OAAO,IAAIE,GAAMA,EAAG,CAAC,CAAC,EAC3CE,EAAO,KAAK,IAAI,GAAGJ,EAAE,OAAO,IAAIE,GAAMA,EAAG,CAAC,CAAC,EAC3CG,EAAO,KAAK,IAAI,GAAGL,EAAE,OAAO,IAAIE,GAAMA,EAAG,CAAC,CAAC,EACjD,OAAOT,GAAKQ,GAAQR,GAAKU,GAAQT,GAAKU,GAAQV,GAAKW,CACrD,CAAA,CAEF,MAAO,EACT,CAGQ,aAAoB,CAC1B,KAAK,QAAQ,KAAK,KAAK,MAAM,KAAK,UAAU,KAAK,OAAO,CAAC,CAAC,CAC5D,CAGQ,MAAa,CACnB,GAAI,KAAK,QAAQ,SAAW,EAAG,OAC/B,MAAMM,EAAgB,KAAK,QAAQ,IAAA,EAC/BA,IACF,KAAK,QAAUA,EACf,KAAK,WAAa,KAClB,KAAK,aAAA,EACL,KAAK,cAAA,EACL,KAAK,oBAAA,EAET,CAGQ,gBAAuB,CACzB,KAAK,aACP,KAAK,YAAA,EACL,KAAK,QAAU,KAAK,QAAQ,UAAYC,EAAE,KAAO,KAAK,UAAU,EAChE,KAAK,WAAa,KAClB,KAAK,aAAA,EACL,KAAK,cAAA,EACL,KAAK,SAAA,EACL,KAAK,oBAAA,EAET,CAGQ,cAAqB,CAC3B,GAAI,KAAK,WAAY,CACnB,MAAMC,EAAc,KAAK,QAAQ,QAAUD,EAAE,KAAO,KAAK,UAAU,EAC/DC,IACF,KAAK,UAAY,KAAK,MAAM,KAAK,UAAUA,CAAW,CAAC,EAE3D,CACF,CAGQ,aAAoB,CAC1B,GAAI,KAAK,UAAW,CAClB,KAAK,YAAA,EACL,MAAMC,EAAS,CACb,GAAG,KAAK,MAAM,KAAK,UAAU,KAAK,SAAS,CAAC,EAC5C,GAAI,KAAK,WAAA,EACT,EAAG,KAAK,UAAU,EAAI,GACtB,EAAG,KAAK,UAAU,EAAI,EAAA,EAEpBA,EAAO,OAAS,QAAUA,EAAO,SACnCA,EAAO,OAASA,EAAO,OAAO,IAAKZ,IAAe,CAChD,EAAGA,EAAG,EAAI,GACV,EAAGA,EAAG,EAAI,EAAA,EACV,GAEJ,KAAK,QAAQ,KAAKY,CAAM,EACxB,KAAK,WAAaA,EAAO,GACzB,KAAK,UAAYA,EACjB,KAAK,aAAA,EACL,KAAK,cAAA,EACL,KAAK,SAAA,EACL,KAAK,oBAAA,CACP,CACF,CAGQ,qBAA4B,CAClC,KAAK,cAAc,IAAI,YAAY,gBAAiB,CAClD,QAAS,GACT,SAAU,GACV,OAAQ,CAAE,QAAS,KAAK,OAAA,CAAQ,CACjC,CAAC,CACJ,CAGQ,cAAczB,EAAwB,CAC5C,GAAI,MAAK,mBAGT,KAAKA,EAAE,SAAWA,EAAE,UAAYA,EAAE,MAAQ,IAAK,CAC7CA,EAAE,eAAA,EACF,KAAK,KAAA,EACL,MACF,CAGA,IAAKA,EAAE,SAAWA,EAAE,UAAYA,EAAE,MAAQ,IAAK,CACzC,KAAK,aACPA,EAAE,eAAA,EACF,KAAK,aAAA,GAEP,MACF,CAGA,IAAKA,EAAE,SAAWA,EAAE,UAAYA,EAAE,MAAQ,IAAK,CACzC,KAAK,YACPA,EAAE,eAAA,EACF,KAAK,YAAA,GAEP,MACF,CAGA,IAAKA,EAAE,MAAQ,UAAYA,EAAE,MAAQ,cAAgB,KAAK,WAAY,CACpEA,EAAE,eAAA,EACF,KAAK,eAAA,EACL,MACF,CAGA,GAAI,CAACA,EAAE,SAAW,CAACA,EAAE,QACnB,OAAQA,EAAE,IAAI,YAAA,EAAY,CACxB,IAAK,IACH,KAAK,QAAQ,QAAQ,EACrB,MACF,IAAK,IACL,IAAK,IACH,KAAK,QAAQ,QAAQ,EACrB,MACF,IAAK,IACH,KAAK,QAAQ,WAAW,EACxB,MACF,IAAK,IACH,KAAK,QAAQ,QAAQ,EACrB,MACF,IAAK,IACH,KAAK,QAAQ,MAAM,EACnB,MACF,IAAK,SACH,KAAK,WAAa,KAClB,KAAK,cAAA,EACL,KAAK,aAAA,EACL,KAAK,SAAA,EACL,KAAA,EAGR,CAGQ,YAAYA,EAAqB,CACvCA,EAAE,eAAA,EACF,MAAMC,EAAO,KAAK,OAAO,sBAAA,EACnByB,EAAS1B,EAAE,QAAUC,EAAK,KAC1B0B,EAAS3B,EAAE,QAAUC,EAAK,IAE1B2B,EAAQ5B,EAAE,OAAS,EAAI,GAAM,IAC7B6B,EAAW,KAAK,MAAQD,EAE9B,KAAK,YAAYC,EAAUH,EAAQC,CAAM,CAC3C,CAGQ,YAAYE,EAAkBC,EAAiBC,EAAuB,CAC5E,MAAMC,EAAe,KAAK,IAAI,KAAK,IAAIH,EAAU,EAAG,EAAG,CAAC,EAElDI,GAAoBH,EAAU,KAAK,UAAU,GAAK,KAAK,MACvDI,GAAoBH,EAAU,KAAK,UAAU,GAAK,KAAK,MAEvDI,EAAgBL,EAAUG,EAAmBD,EAC7CI,EAAgBL,EAAUG,EAAmBF,EAEnD,KAAK,MAAQA,EACb,KAAK,UAAY,CAAE,EAAGG,EAAe,EAAGC,CAAA,EAExC,KAAK,aAAA,EACL,KAAK,cAAA,EACL,KAAK,kBAAA,CACP,CAGQ,QAAe,CACrB,MAAMN,EAAU,KAAK,OAAO,MAAQ,EAC9BC,EAAU,KAAK,OAAO,OAAS,EACrC,KAAK,YAAY,KAAK,MAAQ,IAAKD,EAASC,CAAO,CACrD,CAGQ,SAAgB,CACtB,MAAMD,EAAU,KAAK,OAAO,MAAQ,EAC9BC,EAAU,KAAK,OAAO,OAAS,EACrC,KAAK,YAAY,KAAK,MAAQ,IAAKD,EAASC,CAAO,CACrD,CAGQ,WAAkB,CACxB,KAAK,MAAQ,EACb,KAAK,UAAY,CAAE,EAAG,EAAG,EAAG,CAAA,EAC5B,KAAK,aAAA,EACL,KAAK,cAAA,EACL,KAAK,kBAAA,CACP,CAGQ,mBAA0B,CAChC,MAAMM,EAAW,KAAK,OAAO,cAAc,YAAY,EACnDA,IACFA,EAAS,YAAc,GAAG,KAAK,MAAM,KAAK,MAAQ,GAAG,CAAC,IAE1D,CAGQ,QAAQC,EAAsB,CACpC,KAAK,KAAOA,EACZ,KAAK,kBAAA,CACP,CAGQ,mBAA0B,CAChB,KAAK,OAAO,iBAAiB,WAAW,EAChD,QAAQC,GAAO,CACLA,EAAI,aAAa,WAAW,IAC5B,KAAK,KACnBA,EAAI,UAAU,IAAI,QAAQ,EAE1BA,EAAI,UAAU,OAAO,QAAQ,CAEjC,CAAC,CACH,CAGQ,eAAsB,CAC5B,KAAK,mBAAqB,GACtB,KAAK,qBACP,KAAK,mBAAmB,MAAM,QAAU,QAE1C,KAAK,cAAgB,IACvB,CAGQ,cAAcC,EAAiBC,EAAiBC,EAAe,GAAU,CAC/E,KAAK,mBAAqB,GAC1B,KAAK,mBAAqB,CAAE,EAAGF,EAAS,EAAGC,CAAA,EAEvC,KAAK,oBAAsB,KAAK,YAClC,KAAK,mBAAmB,MAAM,QAAU,QACxC,KAAK,mBAAmB,MAAM,KAAO,GAAGD,CAAO,KAC/C,KAAK,mBAAmB,MAAM,IAAM,GAAGC,EAAU,EAAE,KACnD,KAAK,UAAU,MAAQC,EACvB,KAAK,UAAU,MAAM,MAAQ,KAAK,MAClC,WAAW,IAAM,CACf,KAAK,UAAU,MAAA,EACXA,GAAM,KAAK,UAAU,OAAA,CAC3B,EAAG,CAAC,EAER,CAGQ,YAAmB,SACzB,MAAMC,GAAQC,GAAAC,EAAA,KAAK,YAAL,YAAAA,EAAgB,QAAhB,YAAAD,EAAuB,OACrC,GAAID,EAAO,CACT,GAAI,KAAK,cAAe,CACtB,MAAMG,EAAc,KAAK,QAAQ,QAAUvB,EAAE,KAAO,KAAK,aAAa,EAClEuB,GAAeA,EAAY,OAASH,IACtC,KAAK,YAAA,EACLG,EAAY,KAAOH,GAErB,KAAK,WAAa,KAAK,aACzB,KAAO,CACL,KAAK,YAAA,EACL,MAAMlB,EAAqB,CACzB,GAAI,KAAK,WAAA,EACT,KAAM,OACN,EAAG,KAAK,aAAa,EACrB,EAAG,KAAK,aAAa,EACrB,KAAMkB,EACN,SAAU,GACV,MAAO,KAAK,MACZ,UAAW,KAAK,SAAA,EAElB,KAAK,QAAQ,KAAKlB,CAAM,EACxB,KAAK,WAAaA,EAAO,EAC3B,CACA,KAAK,oBAAA,CACP,CACA,KAAK,cAAA,EACL,KAAK,QAAQ,QAAQ,EACrB,KAAK,aAAA,EACL,KAAK,cAAA,EACL,KAAK,SAAA,CACP,CAGQ,wBAAwBzB,EAAkC,CAChE,KAAM,CAAE,EAAAI,EAAG,EAAAC,CAAA,EAAM,KAAK,YAAYL,CAAC,EAC7B+C,EAAY,KAAK,aAAa/C,CAAC,EASrC,GARA,KAAK,UAAY,CAAE,EAAAI,EAAG,EAAAC,CAAA,EACtB,KAAK,WAAa,GAGd,KAAK,oBAAsB,KAAK,OAAS,QAC3C,KAAK,WAAA,EAGH,KAAK,OAAS,SAAU,CAE1B,GAAI,KAAK,WAAY,CACnB,MAAMmB,EAAc,KAAK,QAAQ,QAAU,EAAE,KAAO,KAAK,UAAU,EACnE,GAAIA,EAAa,CACf,MAAMJ,EAAS,KAAK,uBAAuBI,EAAapB,EAAGC,CAAC,EAC5D,GAAIe,EAAQ,CACV,KAAK,YAAA,EACL,KAAK,WAAa,GAClB,KAAK,aAAeA,EACpB,KAAK,kBAAoB,KAAK,gBAAgBI,CAAW,EACzD,KAAK,qBAAuB,KAAK,MAAM,KAAK,UAAUA,CAAW,CAAC,EAClE,MACF,CACF,CACF,CAGA,MAAMwB,EAAgB,CAAC,GAAG,KAAK,OAAO,EAAE,QAAA,EAAU,QAAY,KAAK,MAAM1C,EAAKF,EAAGC,CAAC,CAAC,EAE/E2C,GACF,KAAK,WAAaA,EAAc,GAChC,KAAK,WAAa,CAAE,EAAG5C,EAAI4C,EAAc,EAAG,EAAG3C,EAAI2C,EAAc,CAAA,EACjE,KAAK,YAAA,EACL,KAAK,SAAA,IAGL,KAAK,WAAa,KAClB,KAAK,UAAY,GACjB,KAAK,SAAWD,EAChB,KAAK,SAAA,EAET,SAAW,KAAK,OAAS,OAEvB,KAAK,aAAe,CAAE,EAAA3C,EAAG,EAAAC,CAAA,EACzB,KAAK,cAAc0C,EAAU,EAAGA,EAAU,CAAC,EAC3C,KAAK,WAAa,OACb,CAEL,KAAK,YAAA,EACL,MAAME,EAAK,KAAK,WAAA,EACZ,KAAK,OAAS,YAChB,KAAK,cAAgB,CAAE,GAAAA,EAAI,KAAM,YAAa,EAAA7C,EAAG,EAAAC,EAAG,MAAO,EAAG,OAAQ,EAAG,MAAO,KAAK,MAAO,UAAW,KAAK,SAAA,EACnG,KAAK,OAAS,SACvB,KAAK,cAAgB,CAAE,GAAA4C,EAAI,KAAM,SAAU,EAAA7C,EAAG,EAAAC,EAAG,OAAQ,EAAG,MAAO,KAAK,MAAO,UAAW,KAAK,SAAA,EACtF,KAAK,OAAS,WACvB,KAAK,cAAgB,CAAE,GAAA4C,EAAI,KAAM,OAAQ,EAAA7C,EAAG,EAAAC,EAAG,OAAQ,CAAC,CAAE,EAAAD,EAAG,EAAAC,CAAA,CAAG,EAAG,MAAO,KAAK,MAAO,UAAW,KAAK,SAAA,EAE1G,CAEA,KAAK,aAAA,CACP,CAGQ,wBAAwBL,EAAkC,CAEhE,GAAI,KAAK,UAAW,CAClB,MAAM+C,EAAY,KAAK,aAAa/C,CAAC,EAC/BkD,EAAKH,EAAU,EAAI,KAAK,SAAS,EACjCI,EAAKJ,EAAU,EAAI,KAAK,SAAS,EACvC,KAAK,UAAY,CAAE,EAAG,KAAK,UAAU,EAAIG,EAAI,EAAG,KAAK,UAAU,EAAIC,CAAA,EACnE,KAAK,SAAWJ,EAChB,KAAK,aAAA,EACL,KAAK,cAAA,EACL,MACF,CAEA,GAAI,CAAC,KAAK,YAAc,CAAC,KAAK,UAAW,OACzC,KAAM,CAAE,EAAA3C,EAAG,EAAAC,CAAA,EAAM,KAAK,YAAYL,CAAC,EAGnC,GAAI,KAAK,YAAc,KAAK,YAAc,KAAK,cAAgB,KAAK,mBAAqB,KAAK,qBAAsB,CAClH,MAAMM,EAAM,KAAK,QAAQ,QAAUiB,EAAE,KAAO,KAAK,UAAU,EAC3D,GAAI,CAACjB,EAAK,OAEV,MAAM4C,EAAK9C,EAAI,KAAK,UAAU,EACxB+C,EAAK9C,EAAI,KAAK,UAAU,EAC9B,IAAI+C,EAAO,KAAK,kBAAkB,EAC9BC,EAAO,KAAK,kBAAkB,EAC9BC,EAAW,KAAK,kBAAkB,MAClCC,EAAY,KAAK,kBAAkB,OAiBvC,OAfI,KAAK,aAAa,SAAS,GAAG,IAAGD,EAAW,KAAK,kBAAkB,MAAQJ,GAC3E,KAAK,aAAa,SAAS,GAAG,IAChCE,EAAO,KAAK,kBAAkB,EAAIF,EAClCI,EAAW,KAAK,kBAAkB,MAAQJ,GAExC,KAAK,aAAa,SAAS,GAAG,IAAGK,EAAY,KAAK,kBAAkB,OAASJ,GAC7E,KAAK,aAAa,SAAS,GAAG,IAChCE,EAAO,KAAK,kBAAkB,EAAIF,EAClCI,EAAY,KAAK,kBAAkB,OAASJ,GAG9CG,EAAW,KAAK,IAAI,GAAIA,CAAQ,EAChCC,EAAY,KAAK,IAAI,GAAIA,CAAS,EAG1BjD,EAAI,KAAA,CACV,IAAK,YACL,IAAK,QACFA,EAAiC,EAAI8C,EACrC9C,EAAiC,EAAI+C,EACrC/C,EAAiC,MAAQgD,EACzChD,EAAiC,OAASiD,EAC3C,MACF,IAAK,SAAU,CACb,MAAMC,EAAS,KAAK,IAAIF,EAAUC,CAAS,EAAI,EAC9CjD,EAAqB,EAAI8C,EAAOI,EAChClD,EAAqB,EAAI+C,EAAOG,EAChClD,EAAqB,OAASkD,EAC/B,KACF,CACA,IAAK,OAAQ,CACX,MAAMC,EAAQ,KAAK,qBACbC,EAAcJ,EAAW,KAAK,kBAAkB,MACrDhD,EAAmB,EAAI8C,EACvB9C,EAAmB,EAAI+C,EAAOE,EAC9BjD,EAAmB,SAAW,KAAK,IAAI,EAAG,KAAK,MAAMmD,EAAM,SAAWC,CAAW,CAAC,EACnF,KACF,CACA,IAAK,OAAQ,CACX,MAAMC,EAAQ,KAAK,qBACbC,EAASN,EAAW,KAAK,kBAAkB,MAC3CO,EAASN,EAAY,KAAK,kBAAkB,OACjDjD,EAAmB,OAASqD,EAAM,OAAO,IAAI9C,IAAO,CACnD,EAAGuC,GAAQvC,EAAG,EAAI,KAAK,kBAAmB,GAAK+C,EAC/C,EAAGP,GAAQxC,EAAG,EAAI,KAAK,kBAAmB,GAAKgD,CAAA,EAC/C,EACF,KACF,CAAA,CAGF,KAAK,aAAA,EACL,KAAK,cAAA,EACL,MACF,CAGA,GAAI,KAAK,OAAS,UAAY,KAAK,WAAY,CAC7C,MAAMvD,EAAM,KAAK,QAAQ,QAAUiB,EAAE,KAAO,KAAK,UAAU,EAC3D,GAAIjB,EAAK,CACP,GAAIA,EAAI,OAAS,OAAQ,CACvB,MAAMK,EAAIL,EACJ4C,EAAK9C,EAAI,KAAK,UAAU,EACxB+C,EAAK9C,EAAI,KAAK,UAAU,EAC9BM,EAAE,OAASA,EAAE,OAAO,QAAW,CAAE,EAAGE,EAAG,EAAIqC,EAAI,EAAGrC,EAAG,EAAIsC,GAAK,EAC9D,KAAK,UAAY,CAAE,EAAA/C,EAAG,EAAAC,CAAA,CACxB,MACEC,EAAI,EAAIF,EAAI,KAAK,WAAW,EAC5BE,EAAI,EAAID,EAAI,KAAK,WAAW,EAE9B,KAAK,aAAA,EACL,KAAK,cAAA,CACP,CACF,SAAW,KAAK,cAAe,CAE7B,GAAI,KAAK,cAAc,OAAS,YAC7B,KAAK,cAA6B,MAAQD,EAAI,KAAK,cAAc,EACjE,KAAK,cAA6B,OAASC,EAAI,KAAK,cAAc,UAC1D,KAAK,cAAc,OAAS,SAAU,CAC/C,MAAMmD,EAAS,KAAK,KAAK,KAAK,IAAIpD,EAAI,KAAK,cAAc,EAAG,CAAC,EAAI,KAAK,IAAIC,EAAI,KAAK,cAAc,EAAG,CAAC,CAAC,EACrG,KAAK,cAA+B,OAASmD,CAChD,MAAW,KAAK,cAAc,OAAS,QACpC,KAAK,cAA6B,OAAO,KAAK,CAAE,EAAApD,EAAG,EAAAC,EAAG,EAEzD,KAAK,aAAA,CACP,CACF,CAGQ,uBAA8B,CACpC,KAAK,WAAa,GAClB,KAAK,UAAY,KACjB,KAAK,WAAa,GAClB,KAAK,aAAe,KACpB,KAAK,kBAAoB,KACzB,KAAK,qBAAuB,KAC5B,KAAK,UAAY,GAEb,KAAK,gBACP,KAAK,QAAQ,KAAK,KAAK,aAAa,EACpC,KAAK,cAAgB,KACrB,KAAK,oBAAA,GAGP,KAAK,aAAA,EACL,KAAK,cAAA,CACP,CAGQ,wBAAwBL,EAAqB,CACnDA,EAAE,eAAA,EACF,KAAM,CAAE,EAAAI,EAAG,EAAAC,CAAA,EAAM,KAAK,YAAYL,CAAC,EAE7BgD,EAAgB,CAAC,GAAG,KAAK,OAAO,EAAE,QAAA,EAAU,QAAY,KAAK,MAAM1C,EAAKF,EAAGC,CAAC,CAAC,EAEnF,GAAI2C,GAAiBA,EAAc,OAAS,OAAQ,CAClD,MAAMc,EAAUd,EAChB,KAAK,cAAgBc,EAAQ,GAC7B,KAAK,aAAe,CAAE,EAAGA,EAAQ,EAAG,EAAGA,EAAQ,CAAA,EAC/C,MAAMtB,EAAUsB,EAAQ,EAAI,KAAK,MAAQ,KAAK,UAAU,EAClDrB,EAAUqB,EAAQ,EAAI,KAAK,MAAQ,KAAK,UAAU,EACxD,KAAK,cAActB,EAASC,EAASqB,EAAQ,IAAI,EACjD,KAAK,QAAQ,QAAQ,CACvB,CACF,CAGQ,cAAqB,CAC3B,GAAK,KAAK,IAuBV,IApBA,KAAK,IAAI,UAAU,EAAG,EAAG,KAAK,OAAO,MAAO,KAAK,OAAO,MAAM,EAG9D,KAAK,IAAI,UAAY,UACrB,KAAK,IAAI,SAAS,EAAG,EAAG,KAAK,OAAO,MAAO,KAAK,OAAO,MAAM,EAG7D,KAAK,IAAI,KAAA,EACT,KAAK,IAAI,UAAU,KAAK,UAAU,EAAG,KAAK,UAAU,CAAC,EACrD,KAAK,IAAI,MAAM,KAAK,MAAO,KAAK,KAAK,EAGrC,KAAK,QAAQ,QAAQxD,GAAO,KAAK,WAAW,KAAK,IAAKA,EAAK,EAAK,CAAC,EAG7D,KAAK,eACP,KAAK,WAAW,KAAK,IAAK,KAAK,cAAe,EAAK,EAIjD,KAAK,YAAc,KAAK,OAAS,SAAU,CAC7C,MAAMkB,EAAc,KAAK,QAAQ,QAAUD,EAAE,KAAO,KAAK,UAAU,EAC/DC,GACF,KAAK,qBAAqB,KAAK,IAAKA,CAAW,CAEnD,CAEA,KAAK,IAAI,QAAA,EACX,CAGQ,WAAWuC,EAA+BzD,EAAmB0D,EAA0B,CAc7F,OAbAD,EAAI,UAAA,EACJA,EAAI,YAAczD,EAAI,MACtByD,EAAI,UAAYzD,EAAI,UACpByD,EAAI,UAAYzD,EAAI,MAGhB,CAAC0D,GAAa1D,EAAI,KAAO,KAAK,YAChCyD,EAAI,YAAc,yBAClBA,EAAI,WAAa,IAEjBA,EAAI,WAAa,EAGXzD,EAAI,KAAA,CACV,IAAK,YAAa,CAChB,MAAMC,EAAID,EACVyD,EAAI,WAAWxD,EAAE,EAAGA,EAAE,EAAGA,EAAE,MAAOA,EAAE,MAAM,EAC1C,KACF,CACA,IAAK,SAAU,CACb,MAAMC,EAAIF,EACVyD,EAAI,UAAA,EACJA,EAAI,IAAIvD,EAAE,EAAGA,EAAE,EAAGA,EAAE,OAAQ,EAAG,EAAI,KAAK,EAAE,EAC1CuD,EAAI,OAAA,EACJ,KACF,CACA,IAAK,OAAQ,CACX,MAAMpD,EAAIL,EACV,GAAIK,EAAE,OAAO,OAAS,EAAG,MACzBoD,EAAI,UAAA,EACJA,EAAI,QAAU,QACdA,EAAI,SAAW,QACfA,EAAI,OAAOpD,EAAE,OAAO,CAAC,EAAE,EAAGA,EAAE,OAAO,CAAC,EAAE,CAAC,EACvC,QAASsD,EAAI,EAAGA,EAAItD,EAAE,OAAO,OAAQsD,IACnCF,EAAI,OAAOpD,EAAE,OAAOsD,CAAC,EAAE,EAAGtD,EAAE,OAAOsD,CAAC,EAAE,CAAC,EAEzCF,EAAI,OAAA,EACJ,KACF,CACA,IAAK,OAAQ,CACX,MAAMtD,EAAIH,EACVyD,EAAI,KAAO,GAAGtD,EAAE,QAAQ,gBACxBsD,EAAI,SAAStD,EAAE,KAAMA,EAAE,EAAGA,EAAE,CAAC,EAC7B,KACF,CACA,IAAK,QAAS,CACZ,MAAMyD,EAAS5D,EACf,GAAI4D,EAAO,cAAgBA,EAAO,aAAa,SAC7CH,EAAI,UAAUG,EAAO,aAAcA,EAAO,EAAGA,EAAO,EAAGA,EAAO,MAAOA,EAAO,MAAM,UACzEA,EAAO,QAAS,CAEzB,MAAM7C,EAAM,IAAI,MAChBA,EAAI,OAAS,IAAM,CACjB6C,EAAO,aAAe7C,EACtB,KAAK,aAAA,CACP,EACAA,EAAI,IAAM6C,EAAO,OACnB,CACA,KACF,CAAA,CAEJ,CAGQ,qBAAqBH,EAA+BzD,EAAyB,CACnF,MAAMW,EAAS,KAAK,gBAAgBX,CAAG,EACjCY,EAAa,EAEnB6C,EAAI,WAAa,EACjBA,EAAI,UAAY,UAChBA,EAAI,YAAc,UAClBA,EAAI,UAAY,EAGA,CACd,CAAE,EAAG9C,EAAO,EAAG,EAAGA,EAAO,CAAA,EACzB,CAAE,EAAGA,EAAO,EAAIA,EAAO,MAAO,EAAGA,EAAO,CAAA,EACxC,CAAE,EAAGA,EAAO,EAAG,EAAGA,EAAO,EAAIA,EAAO,MAAA,EACpC,CAAE,EAAGA,EAAO,EAAIA,EAAO,MAAO,EAAGA,EAAO,EAAIA,EAAO,MAAA,CAAO,EAGpD,QAAQkD,GAAU,CACxBJ,EAAI,UAAA,EACJA,EAAI,KAAKI,EAAO,EAAIjD,EAAa,EAAGiD,EAAO,EAAIjD,EAAa,EAAGA,EAAYA,CAAU,EACrF6C,EAAI,KAAA,EACJA,EAAI,OAAA,CACN,CAAC,EAGDA,EAAI,YAAc,UAClBA,EAAI,UAAY,EAChBA,EAAI,YAAY,CAAC,EAAG,CAAC,CAAC,EACtBA,EAAI,WAAW9C,EAAO,EAAGA,EAAO,EAAGA,EAAO,MAAOA,EAAO,MAAM,EAC9D8C,EAAI,YAAY,EAAE,CACpB,CAGQ,eAAsB,CAC5B,GAAI,CAAC,KAAK,YAAc,CAAC,KAAK,OAAO,YAAa,OAElD,MAAMK,EAAU,KAAK,cACfC,EAAa,KAAK,OAExB,KAAK,WAAW,UAAU,EAAG,EAAGD,EAAQ,MAAOA,EAAQ,MAAM,EAG7D,MAAMR,EAASQ,EAAQ,MAAQC,EAAW,MACpCR,EAASO,EAAQ,OAASC,EAAW,OACrCC,EAAe,KAAK,IAAIV,EAAQC,CAAM,EAAI,IAE1CU,EAAUF,EAAW,MAAQC,EAC7BE,EAAUH,EAAW,OAASC,EAC9BG,GAAWL,EAAQ,MAAQG,GAAW,EACtCG,GAAWN,EAAQ,OAASI,GAAW,EAG7C,KAAK,WAAW,UAAY,UAC5B,KAAK,WAAW,SAASC,EAASC,EAASH,EAASC,CAAO,EAG3D,KAAK,WAAW,KAAA,EAChB,KAAK,WAAW,UAAUC,EAASC,CAAO,EAC1C,KAAK,WAAW,MAAMJ,EAAcA,CAAY,EAChD,KAAK,WAAW,UAAU,KAAK,UAAU,EAAG,KAAK,UAAU,CAAC,EAC5D,KAAK,WAAW,MAAM,KAAK,MAAO,KAAK,KAAK,GAGzB,KAAK,cAAgB,CAAC,GAAG,KAAK,QAAS,KAAK,aAAa,EAAI,KAAK,SAC1E,QAAQhE,GAAO,CAMxB,OALA,KAAK,WAAW,UAAYA,EAAI,MAChC,KAAK,WAAW,YAAcA,EAAI,MAClC,KAAK,WAAW,UAAY,KAAK,IAAIA,EAAI,UAAW,CAAC,EACrD,KAAK,WAAW,YAAY,EAAE,EAEtBA,EAAI,KAAA,CACV,IAAK,YAAa,CAChB,MAAMC,EAAID,EACV,KAAK,WAAW,WAAWC,EAAE,EAAGA,EAAE,EAAGA,EAAE,MAAOA,EAAE,MAAM,EACtD,KACF,CACA,IAAK,SAAU,CACb,MAAM,EAAID,EACV,KAAK,WAAW,UAAA,EAChB,KAAK,WAAW,IAAI,EAAE,EAAG,EAAE,EAAG,EAAE,OAAQ,EAAG,KAAK,GAAK,CAAC,EACtD,KAAK,WAAW,OAAA,EAChB,KACF,CACA,IAAK,OAAQ,CACX,MAAMK,EAAIL,EACNK,EAAE,OAAO,OAAS,IACpB,KAAK,WAAW,UAAA,EAChB,KAAK,WAAW,QAAU,QAC1B,KAAK,WAAW,SAAW,QAC3B,KAAK,WAAW,OAAOA,EAAE,OAAO,CAAC,EAAE,EAAGA,EAAE,OAAO,CAAC,EAAE,CAAC,EACnDA,EAAE,OAAO,QAAQE,GAAM,KAAK,WAAW,OAAOA,EAAG,EAAGA,EAAG,CAAC,CAAC,EACzD,KAAK,WAAW,OAAA,GAElB,KACF,CACA,IAAK,OAAQ,CACX,MAAMJ,EAAIH,EACV,KAAK,WAAW,KAAO,GAAGG,EAAE,QAAQ,gBACpC,KAAK,WAAW,SAASA,EAAE,KAAMA,EAAE,EAAGA,EAAE,CAAC,EACzC,KACF,CACA,IAAK,QAAS,CACZ,MAAMY,EAAMf,EACRe,EAAI,cACN,KAAK,WAAW,UAAUA,EAAI,aAAcA,EAAI,EAAGA,EAAI,EAAGA,EAAI,MAAOA,EAAI,MAAM,EAEjF,KACF,CAAA,CAEJ,CAAC,EAED,KAAK,WAAW,QAAA,EAGhB,KAAK,WAAW,YAAc,UAC9B,KAAK,WAAW,UAAY,EAC5B,KAAK,WAAW,WAAWoD,EAASC,EAASH,EAASC,CAAO,CAC/D,CAGQ,mBAAmBxE,EAAqB,CAC9C,MAAMC,EAAO,KAAK,cAAc,sBAAA,EAC1B0E,EAAS3E,EAAE,QAAUC,EAAK,KAC1B2E,EAAS5E,EAAE,QAAUC,EAAK,IAE1B2D,EAAS,KAAK,cAAc,MAAQ,KAAK,OAAO,MAChDC,EAAS,KAAK,cAAc,OAAS,KAAK,OAAO,OACjDS,EAAe,KAAK,IAAIV,EAAQC,CAAM,EAAI,IAE1CU,EAAU,KAAK,OAAO,MAAQD,EAC9BE,EAAU,KAAK,OAAO,OAASF,EAC/BG,GAAW,KAAK,cAAc,MAAQF,GAAW,EACjDG,GAAW,KAAK,cAAc,OAASF,GAAW,EAElDK,EAAOF,EAASF,EAChBK,EAAOF,EAASF,EAEhBK,GAAWF,EAAOP,EAAe,KAAK,UAAU,GAAK,KAAK,MAC1DU,GAAWF,EAAOR,EAAe,KAAK,UAAU,GAAK,KAAK,MAE1DW,EAAkB,KAAK,OAAO,MAAQ,EACtCC,EAAkB,KAAK,OAAO,OAAS,EAE7C,KAAK,UAAY,CACf,EAAGD,EAAkB,KAAK,MAAQF,EAClC,EAAGG,EAAkB,KAAK,MAAQF,CAAA,EAGpC,KAAK,aAAA,EACL,KAAK,cAAA,CACP,CAGQ,kBAAkBhF,EAAgB,CACxC,MAAMmF,EAAQnF,EAAE,OAChB,GAAI,CAACmF,EAAM,OAASA,EAAM,MAAM,SAAW,EAAG,OAE9C,MAAMC,EAAOD,EAAM,MAAM,CAAC,EACpBE,EAAS,IAAI,WAEnBA,EAAO,OAAUC,GAAU,OACzB,MAAMC,GAAU1C,EAAAyC,EAAM,SAAN,YAAAzC,EAAc,OACxBxB,EAAM,IAAI,MAChBA,EAAI,OAAS,IAAM,CACjB,KAAK,YAAA,EACL,MAAMmE,EAAU,IAChB,IAAI9E,EAAQW,EAAI,MACZoE,EAASpE,EAAI,OACjB,GAAIX,EAAQ8E,GAAWC,EAASD,EAAS,CACvC,MAAME,EAAQ,KAAK,IAAIF,EAAU9E,EAAO8E,EAAUC,CAAM,EACxD/E,GAASgF,EACTD,GAAUC,CACZ,CAEA,MAAMjE,EAAsB,CAC1B,GAAI,KAAK,WAAA,EACT,KAAM,QACN,EAAG,IACH,EAAG,IACH,MAAAf,EACA,OAAA+E,EACA,MAAO,UACP,UAAW,EACX,QAAAF,EACA,aAAclE,CAAA,EAEhB,KAAK,QAAQ,KAAKI,CAAM,EACxB,KAAK,WAAaA,EAAO,GACzB,KAAK,QAAQ,QAAQ,EACrB,KAAK,aAAA,EACL,KAAK,cAAA,EACL,KAAK,SAAA,EACL,KAAK,oBAAA,CACP,EACAJ,EAAI,IAAMkE,CACZ,EAEAF,EAAO,cAAcD,CAAI,EACzBD,EAAM,MAAQ,EAChB,CAGQ,UAAiB,CACvB,MAAMQ,EAAO,CACX,QAAS,MACT,QAAS,KAAK,QAAQ,IAAIrF,GAAO,CAC/B,KAAM,CAAE,aAAAsF,EAAc,GAAGC,CAAA,EAASvF,EAClC,OAAOuF,CACT,CAAC,CAAA,EAEGC,EAAO,KAAK,UAAUH,EAAM,KAAM,CAAC,EACnCI,EAAO,IAAI,KAAK,CAACD,CAAI,EAAG,CAAE,KAAM,mBAAoB,EACpDE,EAAM,IAAI,gBAAgBD,CAAI,EAC9BE,EAAI,SAAS,cAAc,GAAG,EACpCA,EAAE,KAAOD,EACTC,EAAE,SAAW,sBACbA,EAAE,MAAA,EACF,IAAI,gBAAgBD,CAAG,CACzB,CAGQ,SAAShG,EAAgB,CAC/B,MAAMmF,EAAQnF,EAAE,OAChB,GAAI,CAACmF,EAAM,OAASA,EAAM,MAAM,SAAW,EAAG,OAE9C,MAAMC,EAAOD,EAAM,MAAM,CAAC,EACpBE,EAAS,IAAI,WAEnBA,EAAO,OAAUC,GAAU,OACzB,GAAI,CACF,MAAMK,EAAO,KAAK,OAAM9C,EAAAyC,EAAM,SAAN,YAAAzC,EAAc,MAAgB,EAClD8C,EAAK,SAAW,MAAM,QAAQA,EAAK,OAAO,IAC5C,KAAK,YAAA,EACL,KAAK,QAAUA,EAAK,QACpB,KAAK,WAAa,KAGlB,KAAK,QAAQ,QAAQrF,GAAO,CAC1B,GAAIA,EAAI,OAAS,SAAYA,EAAoB,QAAS,CACxD,MAAMe,EAAM,IAAI,MAChBA,EAAI,OAAS,IAAM,CAChBf,EAAoB,aAAee,EACpC,KAAK,aAAA,EACL,KAAK,cAAA,CACP,EACAA,EAAI,IAAOf,EAAoB,OACjC,CACF,CAAC,EAED,KAAK,aAAA,EACL,KAAK,cAAA,EACL,KAAK,SAAA,EACL,KAAK,oBAAA,EAET,OAAS4F,EAAK,CACZ,QAAQ,MAAM,uBAAwBA,CAAG,CAC3C,CACF,EAEAb,EAAO,WAAWD,CAAI,EACtBD,EAAM,MAAQ,EAChB,CAGQ,WAAkB,CAExB,MAAMgB,EAAa,SAAS,cAAc,QAAQ,EAClDA,EAAW,MAAQ,KAAK,OAAO,MAC/BA,EAAW,OAAS,KAAK,OAAO,OAChC,MAAMC,EAAUD,EAAW,WAAW,IAAI,EAG1CC,EAAQ,UAAY,UACpBA,EAAQ,SAAS,EAAG,EAAGD,EAAW,MAAOA,EAAW,MAAM,EAG1DC,EAAQ,UAAU,KAAK,UAAU,EAAG,KAAK,UAAU,CAAC,EACpDA,EAAQ,MAAM,KAAK,MAAO,KAAK,KAAK,EAGpC,KAAK,QAAQ,QAAQ9F,GAAO,KAAK,WAAW8F,EAAS9F,EAAK,EAAI,CAAC,EAG/D,MAAM0F,EAAMG,EAAW,UAAU,WAAW,EACtCF,EAAI,SAAS,cAAc,GAAG,EACpCA,EAAE,KAAOD,EACTC,EAAE,SAAW,oBACbA,EAAE,MAAA,CACJ,CAGQ,UAAiB,CAEvB,MAAMI,EAAgB,KAAK,OAAO,cAAc,iBAAiB,EACjE,GAAIA,EACF,GAAI,KAAK,WAAY,CACnB,MAAM7E,EAAc,KAAK,QAAQ,QAAUD,EAAE,KAAO,KAAK,UAAU,EACnE,GAAIC,EAAa,CAQf,MAAM8E,EAPqC,CACzC,UAAa,KACb,OAAU,KACV,KAAQ,KACR,KAAQ,KACR,MAAS,IAAA,EAEkB9E,EAAY,IAAI,GAAKA,EAAY,KAC9D6E,EAAc,UAAY;AAAA,iDACaC,CAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAOhDD,EAAc,UAAU,IAAI,SAAS,EACrC,MAAME,EAAYF,EAAc,cAAc,aAAa,EACvDE,GACFA,EAAU,iBAAiB,QAAS,IAAM,KAAK,gBAAgB,CAEnE,CACF,MACEF,EAAc,UAAU,OAAO,SAAS,EACxCA,EAAc,UAAY,GAK9B,MAAMG,EAAU,KAAK,OAAO,cAAc,WAAW,EACjDA,IACFA,EAAQ,SAAW,KAAK,QAAQ,SAAW,GAI7C,MAAMC,EAAY,KAAK,OAAO,cAAc,aAAa,EACrDA,IACFA,EAAU,MAAM,QAAU,KAAK,QAAQ,SAAW,EAAI,OAAS,OAEnE,CAGQ,QAAe,CACrB,KAAK,OAAO,UAAY;AAAA,eACb,KAAK,WAAW;AAAA;AAAA;AAAA;AAAA,YAInB,KAAK,iBAAiB,SAAU,cAAe,QAAQ,CAAC;AAAA;AAAA,YAExD,KAAK,OAAO,WAAa,KAAK,iBAAiB,SAAU,cAAe,QAAQ,EAAI,EAAE;AAAA,YACtF,KAAK,OAAO,cAAgB,KAAK,iBAAiB,YAAa,YAAa,QAAQ,EAAI,EAAE;AAAA,YAC1F,KAAK,OAAO,WAAa,KAAK,iBAAiB,SAAU,cAAe,QAAQ,EAAI,EAAE;AAAA,YACtF,KAAK,OAAO,SAAW,KAAK,iBAAiB,OAAQ,YAAa,QAAQ,EAAI,EAAE;AAAA,YAChF,KAAK,OAAO,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAStB,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YASJ,KAAK,OAAO,UAAY;AAAA,8DAC0B,KAAK,KAAK;AAAA,YAC1D,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kCAQkB,KAAK,OAAO,KAAK;AAAA;AAAA;AAAA;AAAA,gBAInC,KAAK,OAAO,SAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAcrB,EAAE;AAAA,gBACH,KAAK,OAAO,YAAc,KAAK,OAAO,YAAc,KAAK,OAAO,aAAgB;AAAA;AAAA,oBAE7E,KAAK,OAAO,WAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAOvB,EAAE;AAAA,oBACJ,KAAK,OAAO,WAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAOvB,EAAE;AAAA,oBACJ,KAAK,OAAO,aAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAMzB,EAAE;AAAA;AAAA,gBAEN,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAQN,KAAK,OAAO,YAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAWxB,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAkBd,KAAK,UAAY,KAAK,OAAO,cAAc,mBAAmB,EAC9D,KAAK,QAAU,KAAK,OAAO,cAAc,UAAU,EACnD,KAAK,OAAS,KAAK,OAAO,cAAc,UAAU,EAClD,KAAK,gBAAkB,KAAK,OAAO,cAAc,mBAAmB,EACpE,KAAK,OAAS,KAAK,OAAO,cAAc,cAAc,EACtD,KAAK,IAAM,KAAK,OAAO,WAAW,IAAI,EAElC,KAAK,OAAO,cACd,KAAK,cAAgB,KAAK,OAAO,cAAc,iBAAiB,EAChE,KAAK,WAAa,KAAK,cAAc,WAAW,IAAI,GAGtD,KAAK,mBAAqB,KAAK,OAAO,cAAc,uBAAuB,EAC3E,KAAK,UAAY,KAAK,OAAO,cAAc,aAAa,EAGxD,KAAK,WAAA,CACP,CAGQ,YAAmB,CAEzB,KAAK,OAAO,iBAAiB,YAAczG,GAAM,KAAK,wBAAwBA,CAAC,CAAC,EAChF,KAAK,OAAO,iBAAiB,YAAcA,GAAM,KAAK,wBAAwBA,CAAC,CAAC,EAChF,KAAK,OAAO,iBAAiB,UAAW,IAAM,KAAK,uBAAuB,EAC1E,KAAK,OAAO,iBAAiB,aAAc,IAAM,KAAK,uBAAuB,EAC7E,KAAK,OAAO,iBAAiB,WAAaA,GAAM,KAAK,wBAAwBA,CAAC,CAAC,EAC/E,KAAK,OAAO,iBAAiB,aAAeA,GAAM,KAAK,wBAAwBA,CAAC,CAAC,EACjF,KAAK,OAAO,iBAAiB,YAAcA,GAAM,KAAK,wBAAwBA,CAAC,CAAC,EAChF,KAAK,OAAO,iBAAiB,WAAY,IAAM,KAAK,uBAAuB,EAC3E,KAAK,OAAO,iBAAiB,QAAS,KAAK,iBAAkB,CAAE,QAAS,GAAO,EAG/E,KAAK,OAAO,iBAAiB,sBAAsB,EAAE,QAAQuC,GAAO,CAClEA,EAAI,iBAAiB,QAAS,IAAM,CAClC,MAAMD,EAAOC,EAAI,aAAa,WAAW,EACzC,KAAK,QAAQD,CAAI,CACnB,CAAC,CACH,CAAC,EAGD,MAAMkE,EAAU,KAAK,OAAO,cAAc,WAAW,EACjDA,GACFA,EAAQ,iBAAiB,QAAS,IAAM,KAAK,MAAM,EAIrD,MAAME,EAAc,KAAK,OAAO,cAAc,eAAe,EACzDA,GACFA,EAAY,iBAAiB,QAAU1G,GAAM,CAC3C,KAAK,MAASA,EAAE,OAA4B,KAC9C,CAAC,EAIH,MAAM2G,EAAa,KAAK,OAAO,cAAc,cAAc,EACvDA,GACFA,EAAW,iBAAiB,SAAW3G,GAAM,KAAK,kBAAkBA,CAAC,CAAC,EAIxE,MAAM4G,EAAY,KAAK,OAAO,cAAc,cAAc,EACpDC,EAAa,KAAK,OAAO,cAAc,eAAe,EACtDxE,EAAW,KAAK,OAAO,cAAc,YAAY,EACnDuE,GAAWA,EAAU,iBAAiB,QAAS,IAAM,KAAK,QAAQ,EAClEC,GAAYA,EAAW,iBAAiB,QAAS,IAAM,KAAK,SAAS,EACrExE,GAAUA,EAAS,iBAAiB,QAAS,IAAM,KAAK,WAAW,EAGvE,MAAMyE,EAAc,KAAK,OAAO,cAAc,gBAAgB,EACxDC,EAAgB,KAAK,OAAO,cAAc,kBAAkB,EAC5DC,EAAe,KAAK,OAAO,cAAc,iBAAiB,EAC5DF,GAAaA,EAAY,iBAAiB,QAAS,IAAM,KAAK,UAAU,EACxEC,KAA6B,iBAAiB,SAAW/G,GAAM,KAAK,SAASA,CAAC,CAAC,EAC/EgH,GAAcA,EAAa,iBAAiB,QAAS,IAAM,KAAK,WAAW,EAG3E,KAAK,eACP,KAAK,cAAc,iBAAiB,QAAUhH,GAAM,KAAK,mBAAmBA,CAAC,CAAC,EAI5E,KAAK,YACP,KAAK,UAAU,iBAAiB,UAAYA,GAAM,CAC5CA,EAAE,MAAQ,SACZA,EAAE,eAAA,EACF,KAAK,WAAA,GACIA,EAAE,MAAQ,UACnB,KAAK,cAAA,CAET,CAAC,EACD,KAAK,UAAU,iBAAiB,OAAQ,IAAM,CACxC,KAAK,oBACP,KAAK,WAAA,CAET,CAAC,EAEL,CAGQ,iBAAiBsC,EAAgB2E,EAAmBC,EAAuB,CACjF,MAAMC,EAAgC,CACpC,cAAe,6EACf,cAAe,kEACf,YAAa,oDACb,cAAe,mCACf,YAAa,wCAAA,EAGf,MAAO;AAAA,gCADU,KAAK,OAAS7E,EAEQ,SAAW,EAAE,gBAAgBA,CAAI,YAAY4E,CAAK;AAAA;AAAA,YAEjFC,EAAMF,CAAS,CAAC;AAAA;AAAA;AAAA,KAI1B,CAGQ,WAAoB,CAC1B,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAiUT,CACF,CAGI,OAAO,OAAW,KAAe,CAAC,eAAe,IAAI,uBAAuB,GAC9E,eAAe,OAAO,wBAAyBrH,CAAmB"}
|
|
1
|
+
{"version":3,"file":"canvas-drawing-editor.umd.js","sources":["../src/core/CanvasDrawingEditor.ts"],"sourcesContent":["/**\n * Canvas Drawing Editor - 纯 JavaScript Web Component\n * 无任何框架依赖\n */\n\n// 类型定义\nexport type ToolType = 'SELECT' | 'PENCIL' | 'RECTANGLE' | 'CIRCLE' | 'TEXT' | 'IMAGE';\n\nexport interface Point {\n x: number;\n y: number;\n}\n\nexport interface BaseObject {\n id: string;\n type: string;\n x: number;\n y: number;\n color: string;\n lineWidth: number;\n}\n\nexport interface RectObject extends BaseObject {\n type: 'RECTANGLE';\n width: number;\n height: number;\n}\n\nexport interface CircleObject extends BaseObject {\n type: 'CIRCLE';\n radius: number;\n}\n\nexport interface PathObject extends BaseObject {\n type: 'PATH';\n points: Point[];\n}\n\nexport interface TextObject extends BaseObject {\n type: 'TEXT';\n text: string;\n fontSize: number;\n}\n\nexport interface ImageObject extends BaseObject {\n type: 'IMAGE';\n width: number;\n height: number;\n dataUrl: string;\n imageElement?: HTMLImageElement;\n}\n\nexport type CanvasObject = RectObject | CircleObject | PathObject | TextObject | ImageObject;\n\nexport interface EditorConfig {\n title?: string;\n showPencil?: boolean;\n showRectangle?: boolean;\n showCircle?: boolean;\n showText?: boolean;\n showImage?: boolean;\n showZoom?: boolean;\n showDownload?: boolean;\n showExport?: boolean;\n showImport?: boolean;\n showColor?: boolean;\n showMinimap?: boolean;\n}\n\n// 默认配置\nconst defaultConfig: EditorConfig = {\n title: 'Canvas Editor',\n showPencil: true,\n showRectangle: true,\n showCircle: true,\n showText: true,\n showImage: true,\n showZoom: true,\n showDownload: true,\n showExport: true,\n showImport: true,\n showColor: true,\n showMinimap: true,\n};\n\n/**\n * Canvas Drawing Editor Web Component\n */\nexport class CanvasDrawingEditor extends HTMLElement {\n // Shadow DOM\n private shadow: ShadowRoot;\n\n // DOM 元素\n private container!: HTMLDivElement;\n private toolbar!: HTMLDivElement;\n private topBar!: HTMLDivElement;\n private canvasContainer!: HTMLDivElement;\n private canvas!: HTMLCanvasElement;\n private ctx!: CanvasRenderingContext2D;\n private minimapCanvas!: HTMLCanvasElement;\n private minimapCtx!: CanvasRenderingContext2D;\n private textInput!: HTMLInputElement;\n private textInputContainer!: HTMLDivElement;\n\n // 配置\n private config: EditorConfig = { ...defaultConfig };\n\n // 状态\n private objects: CanvasObject[] = [];\n private selectedId: string | null = null;\n private tool: ToolType = 'SELECT';\n private color: string = '#000000';\n private lineWidth: number = 3;\n\n // 交互状态\n private isDragging: boolean = false;\n private dragStart: Point | null = null;\n private currentObject: CanvasObject | null = null;\n private dragOffset: Point = { x: 0, y: 0 };\n\n // 文本输入状态\n private isTextInputVisible: boolean = false;\n private textInputPos: Point = { x: 0, y: 0 };\n private textInputScreenPos: Point = { x: 0, y: 0 };\n private editingTextId: string | null = null;\n\n // 调整大小状态\n private isResizing: boolean = false;\n private resizeHandle: string | null = null;\n private resizeStartBounds: { x: number; y: number; width: number; height: number } | null = null;\n private resizeOriginalObject: CanvasObject | null = null;\n\n // 历史记录\n private history: CanvasObject[][] = [];\n private clipboard: CanvasObject | null = null;\n\n // 缩放状态\n private scale: number = 1;\n private panOffset: Point = { x: 0, y: 0 };\n\n // 平移状态\n private isPanning: boolean = false;\n private panStart: Point = { x: 0, y: 0 };\n\n // 绑定的事件处理器(用于移除监听)\n private boundHandleResize: () => void;\n private boundHandleKeyDown: (e: KeyboardEvent) => void;\n private boundHandleWheel: (e: WheelEvent) => void;\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n \n // 绑定事件处理器\n this.boundHandleResize = this.handleResize.bind(this);\n this.boundHandleKeyDown = this.handleKeyDown.bind(this);\n this.boundHandleWheel = this.handleWheel.bind(this);\n }\n\n // 观察的属性\n static get observedAttributes(): string[] {\n return [\n 'title', 'show-pencil', 'show-rectangle', 'show-circle', 'show-text',\n 'show-image', 'show-zoom', 'show-download', 'show-export', 'show-import',\n 'show-color', 'show-minimap', 'initial-data'\n ];\n }\n\n // 生命周期:连接到 DOM\n connectedCallback(): void {\n this.parseAttributes();\n this.render();\n this.setupEventListeners();\n this.initCanvas();\n this.loadInitialData();\n }\n\n // 生命周期:从 DOM 断开\n disconnectedCallback(): void {\n this.removeEventListeners();\n }\n\n // 生命周期:属性变化\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n // 处理 initial-data 属性变化\n if (name === 'initial-data' && newValue && this.canvas) {\n this.loadInitialData();\n return;\n }\n\n this.parseAttributes();\n if (this.container) {\n this.updateUI();\n }\n }\n\n // 解析 HTML 属性\n private parseAttributes(): void {\n this.config = {\n title: this.getAttribute('title') || defaultConfig.title,\n showPencil: this.getAttribute('show-pencil') !== 'false',\n showRectangle: this.getAttribute('show-rectangle') !== 'false',\n showCircle: this.getAttribute('show-circle') !== 'false',\n showText: this.getAttribute('show-text') !== 'false',\n showImage: this.getAttribute('show-image') !== 'false',\n showZoom: this.getAttribute('show-zoom') !== 'false',\n showDownload: this.getAttribute('show-download') !== 'false',\n showExport: this.getAttribute('show-export') !== 'false',\n showImport: this.getAttribute('show-import') !== 'false',\n showColor: this.getAttribute('show-color') !== 'false',\n showMinimap: this.getAttribute('show-minimap') !== 'false',\n };\n }\n\n // 生成唯一 ID\n private generateId(): string {\n return Math.random().toString(36).substr(2, 9);\n }\n\n // 加载初始数据\n private loadInitialData(): void {\n const initialData = this.getAttribute('initial-data');\n if (!initialData) return;\n\n try {\n const data = JSON.parse(initialData);\n if (data.objects && Array.isArray(data.objects)) {\n this.objects = data.objects;\n this.selectedId = null;\n\n // 重新加载图片\n this.objects.forEach(obj => {\n if (obj.type === 'IMAGE' && (obj as ImageObject).dataUrl) {\n const img = new Image();\n img.onload = () => {\n (obj as ImageObject).imageElement = img;\n this.renderCanvas();\n this.renderMinimap();\n };\n img.src = (obj as ImageObject).dataUrl;\n }\n });\n\n this.renderCanvas();\n this.renderMinimap();\n this.updateUI();\n }\n } catch (err) {\n console.error('Failed to parse initial-data:', err);\n }\n }\n\n // 设置事件监听\n private setupEventListeners(): void {\n window.addEventListener('resize', this.boundHandleResize);\n window.addEventListener('keydown', this.boundHandleKeyDown);\n }\n\n // 移除事件监听\n private removeEventListeners(): void {\n window.removeEventListener('resize', this.boundHandleResize);\n window.removeEventListener('keydown', this.boundHandleKeyDown);\n if (this.canvas) {\n this.canvas.removeEventListener('wheel', this.boundHandleWheel);\n }\n }\n\n // 窗口大小变化处理\n private handleResize(): void {\n this.initCanvas();\n }\n\n // 初始化画布\n private initCanvas(): void {\n if (!this.canvasContainer || !this.canvas) return;\n\n // 使用 requestAnimationFrame 确保 DOM 已经渲染\n requestAnimationFrame(() => {\n this.canvas.width = this.canvasContainer.clientWidth;\n this.canvas.height = this.canvasContainer.clientHeight;\n this.renderCanvas();\n this.renderMinimap();\n });\n }\n\n // 获取鼠标在画布上的位置(考虑缩放和平移)\n private getMousePos(e: MouseEvent | TouchEvent): Point {\n const rect = this.canvas.getBoundingClientRect();\n let clientX: number, clientY: number;\n\n if ('touches' in e && e.touches.length > 0) {\n clientX = e.touches[0].clientX;\n clientY = e.touches[0].clientY;\n } else if ('clientX' in e) {\n clientX = e.clientX;\n clientY = e.clientY;\n } else {\n return { x: 0, y: 0 };\n }\n\n const x = (clientX - rect.left - this.panOffset.x) / this.scale;\n const y = (clientY - rect.top - this.panOffset.y) / this.scale;\n return { x, y };\n }\n\n // 获取屏幕坐标(不考虑缩放和平移)\n private getScreenPos(e: MouseEvent | TouchEvent): Point {\n const rect = this.canvas.getBoundingClientRect();\n let clientX: number, clientY: number;\n\n if ('touches' in e && e.touches.length > 0) {\n clientX = e.touches[0].clientX;\n clientY = e.touches[0].clientY;\n } else if ('clientX' in e) {\n clientX = e.clientX;\n clientY = e.clientY;\n } else {\n return { x: 0, y: 0 };\n }\n\n return { x: clientX - rect.left, y: clientY - rect.top };\n }\n\n // 获取对象边界\n private getObjectBounds(obj: CanvasObject): { x: number; y: number; width: number; height: number } {\n switch (obj.type) {\n case 'RECTANGLE':\n case 'IMAGE': {\n const r = obj as RectObject | ImageObject;\n return { x: r.x, y: r.y, width: r.width, height: r.height };\n }\n case 'CIRCLE': {\n const c = obj as CircleObject;\n return { x: c.x - c.radius, y: c.y - c.radius, width: c.radius * 2, height: c.radius * 2 };\n }\n case 'TEXT': {\n const t = obj as TextObject;\n const width = t.text.length * t.fontSize * 0.6;\n return { x: t.x, y: t.y - t.fontSize, width, height: t.fontSize };\n }\n case 'PATH': {\n const p = obj as PathObject;\n if (p.points.length === 0) return { x: 0, y: 0, width: 0, height: 0 };\n const minX = Math.min(...p.points.map(pt => pt.x));\n const maxX = Math.max(...p.points.map(pt => pt.x));\n const minY = Math.min(...p.points.map(pt => pt.y));\n const maxY = Math.max(...p.points.map(pt => pt.y));\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n }\n }\n return { x: 0, y: 0, width: 0, height: 0 };\n }\n\n // 检查调整大小手柄\n private getResizeHandleAtPoint(obj: CanvasObject, x: number, y: number): string | null {\n const bounds = this.getObjectBounds(obj);\n const handleSize = 8;\n\n const handles = [\n { name: 'nw', x: bounds.x, y: bounds.y },\n { name: 'ne', x: bounds.x + bounds.width, y: bounds.y },\n { name: 'sw', x: bounds.x, y: bounds.y + bounds.height },\n { name: 'se', x: bounds.x + bounds.width, y: bounds.y + bounds.height },\n ];\n\n for (const handle of handles) {\n if (Math.abs(x - handle.x) <= handleSize && Math.abs(y - handle.y) <= handleSize) {\n return handle.name;\n }\n }\n return null;\n }\n\n // 碰撞检测\n private isHit(obj: CanvasObject, x: number, y: number): boolean {\n switch (obj.type) {\n case 'RECTANGLE': {\n const r = obj as RectObject;\n return x >= r.x && x <= r.x + r.width && y >= r.y && y <= r.y + r.height;\n }\n case 'CIRCLE': {\n const c = obj as CircleObject;\n const dist = Math.sqrt(Math.pow(x - c.x, 2) + Math.pow(y - c.y, 2));\n return dist <= c.radius;\n }\n case 'IMAGE': {\n const img = obj as ImageObject;\n return x >= img.x && x <= img.x + img.width && y >= img.y && y <= img.y + img.height;\n }\n case 'TEXT': {\n const t = obj as TextObject;\n return x >= t.x && x <= t.x + (t.text.length * t.fontSize * 0.6) && y >= t.y - t.fontSize && y <= t.y;\n }\n case 'PATH': {\n const p = obj as PathObject;\n if (p.points.length === 0) return false;\n const minX = Math.min(...p.points.map(pt => pt.x));\n const maxX = Math.max(...p.points.map(pt => pt.x));\n const minY = Math.min(...p.points.map(pt => pt.y));\n const maxY = Math.max(...p.points.map(pt => pt.y));\n return x >= minX && x <= maxX && y >= minY && y <= maxY;\n }\n }\n return false;\n }\n\n // 保存历史\n private saveHistory(): void {\n this.history.push(JSON.parse(JSON.stringify(this.objects)));\n }\n\n // 撤销\n private undo(): void {\n if (this.history.length === 0) return;\n const previousState = this.history.pop();\n if (previousState) {\n this.objects = previousState;\n this.selectedId = null;\n this.renderCanvas();\n this.renderMinimap();\n this.dispatchChangeEvent();\n }\n }\n\n // 删除选中对象\n private deleteSelected(): void {\n if (this.selectedId) {\n this.saveHistory();\n this.objects = this.objects.filter(o => o.id !== this.selectedId);\n this.selectedId = null;\n this.renderCanvas();\n this.renderMinimap();\n this.updateUI();\n this.dispatchChangeEvent();\n }\n }\n\n // 复制选中对象\n private copySelected(): void {\n if (this.selectedId) {\n const selectedObj = this.objects.find(o => o.id === this.selectedId);\n if (selectedObj) {\n this.clipboard = JSON.parse(JSON.stringify(selectedObj));\n }\n }\n }\n\n // 粘贴对象\n private pasteObject(): void {\n if (this.clipboard) {\n this.saveHistory();\n const newObj = {\n ...JSON.parse(JSON.stringify(this.clipboard)),\n id: this.generateId(),\n x: this.clipboard.x + 20,\n y: this.clipboard.y + 20\n };\n if (newObj.type === 'PATH' && newObj.points) {\n newObj.points = newObj.points.map((pt: Point) => ({\n x: pt.x + 20,\n y: pt.y + 20\n }));\n }\n this.objects.push(newObj);\n this.selectedId = newObj.id;\n this.clipboard = newObj;\n this.renderCanvas();\n this.renderMinimap();\n this.updateUI();\n this.dispatchChangeEvent();\n }\n }\n\n // 派发变化事件\n private dispatchChangeEvent(): void {\n this.dispatchEvent(new CustomEvent('editor-change', {\n bubbles: true,\n composed: true,\n detail: { objects: this.objects }\n }));\n }\n\n // 键盘事件处理\n private handleKeyDown(e: KeyboardEvent): void {\n if (this.isTextInputVisible) return;\n\n // Ctrl+Z: 撤销\n if ((e.ctrlKey || e.metaKey) && e.key === 'z') {\n e.preventDefault();\n this.undo();\n return;\n }\n\n // Ctrl+C: 复制\n if ((e.ctrlKey || e.metaKey) && e.key === 'c') {\n if (this.selectedId) {\n e.preventDefault();\n this.copySelected();\n }\n return;\n }\n\n // Ctrl+V: 粘贴\n if ((e.ctrlKey || e.metaKey) && e.key === 'v') {\n if (this.clipboard) {\n e.preventDefault();\n this.pasteObject();\n }\n return;\n }\n\n // Delete/Backspace: 删除\n if ((e.key === 'Delete' || e.key === 'Backspace') && this.selectedId) {\n e.preventDefault();\n this.deleteSelected();\n return;\n }\n\n // 快捷键切换工具\n if (!e.ctrlKey && !e.metaKey) {\n switch (e.key.toLowerCase()) {\n case 'v':\n this.setTool('SELECT');\n break;\n case 'p':\n case 'b':\n this.setTool('PENCIL');\n break;\n case 'r':\n this.setTool('RECTANGLE');\n break;\n case 'o':\n this.setTool('CIRCLE');\n break;\n case 't':\n this.setTool('TEXT');\n break;\n case 'escape':\n this.selectedId = null;\n this.hideTextInput();\n this.renderCanvas();\n this.updateUI();\n break;\n }\n }\n }\n\n // 滚轮缩放\n private handleWheel(e: WheelEvent): void {\n e.preventDefault();\n const rect = this.canvas.getBoundingClientRect();\n const mouseX = e.clientX - rect.left;\n const mouseY = e.clientY - rect.top;\n\n const delta = e.deltaY > 0 ? 0.9 : 1.1;\n const newScale = this.scale * delta;\n\n this.zoomAtPoint(newScale, mouseX, mouseY);\n }\n\n // 以指定点为中心缩放\n private zoomAtPoint(newScale: number, centerX: number, centerY: number): void {\n const clampedScale = Math.min(Math.max(newScale, 0.2), 5);\n\n const mouseXBeforeZoom = (centerX - this.panOffset.x) / this.scale;\n const mouseYBeforeZoom = (centerY - this.panOffset.y) / this.scale;\n\n const newPanOffsetX = centerX - mouseXBeforeZoom * clampedScale;\n const newPanOffsetY = centerY - mouseYBeforeZoom * clampedScale;\n\n this.scale = clampedScale;\n this.panOffset = { x: newPanOffsetX, y: newPanOffsetY };\n\n this.renderCanvas();\n this.renderMinimap();\n this.updateZoomDisplay();\n }\n\n // 放大\n private zoomIn(): void {\n const centerX = this.canvas.width / 2;\n const centerY = this.canvas.height / 2;\n this.zoomAtPoint(this.scale * 1.2, centerX, centerY);\n }\n\n // 缩小\n private zoomOut(): void {\n const centerX = this.canvas.width / 2;\n const centerY = this.canvas.height / 2;\n this.zoomAtPoint(this.scale / 1.2, centerX, centerY);\n }\n\n // 重置缩放\n private resetZoom(): void {\n this.scale = 1;\n this.panOffset = { x: 0, y: 0 };\n this.renderCanvas();\n this.renderMinimap();\n this.updateZoomDisplay();\n }\n\n // 更新缩放显示\n private updateZoomDisplay(): void {\n const zoomText = this.shadow.querySelector('.zoom-text');\n if (zoomText) {\n zoomText.textContent = `${Math.round(this.scale * 100)}%`;\n }\n }\n\n // 设置工具\n private setTool(tool: ToolType): void {\n this.tool = tool;\n this.updateToolButtons();\n }\n\n // 更新工具按钮状态\n private updateToolButtons(): void {\n const buttons = this.shadow.querySelectorAll('.tool-btn');\n buttons.forEach(btn => {\n const btnTool = btn.getAttribute('data-tool');\n if (btnTool === this.tool) {\n btn.classList.add('active');\n } else {\n btn.classList.remove('active');\n }\n });\n }\n\n // 隐藏文本输入\n private hideTextInput(): void {\n this.isTextInputVisible = false;\n if (this.textInputContainer) {\n this.textInputContainer.style.display = 'none';\n }\n this.editingTextId = null;\n }\n\n // 显示文本输入\n private showTextInput(screenX: number, screenY: number, text: string = ''): void {\n this.isTextInputVisible = true;\n this.textInputScreenPos = { x: screenX, y: screenY };\n\n if (this.textInputContainer && this.textInput) {\n this.textInputContainer.style.display = 'block';\n this.textInputContainer.style.left = `${screenX}px`;\n this.textInputContainer.style.top = `${screenY - 30}px`;\n this.textInput.value = text;\n this.textInput.style.color = this.color;\n setTimeout(() => {\n this.textInput.focus();\n if (text) this.textInput.select();\n }, 0);\n }\n }\n\n // 提交文本\n private submitText(): void {\n const value = this.textInput?.value?.trim();\n if (value) {\n if (this.editingTextId) {\n const existingObj = this.objects.find(o => o.id === this.editingTextId) as TextObject | undefined;\n if (existingObj && existingObj.text !== value) {\n this.saveHistory();\n existingObj.text = value;\n }\n this.selectedId = this.editingTextId;\n } else {\n this.saveHistory();\n const newObj: TextObject = {\n id: this.generateId(),\n type: 'TEXT',\n x: this.textInputPos.x,\n y: this.textInputPos.y,\n text: value,\n fontSize: 24,\n color: this.color,\n lineWidth: this.lineWidth\n };\n this.objects.push(newObj);\n this.selectedId = newObj.id;\n }\n this.dispatchChangeEvent();\n }\n this.hideTextInput();\n this.setTool('SELECT');\n this.renderCanvas();\n this.renderMinimap();\n this.updateUI();\n }\n\n // 画布鼠标按下\n private handleCanvasPointerDown(e: MouseEvent | TouchEvent): void {\n const { x, y } = this.getMousePos(e);\n const screenPos = this.getScreenPos(e);\n this.dragStart = { x, y };\n this.isDragging = true;\n\n // 如果文本输入可见且不是文本工具,先保存文本\n if (this.isTextInputVisible && this.tool !== 'TEXT') {\n this.submitText();\n }\n\n if (this.tool === 'SELECT') {\n // 检查是否点击调整大小手柄\n if (this.selectedId) {\n const selectedObj = this.objects.find(o => o.id === this.selectedId);\n if (selectedObj) {\n const handle = this.getResizeHandleAtPoint(selectedObj, x, y);\n if (handle) {\n this.saveHistory();\n this.isResizing = true;\n this.resizeHandle = handle;\n this.resizeStartBounds = this.getObjectBounds(selectedObj);\n this.resizeOriginalObject = JSON.parse(JSON.stringify(selectedObj));\n return;\n }\n }\n }\n\n // 查找点击的对象\n const clickedObject = [...this.objects].reverse().find(obj => this.isHit(obj, x, y));\n\n if (clickedObject) {\n this.selectedId = clickedObject.id;\n this.dragOffset = { x: x - clickedObject.x, y: y - clickedObject.y };\n this.saveHistory();\n this.updateUI();\n } else {\n // 开始拖拽画布\n this.selectedId = null;\n this.isPanning = true;\n this.panStart = screenPos;\n this.updateUI();\n }\n } else if (this.tool === 'TEXT') {\n // 显示文本输入\n this.textInputPos = { x, y };\n this.showTextInput(screenPos.x, screenPos.y);\n this.isDragging = false;\n } else {\n // 开始绘制图形\n this.saveHistory();\n const id = this.generateId();\n if (this.tool === 'RECTANGLE') {\n this.currentObject = { id, type: 'RECTANGLE', x, y, width: 0, height: 0, color: this.color, lineWidth: this.lineWidth };\n } else if (this.tool === 'CIRCLE') {\n this.currentObject = { id, type: 'CIRCLE', x, y, radius: 0, color: this.color, lineWidth: this.lineWidth };\n } else if (this.tool === 'PENCIL') {\n this.currentObject = { id, type: 'PATH', x, y, points: [{ x, y }], color: this.color, lineWidth: this.lineWidth };\n }\n }\n\n this.renderCanvas();\n }\n\n // 画布鼠标移动\n private handleCanvasPointerMove(e: MouseEvent | TouchEvent): void {\n // 处理画布拖拽\n if (this.isPanning) {\n const screenPos = this.getScreenPos(e);\n const dx = screenPos.x - this.panStart.x;\n const dy = screenPos.y - this.panStart.y;\n this.panOffset = { x: this.panOffset.x + dx, y: this.panOffset.y + dy };\n this.panStart = screenPos;\n this.renderCanvas();\n this.renderMinimap();\n return;\n }\n\n if (!this.isDragging || !this.dragStart) return;\n const { x, y } = this.getMousePos(e);\n\n // 处理调整大小\n if (this.isResizing && this.selectedId && this.resizeHandle && this.resizeStartBounds && this.resizeOriginalObject) {\n const obj = this.objects.find(o => o.id === this.selectedId);\n if (!obj) return;\n\n const dx = x - this.dragStart.x;\n const dy = y - this.dragStart.y;\n let newX = this.resizeStartBounds.x;\n let newY = this.resizeStartBounds.y;\n let newWidth = this.resizeStartBounds.width;\n let newHeight = this.resizeStartBounds.height;\n\n if (this.resizeHandle.includes('e')) newWidth = this.resizeStartBounds.width + dx;\n if (this.resizeHandle.includes('w')) {\n newX = this.resizeStartBounds.x + dx;\n newWidth = this.resizeStartBounds.width - dx;\n }\n if (this.resizeHandle.includes('s')) newHeight = this.resizeStartBounds.height + dy;\n if (this.resizeHandle.includes('n')) {\n newY = this.resizeStartBounds.y + dy;\n newHeight = this.resizeStartBounds.height - dy;\n }\n\n newWidth = Math.max(10, newWidth);\n newHeight = Math.max(10, newHeight);\n\n // 根据对象类型应用变化\n switch (obj.type) {\n case 'RECTANGLE':\n case 'IMAGE':\n (obj as RectObject | ImageObject).x = newX;\n (obj as RectObject | ImageObject).y = newY;\n (obj as RectObject | ImageObject).width = newWidth;\n (obj as RectObject | ImageObject).height = newHeight;\n break;\n case 'CIRCLE': {\n const radius = Math.max(newWidth, newHeight) / 2;\n (obj as CircleObject).x = newX + radius;\n (obj as CircleObject).y = newY + radius;\n (obj as CircleObject).radius = radius;\n break;\n }\n case 'TEXT': {\n const origT = this.resizeOriginalObject as TextObject;\n const scaleFactor = newWidth / this.resizeStartBounds.width;\n (obj as TextObject).x = newX;\n (obj as TextObject).y = newY + newHeight;\n (obj as TextObject).fontSize = Math.max(8, Math.round(origT.fontSize * scaleFactor));\n break;\n }\n case 'PATH': {\n const origP = this.resizeOriginalObject as PathObject;\n const scaleX = newWidth / this.resizeStartBounds.width;\n const scaleY = newHeight / this.resizeStartBounds.height;\n (obj as PathObject).points = origP.points.map(pt => ({\n x: newX + (pt.x - this.resizeStartBounds!.x) * scaleX,\n y: newY + (pt.y - this.resizeStartBounds!.y) * scaleY\n }));\n break;\n }\n }\n\n this.renderCanvas();\n this.renderMinimap();\n return;\n }\n\n // 移动选中对象\n if (this.tool === 'SELECT' && this.selectedId) {\n const obj = this.objects.find(o => o.id === this.selectedId);\n if (obj) {\n if (obj.type === 'PATH') {\n const p = obj as PathObject;\n const dx = x - this.dragStart.x;\n const dy = y - this.dragStart.y;\n p.points = p.points.map(pt => ({ x: pt.x + dx, y: pt.y + dy }));\n this.dragStart = { x, y };\n } else {\n obj.x = x - this.dragOffset.x;\n obj.y = y - this.dragOffset.y;\n }\n this.renderCanvas();\n this.renderMinimap();\n }\n } else if (this.currentObject) {\n // 更新正在绘制的图形\n if (this.currentObject.type === 'RECTANGLE') {\n (this.currentObject as RectObject).width = x - this.currentObject.x;\n (this.currentObject as RectObject).height = y - this.currentObject.y;\n } else if (this.currentObject.type === 'CIRCLE') {\n const radius = Math.sqrt(Math.pow(x - this.currentObject.x, 2) + Math.pow(y - this.currentObject.y, 2));\n (this.currentObject as CircleObject).radius = radius;\n } else if (this.currentObject.type === 'PATH') {\n (this.currentObject as PathObject).points.push({ x, y });\n }\n this.renderCanvas();\n }\n }\n\n // 画布鼠标抬起\n private handleCanvasPointerUp(): void {\n this.isDragging = false;\n this.dragStart = null;\n this.isResizing = false;\n this.resizeHandle = null;\n this.resizeStartBounds = null;\n this.resizeOriginalObject = null;\n this.isPanning = false;\n\n if (this.currentObject) {\n this.objects.push(this.currentObject);\n this.currentObject = null;\n this.dispatchChangeEvent();\n }\n\n this.renderCanvas();\n this.renderMinimap();\n this.updateUI();\n }\n\n // 双击编辑文本\n private handleCanvasDoubleClick(e: MouseEvent): void {\n e.preventDefault();\n const { x, y } = this.getMousePos(e);\n\n const clickedObject = [...this.objects].reverse().find(obj => this.isHit(obj, x, y));\n\n if (clickedObject && clickedObject.type === 'TEXT') {\n const textObj = clickedObject as TextObject;\n this.editingTextId = textObj.id;\n this.textInputPos = { x: textObj.x, y: textObj.y };\n const screenX = textObj.x * this.scale + this.panOffset.x;\n const screenY = textObj.y * this.scale + this.panOffset.y;\n this.showTextInput(screenX, screenY, textObj.text);\n this.setTool('SELECT');\n }\n }\n\n // 渲染画布\n private renderCanvas(): void {\n if (!this.ctx) return;\n\n // 清空画布\n this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n\n // 绘制背景\n this.ctx.fillStyle = '#ffffff';\n this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);\n\n // 应用缩放和平移\n this.ctx.save();\n this.ctx.translate(this.panOffset.x, this.panOffset.y);\n this.ctx.scale(this.scale, this.scale);\n\n // 绘制所有对象\n this.objects.forEach(obj => this.drawObject(this.ctx, obj, false));\n\n // 绘制正在创建的对象\n if (this.currentObject) {\n this.drawObject(this.ctx, this.currentObject, false);\n }\n\n // 绘制选中对象的调整手柄\n if (this.selectedId && this.tool === 'SELECT') {\n const selectedObj = this.objects.find(o => o.id === this.selectedId);\n if (selectedObj) {\n this.drawSelectionHandles(this.ctx, selectedObj);\n }\n }\n\n this.ctx.restore();\n }\n\n // 绘制单个对象\n private drawObject(ctx: CanvasRenderingContext2D, obj: CanvasObject, isMinimap: boolean): void {\n ctx.beginPath();\n ctx.strokeStyle = obj.color;\n ctx.lineWidth = obj.lineWidth;\n ctx.fillStyle = obj.color;\n\n // 选中高亮(仅主画布)\n if (!isMinimap && obj.id === this.selectedId) {\n ctx.shadowColor = 'rgba(0, 100, 255, 0.5)';\n ctx.shadowBlur = 10;\n } else {\n ctx.shadowBlur = 0;\n }\n\n switch (obj.type) {\n case 'RECTANGLE': {\n const r = obj as RectObject;\n ctx.strokeRect(r.x, r.y, r.width, r.height);\n break;\n }\n case 'CIRCLE': {\n const c = obj as CircleObject;\n ctx.beginPath();\n ctx.arc(c.x, c.y, c.radius, 0, 2 * Math.PI);\n ctx.stroke();\n break;\n }\n case 'PATH': {\n const p = obj as PathObject;\n if (p.points.length < 2) break;\n ctx.beginPath();\n ctx.lineCap = 'round';\n ctx.lineJoin = 'round';\n ctx.moveTo(p.points[0].x, p.points[0].y);\n for (let i = 1; i < p.points.length; i++) {\n ctx.lineTo(p.points[i].x, p.points[i].y);\n }\n ctx.stroke();\n break;\n }\n case 'TEXT': {\n const t = obj as TextObject;\n ctx.font = `${t.fontSize}px sans-serif`;\n ctx.fillText(t.text, t.x, t.y);\n break;\n }\n case 'IMAGE': {\n const imgObj = obj as ImageObject;\n if (imgObj.imageElement && imgObj.imageElement.complete) {\n ctx.drawImage(imgObj.imageElement, imgObj.x, imgObj.y, imgObj.width, imgObj.height);\n } else if (imgObj.dataUrl) {\n // 加载图片\n const img = new Image();\n img.onload = () => {\n imgObj.imageElement = img;\n this.renderCanvas();\n };\n img.src = imgObj.dataUrl;\n }\n break;\n }\n }\n }\n\n // 绘制选中手柄\n private drawSelectionHandles(ctx: CanvasRenderingContext2D, obj: CanvasObject): void {\n const bounds = this.getObjectBounds(obj);\n const handleSize = 8;\n\n ctx.shadowBlur = 0;\n ctx.fillStyle = '#3b82f6';\n ctx.strokeStyle = '#ffffff';\n ctx.lineWidth = 2;\n\n // 绘制角落手柄\n const corners = [\n { x: bounds.x, y: bounds.y },\n { x: bounds.x + bounds.width, y: bounds.y },\n { x: bounds.x, y: bounds.y + bounds.height },\n { x: bounds.x + bounds.width, y: bounds.y + bounds.height },\n ];\n\n corners.forEach(corner => {\n ctx.beginPath();\n ctx.rect(corner.x - handleSize / 2, corner.y - handleSize / 2, handleSize, handleSize);\n ctx.fill();\n ctx.stroke();\n });\n\n // 绘制选择边框\n ctx.strokeStyle = '#3b82f6';\n ctx.lineWidth = 1;\n ctx.setLineDash([5, 5]);\n ctx.strokeRect(bounds.x, bounds.y, bounds.width, bounds.height);\n ctx.setLineDash([]);\n }\n\n // 渲染小地图\n private renderMinimap(): void {\n if (!this.minimapCtx || !this.config.showMinimap) return;\n\n const minimap = this.minimapCanvas;\n const mainCanvas = this.canvas;\n\n this.minimapCtx.clearRect(0, 0, minimap.width, minimap.height);\n\n // 计算缩放比例\n const scaleX = minimap.width / mainCanvas.width;\n const scaleY = minimap.height / mainCanvas.height;\n const minimapScale = Math.min(scaleX, scaleY) * 0.92;\n\n const canvasW = mainCanvas.width * minimapScale;\n const canvasH = mainCanvas.height * minimapScale;\n const offsetX = (minimap.width - canvasW) / 2;\n const offsetY = (minimap.height - canvasH) / 2;\n\n // 绘制画布区域背景\n this.minimapCtx.fillStyle = '#ffffff';\n this.minimapCtx.fillRect(offsetX, offsetY, canvasW, canvasH);\n\n // 应用主画布的缩放和平移变换\n this.minimapCtx.save();\n this.minimapCtx.translate(offsetX, offsetY);\n this.minimapCtx.scale(minimapScale, minimapScale);\n this.minimapCtx.translate(this.panOffset.x, this.panOffset.y);\n this.minimapCtx.scale(this.scale, this.scale);\n\n // 绘制所有对象\n const allObjects = this.currentObject ? [...this.objects, this.currentObject] : this.objects;\n allObjects.forEach(obj => {\n this.minimapCtx.fillStyle = obj.color;\n this.minimapCtx.strokeStyle = obj.color;\n this.minimapCtx.lineWidth = Math.max(obj.lineWidth, 1);\n this.minimapCtx.setLineDash([]);\n\n switch (obj.type) {\n case 'RECTANGLE': {\n const r = obj as RectObject;\n this.minimapCtx.strokeRect(r.x, r.y, r.width, r.height);\n break;\n }\n case 'CIRCLE': {\n const c = obj as CircleObject;\n this.minimapCtx.beginPath();\n this.minimapCtx.arc(c.x, c.y, c.radius, 0, Math.PI * 2);\n this.minimapCtx.stroke();\n break;\n }\n case 'PATH': {\n const p = obj as PathObject;\n if (p.points.length > 0) {\n this.minimapCtx.beginPath();\n this.minimapCtx.lineCap = 'round';\n this.minimapCtx.lineJoin = 'round';\n this.minimapCtx.moveTo(p.points[0].x, p.points[0].y);\n p.points.forEach(pt => this.minimapCtx.lineTo(pt.x, pt.y));\n this.minimapCtx.stroke();\n }\n break;\n }\n case 'TEXT': {\n const t = obj as TextObject;\n this.minimapCtx.font = `${t.fontSize}px sans-serif`;\n this.minimapCtx.fillText(t.text, t.x, t.y);\n break;\n }\n case 'IMAGE': {\n const img = obj as ImageObject;\n if (img.imageElement) {\n this.minimapCtx.drawImage(img.imageElement, img.x, img.y, img.width, img.height);\n }\n break;\n }\n }\n });\n\n this.minimapCtx.restore();\n\n // 绘制画布边框\n this.minimapCtx.strokeStyle = '#94a3b8';\n this.minimapCtx.lineWidth = 1;\n this.minimapCtx.strokeRect(offsetX, offsetY, canvasW, canvasH);\n }\n\n // 小地图点击定位\n private handleMinimapClick(e: MouseEvent): void {\n const rect = this.minimapCanvas.getBoundingClientRect();\n const clickX = e.clientX - rect.left;\n const clickY = e.clientY - rect.top;\n\n const scaleX = this.minimapCanvas.width / this.canvas.width;\n const scaleY = this.minimapCanvas.height / this.canvas.height;\n const minimapScale = Math.min(scaleX, scaleY) * 0.92;\n\n const canvasW = this.canvas.width * minimapScale;\n const canvasH = this.canvas.height * minimapScale;\n const offsetX = (this.minimapCanvas.width - canvasW) / 2;\n const offsetY = (this.minimapCanvas.height - canvasH) / 2;\n\n const relX = clickX - offsetX;\n const relY = clickY - offsetY;\n\n const canvasX = (relX / minimapScale - this.panOffset.x) / this.scale;\n const canvasY = (relY / minimapScale - this.panOffset.y) / this.scale;\n\n const viewportCenterX = this.canvas.width / 2;\n const viewportCenterY = this.canvas.height / 2;\n\n this.panOffset = {\n x: viewportCenterX / this.scale - canvasX,\n y: viewportCenterY / this.scale - canvasY\n };\n\n this.renderCanvas();\n this.renderMinimap();\n }\n\n // 图片上传处理\n private handleImageUpload(e: Event): void {\n const input = e.target as HTMLInputElement;\n if (!input.files || input.files.length === 0) return;\n\n const file = input.files[0];\n const reader = new FileReader();\n\n reader.onload = (event) => {\n const dataUrl = event.target?.result as string;\n const img = new Image();\n img.onload = () => {\n this.saveHistory();\n const maxSize = 300;\n let width = img.width;\n let height = img.height;\n if (width > maxSize || height > maxSize) {\n const ratio = Math.min(maxSize / width, maxSize / height);\n width *= ratio;\n height *= ratio;\n }\n\n const newObj: ImageObject = {\n id: this.generateId(),\n type: 'IMAGE',\n x: 100,\n y: 100,\n width,\n height,\n color: '#000000',\n lineWidth: 1,\n dataUrl,\n imageElement: img\n };\n this.objects.push(newObj);\n this.selectedId = newObj.id;\n this.setTool('SELECT');\n this.renderCanvas();\n this.renderMinimap();\n this.updateUI();\n this.dispatchChangeEvent();\n };\n img.src = dataUrl;\n };\n\n reader.readAsDataURL(file);\n input.value = '';\n }\n\n // 保存 JSON\n private saveJson(): void {\n const data = {\n version: '1.0',\n objects: this.objects.map(obj => {\n const { imageElement, ...rest } = obj as ImageObject;\n return rest;\n })\n };\n const json = JSON.stringify(data, null, 2);\n const blob = new Blob([json], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = 'canvas-project.json';\n a.click();\n URL.revokeObjectURL(url);\n }\n\n // 加载 JSON\n private loadJson(e: Event): void {\n const input = e.target as HTMLInputElement;\n if (!input.files || input.files.length === 0) return;\n\n const file = input.files[0];\n const reader = new FileReader();\n\n reader.onload = (event) => {\n try {\n const data = JSON.parse(event.target?.result as string);\n if (data.objects && Array.isArray(data.objects)) {\n this.saveHistory();\n this.objects = data.objects;\n this.selectedId = null;\n\n // 重新加载图片\n this.objects.forEach(obj => {\n if (obj.type === 'IMAGE' && (obj as ImageObject).dataUrl) {\n const img = new Image();\n img.onload = () => {\n (obj as ImageObject).imageElement = img;\n this.renderCanvas();\n this.renderMinimap();\n };\n img.src = (obj as ImageObject).dataUrl;\n }\n });\n\n this.renderCanvas();\n this.renderMinimap();\n this.updateUI();\n this.dispatchChangeEvent();\n }\n } catch (err) {\n console.error('Failed to load JSON:', err);\n }\n };\n\n reader.readAsText(file);\n input.value = '';\n }\n\n // 导出 PNG\n private exportPng(): void {\n // 创建临时画布\n const tempCanvas = document.createElement('canvas');\n tempCanvas.width = this.canvas.width;\n tempCanvas.height = this.canvas.height;\n const tempCtx = tempCanvas.getContext('2d')!;\n\n // 绘制白色背景\n tempCtx.fillStyle = '#ffffff';\n tempCtx.fillRect(0, 0, tempCanvas.width, tempCanvas.height);\n\n // 应用缩放和平移\n tempCtx.translate(this.panOffset.x, this.panOffset.y);\n tempCtx.scale(this.scale, this.scale);\n\n // 绘制所有对象\n this.objects.forEach(obj => this.drawObject(tempCtx, obj, true));\n\n // 下载\n const url = tempCanvas.toDataURL('image/png');\n const a = document.createElement('a');\n a.href = url;\n a.download = 'canvas-export.png';\n a.click();\n }\n\n // 更新 UI\n private updateUI(): void {\n // 更新选中状态显示\n const selectionInfo = this.shadow.querySelector('.selection-info');\n if (selectionInfo) {\n if (this.selectedId) {\n const selectedObj = this.objects.find(o => o.id === this.selectedId);\n if (selectedObj) {\n const typeLabels: Record<string, string> = {\n 'RECTANGLE': '矩形',\n 'CIRCLE': '圆形',\n 'PATH': '画笔',\n 'TEXT': '文本',\n 'IMAGE': '图片'\n };\n const typeLabel = typeLabels[selectedObj.type] || selectedObj.type;\n selectionInfo.innerHTML = `\n <span class=\"selection-label\">已选择: ${typeLabel}</span>\n <button class=\"delete-btn\" title=\"删除\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M3 6h18M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2\"/>\n </svg>\n </button>\n `;\n selectionInfo.classList.add('visible');\n const deleteBtn = selectionInfo.querySelector('.delete-btn');\n if (deleteBtn) {\n deleteBtn.addEventListener('click', () => this.deleteSelected());\n }\n }\n } else {\n selectionInfo.classList.remove('visible');\n selectionInfo.innerHTML = '';\n }\n }\n\n // 更新撤销按钮状态\n const undoBtn = this.shadow.querySelector('.undo-btn') as HTMLButtonElement;\n if (undoBtn) {\n undoBtn.disabled = this.history.length === 0;\n }\n\n // 更新空画布提示显示\n const emptyHint = this.shadow.querySelector('.empty-hint') as HTMLElement;\n if (emptyHint) {\n emptyHint.style.display = this.objects.length === 0 ? 'flex' : 'none';\n }\n }\n\n // 渲染 DOM 结构\n private render(): void {\n this.shadow.innerHTML = `\n <style>${this.getStyles()}</style>\n <div class=\"editor-container\">\n <!-- 左侧工具栏 -->\n <div class=\"toolbar\">\n ${this.createToolButton('SELECT', 'select-icon', '选择 (V)')}\n <div class=\"divider\"></div>\n ${this.config.showPencil ? this.createToolButton('PENCIL', 'pencil-icon', '画笔 (P)') : ''}\n ${this.config.showRectangle ? this.createToolButton('RECTANGLE', 'rect-icon', '矩形 (R)') : ''}\n ${this.config.showCircle ? this.createToolButton('CIRCLE', 'circle-icon', '圆形 (O)') : ''}\n ${this.config.showText ? this.createToolButton('TEXT', 'text-icon', '文本 (T)') : ''}\n ${this.config.showImage ? `\n <label class=\"tool-btn\" title=\"插入图片\">\n <svg class=\"icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"/>\n <circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"/>\n <path d=\"M21 15l-5-5L5 21\"/>\n </svg>\n <input type=\"file\" accept=\"image/*\" class=\"hidden image-input\" />\n </label>\n ` : ''}\n <div class=\"divider\"></div>\n <button class=\"tool-btn undo-btn\" title=\"撤销 (Ctrl+Z)\" disabled>\n <svg class=\"icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M1 4v6h6\"/>\n <path d=\"M3.51 15a9 9 0 1 0 2.13-9.36L1 10\"/>\n </svg>\n </button>\n <div class=\"spacer\"></div>\n ${this.config.showColor ? `\n <input type=\"color\" class=\"color-picker\" value=\"${this.color}\" title=\"颜色\" />\n ` : ''}\n </div>\n\n <!-- 主区域 -->\n <div class=\"main-area\">\n <!-- 顶部栏 -->\n <div class=\"top-bar\">\n <div class=\"top-bar-left\">\n <h2 class=\"title\">${this.config.title}</h2>\n <div class=\"selection-info\"></div>\n </div>\n <div class=\"top-bar-right\">\n ${this.config.showZoom ? `\n <div class=\"zoom-controls\">\n <button class=\"zoom-btn zoom-out-btn\" title=\"缩小\">\n <svg class=\"icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"M21 21l-4.35-4.35M8 11h6\"/>\n </svg>\n </button>\n <button class=\"zoom-text\" title=\"重置缩放\">100%</button>\n <button class=\"zoom-btn zoom-in-btn\" title=\"放大\">\n <svg class=\"icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"M21 21l-4.35-4.35M11 8v6M8 11h6\"/>\n </svg>\n </button>\n </div>\n ` : ''}\n ${(this.config.showExport || this.config.showImport || this.config.showDownload) ? `\n <div class=\"file-controls\">\n ${this.config.showExport ? `\n <button class=\"file-btn save-json-btn\" title=\"保存项目 (JSON)\">\n <svg class=\"icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M19 21H5a2 2 0 01-2-2V5a2 2 0 012-2h11l5 5v11a2 2 0 01-2 2z\"/>\n <polyline points=\"17 21 17 13 7 13 7 21\"/><polyline points=\"7 3 7 8 15 8\"/>\n </svg>\n </button>\n ` : ''}\n ${this.config.showImport ? `\n <label class=\"file-btn\" title=\"加载项目 (JSON)\">\n <svg class=\"icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M22 19a2 2 0 01-2 2H4a2 2 0 01-2-2V5a2 2 0 012-2h5l2 3h9a2 2 0 012 2z\"/>\n </svg>\n <input type=\"file\" accept=\".json\" class=\"hidden load-json-input\" />\n </label>\n ` : ''}\n ${this.config.showDownload ? `\n <button class=\"file-btn export-png-btn\" title=\"导出 PNG\">\n <svg class=\"icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3\"/>\n </svg>\n </button>\n ` : ''}\n </div>\n ` : ''}\n </div>\n </div>\n\n <!-- 画布容器 -->\n <div class=\"canvas-container\">\n <canvas class=\"main-canvas\"></canvas>\n\n ${this.config.showMinimap ? `\n <div class=\"minimap-wrapper\">\n <div class=\"minimap-header\">\n <svg class=\"minimap-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"/>\n <path d=\"M3 9h18M9 21V9\"/>\n </svg>\n <span>导航</span>\n </div>\n <canvas class=\"minimap-canvas\" width=\"220\" height=\"140\"></canvas>\n </div>\n ` : ''}\n\n <!-- 文本输入 -->\n <div class=\"text-input-container\" style=\"display: none;\">\n <div class=\"text-input-hint\">按 Enter 确认,Esc 取消</div>\n <input type=\"text\" class=\"text-input\" placeholder=\"输入文本...\" />\n </div>\n\n <!-- 空画布提示 -->\n <div class=\"empty-hint\">\n <h3>开始创作</h3>\n <p>选择左侧的工具开始绘制</p>\n </div>\n </div>\n </div>\n </div>\n `;\n\n // 获取 DOM 引用\n this.container = this.shadow.querySelector('.editor-container')!;\n this.toolbar = this.shadow.querySelector('.toolbar')!;\n this.topBar = this.shadow.querySelector('.top-bar')!;\n this.canvasContainer = this.shadow.querySelector('.canvas-container')!;\n this.canvas = this.shadow.querySelector('.main-canvas')!;\n this.ctx = this.canvas.getContext('2d')!;\n\n if (this.config.showMinimap) {\n this.minimapCanvas = this.shadow.querySelector('.minimap-canvas')!;\n this.minimapCtx = this.minimapCanvas.getContext('2d')!;\n }\n\n this.textInputContainer = this.shadow.querySelector('.text-input-container')!;\n this.textInput = this.shadow.querySelector('.text-input')!;\n\n // 绑定事件\n this.bindEvents();\n }\n\n // 绑定事件\n private bindEvents(): void {\n // 画布事件\n this.canvas.addEventListener('mousedown', (e) => this.handleCanvasPointerDown(e));\n this.canvas.addEventListener('mousemove', (e) => this.handleCanvasPointerMove(e));\n this.canvas.addEventListener('mouseup', () => this.handleCanvasPointerUp());\n this.canvas.addEventListener('mouseleave', () => this.handleCanvasPointerUp());\n this.canvas.addEventListener('dblclick', (e) => this.handleCanvasDoubleClick(e));\n this.canvas.addEventListener('touchstart', (e) => this.handleCanvasPointerDown(e));\n this.canvas.addEventListener('touchmove', (e) => this.handleCanvasPointerMove(e));\n this.canvas.addEventListener('touchend', () => this.handleCanvasPointerUp());\n this.canvas.addEventListener('wheel', this.boundHandleWheel, { passive: false });\n\n // 工具按钮\n this.shadow.querySelectorAll('.tool-btn[data-tool]').forEach(btn => {\n btn.addEventListener('mousedown', (e) => {\n // 阻止 blur 事件触发,在点击后手动处理\n e.preventDefault();\n });\n btn.addEventListener('click', () => {\n // 如果有文本输入,先提交\n if (this.isTextInputVisible) {\n this.submitText();\n }\n const tool = btn.getAttribute('data-tool') as ToolType;\n this.setTool(tool);\n });\n });\n\n // 撤销按钮\n const undoBtn = this.shadow.querySelector('.undo-btn');\n if (undoBtn) {\n undoBtn.addEventListener('click', () => this.undo());\n }\n\n // 颜色选择器\n const colorPicker = this.shadow.querySelector('.color-picker') as HTMLInputElement;\n if (colorPicker) {\n colorPicker.addEventListener('input', (e) => {\n this.color = (e.target as HTMLInputElement).value;\n });\n }\n\n // 图片上传\n const imageInput = this.shadow.querySelector('.image-input');\n if (imageInput) {\n imageInput.addEventListener('change', (e) => this.handleImageUpload(e));\n }\n\n // 缩放按钮\n const zoomInBtn = this.shadow.querySelector('.zoom-in-btn');\n const zoomOutBtn = this.shadow.querySelector('.zoom-out-btn');\n const zoomText = this.shadow.querySelector('.zoom-text');\n if (zoomInBtn) zoomInBtn.addEventListener('click', () => this.zoomIn());\n if (zoomOutBtn) zoomOutBtn.addEventListener('click', () => this.zoomOut());\n if (zoomText) zoomText.addEventListener('click', () => this.resetZoom());\n\n // 文件操作\n const saveJsonBtn = this.shadow.querySelector('.save-json-btn');\n const loadJsonInput = this.shadow.querySelector('.load-json-input');\n const exportPngBtn = this.shadow.querySelector('.export-png-btn');\n if (saveJsonBtn) saveJsonBtn.addEventListener('click', () => this.saveJson());\n if (loadJsonInput) loadJsonInput.addEventListener('change', (e) => this.loadJson(e));\n if (exportPngBtn) exportPngBtn.addEventListener('click', () => this.exportPng());\n\n // 小地图点击\n if (this.minimapCanvas) {\n this.minimapCanvas.addEventListener('click', (e) => this.handleMinimapClick(e));\n }\n\n // 文本输入\n if (this.textInput) {\n this.textInput.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n this.submitText();\n } else if (e.key === 'Escape') {\n this.hideTextInput();\n }\n });\n this.textInput.addEventListener('blur', () => {\n if (this.isTextInputVisible) {\n this.submitText();\n }\n });\n }\n }\n\n // 创建工具按钮 HTML\n private createToolButton(tool: ToolType, iconClass: string, title: string): string {\n const icons: Record<string, string> = {\n 'select-icon': '<path d=\"M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z\"/><path d=\"M13 13l6 6\"/>',\n 'pencil-icon': '<path d=\"M17 3a2.85 2.85 0 114 4L7.5 20.5 2 22l1.5-5.5L17 3z\"/>',\n 'rect-icon': '<rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"/>',\n 'circle-icon': '<circle cx=\"12\" cy=\"12\" r=\"10\"/>',\n 'text-icon': '<path d=\"M4 7V4h16v3M9 20h6M12 4v16\"/>',\n };\n const isActive = this.tool === tool;\n return `\n <button class=\"tool-btn ${isActive ? 'active' : ''}\" data-tool=\"${tool}\" title=\"${title}\">\n <svg class=\"icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n ${icons[iconClass]}\n </svg>\n </button>\n `;\n }\n\n // 获取样式\n private getStyles(): string {\n return `\n :host {\n display: block;\n width: 100%;\n height: 100%;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n\n * {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n }\n\n .hidden {\n display: none !important;\n }\n\n .editor-container {\n display: flex;\n width: 100%;\n height: 100%;\n background: #f1f5f9;\n }\n\n /* 工具栏 */\n .toolbar {\n width: 64px;\n background: #ffffff;\n border-right: 1px solid #e2e8f0;\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 12px 8px;\n gap: 4px;\n }\n\n .tool-btn {\n width: 44px;\n height: 44px;\n border: none;\n background: transparent;\n border-radius: 12px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #64748b;\n transition: all 0.2s;\n }\n\n .tool-btn:hover {\n background: #f1f5f9;\n color: #4f46e5;\n }\n\n .tool-btn.active {\n background: #4f46e5;\n color: #ffffff;\n box-shadow: 0 4px 12px rgba(79, 70, 229, 0.3);\n transform: scale(1.05);\n }\n\n .tool-btn:disabled {\n color: #cbd5e1;\n cursor: not-allowed;\n }\n\n .tool-btn:disabled:hover {\n background: transparent;\n color: #cbd5e1;\n }\n\n .icon {\n width: 20px;\n height: 20px;\n }\n\n .divider {\n width: 32px;\n height: 1px;\n background: #e2e8f0;\n margin: 8px 0;\n }\n\n .spacer {\n flex: 1;\n }\n\n .color-picker {\n width: 32px;\n height: 32px;\n border: 2px solid #e2e8f0;\n border-radius: 50%;\n cursor: pointer;\n padding: 0;\n overflow: hidden;\n -webkit-appearance: none;\n }\n\n .color-picker::-webkit-color-swatch-wrapper {\n padding: 0;\n }\n\n .color-picker::-webkit-color-swatch {\n border: none;\n border-radius: 50%;\n }\n\n /* 主区域 */\n .main-area {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n /* 顶部栏 */\n .top-bar {\n height: 56px;\n background: #ffffff;\n border-bottom: 1px solid #e2e8f0;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0 16px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);\n }\n\n .top-bar-left, .top-bar-right {\n display: flex;\n align-items: center;\n gap: 16px;\n }\n\n .title {\n font-size: 16px;\n font-weight: 600;\n color: #334155;\n }\n\n .selection-info {\n display: none;\n align-items: center;\n gap: 8px;\n background: #eef2ff;\n padding: 4px 12px;\n border-radius: 20px;\n border: 1px solid #c7d2fe;\n }\n\n .selection-info.visible {\n display: flex;\n }\n\n .selection-label {\n font-size: 12px;\n font-weight: 600;\n color: #4f46e5;\n text-transform: uppercase;\n }\n\n .delete-btn {\n background: none;\n border: none;\n color: #ef4444;\n cursor: pointer;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .delete-btn:hover {\n color: #dc2626;\n }\n\n .zoom-controls, .file-controls {\n display: flex;\n align-items: center;\n background: #f1f5f9;\n border-radius: 8px;\n padding: 4px;\n }\n\n .zoom-btn, .file-btn {\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #475569;\n transition: all 0.2s;\n }\n\n .zoom-btn:hover, .file-btn:hover {\n color: #4f46e5;\n }\n\n .zoom-text {\n padding: 4px 8px;\n font-size: 12px;\n font-weight: 500;\n color: #475569;\n background: transparent;\n border: none;\n cursor: pointer;\n min-width: 50px;\n text-align: center;\n }\n\n .zoom-text:hover {\n color: #4f46e5;\n }\n\n /* 画布容器 */\n .canvas-container {\n flex: 1;\n position: relative;\n background: #f1f5f9;\n overflow: hidden;\n }\n\n .main-canvas {\n position: absolute;\n inset: 0;\n display: block;\n cursor: crosshair;\n touch-action: none;\n }\n\n /* 小地图 */\n .minimap-wrapper {\n position: absolute;\n top: 16px;\n right: 16px;\n z-index: 30;\n border-radius: 12px;\n overflow: hidden;\n box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n padding: 2px;\n }\n\n .minimap-wrapper > * {\n background: #ffffff;\n }\n\n .minimap-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: linear-gradient(to right, #f8fafc, #f1f5f9);\n border-bottom: 1px solid #e2e8f0;\n font-size: 12px;\n font-weight: 600;\n color: #475569;\n border-radius: 10px 10px 0 0;\n }\n\n .minimap-icon {\n width: 12px;\n height: 12px;\n color: #4f46e5;\n }\n\n .minimap-canvas {\n cursor: pointer;\n background: #f8fafc;\n border-radius: 0 0 10px 10px;\n display: block;\n }\n\n .minimap-canvas:hover {\n filter: brightness(1.05);\n }\n\n /* 文本输入 */\n .text-input-container {\n position: absolute;\n z-index: 20;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n }\n\n .text-input-hint {\n background: rgba(0, 0, 0, 0.75);\n color: #fff;\n font-size: 12px;\n padding: 4px 8px;\n border-radius: 4px;\n margin-bottom: 4px;\n white-space: nowrap;\n }\n\n .text-input {\n padding: 8px 12px;\n border: 2px solid #4f46e5;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n outline: none;\n min-width: 200px;\n font-size: 16px;\n }\n\n /* 空画布提示 */\n .empty-hint {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n pointer-events: none;\n opacity: 0.4;\n }\n\n .empty-hint h3 {\n font-size: 24px;\n font-weight: 700;\n color: #94a3b8;\n margin-bottom: 8px;\n }\n\n .empty-hint p {\n color: #94a3b8;\n }\n `;\n }\n}\n\n// 注册 Web Component\nif (typeof window !== 'undefined' && !customElements.get('canvas-drawing-editor')) {\n customElements.define('canvas-drawing-editor', CanvasDrawingEditor);\n}\n"],"names":["defaultConfig","CanvasDrawingEditor","name","oldValue","newValue","initialData","data","obj","img","err","e","rect","clientX","clientY","x","y","r","c","t","width","p","minX","pt","maxX","minY","maxY","bounds","handleSize","handles","handle","previousState","o","selectedObj","newObj","mouseX","mouseY","delta","newScale","centerX","centerY","clampedScale","mouseXBeforeZoom","mouseYBeforeZoom","newPanOffsetX","newPanOffsetY","zoomText","tool","btn","screenX","screenY","text","value","_b","_a","existingObj","screenPos","clickedObject","id","dx","dy","newX","newY","newWidth","newHeight","radius","origT","scaleFactor","origP","scaleX","scaleY","textObj","ctx","isMinimap","i","imgObj","corner","minimap","mainCanvas","minimapScale","canvasW","canvasH","offsetX","offsetY","clickX","clickY","relX","relY","canvasX","canvasY","viewportCenterX","viewportCenterY","input","file","reader","event","dataUrl","maxSize","height","ratio","imageElement","rest","json","blob","url","a","tempCanvas","tempCtx","selectionInfo","typeLabel","deleteBtn","undoBtn","emptyHint","colorPicker","imageInput","zoomInBtn","zoomOutBtn","saveJsonBtn","loadJsonInput","exportPngBtn","iconClass","title","icons"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -56,6 +56,7 @@ export declare class CanvasDrawingEditor extends HTMLElement {
|
|
|
56
56
|
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
|
|
57
57
|
private parseAttributes;
|
|
58
58
|
private generateId;
|
|
59
|
+
private loadInitialData;
|
|
59
60
|
private setupEventListeners;
|
|
60
61
|
private removeEventListeners;
|
|
61
62
|
private handleResize;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "canvas-drawing-editor",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "A powerful canvas-based drawing editor Web Component - Zero dependencies, works with Vue 2/3, React, Angular, and vanilla HTML",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/canvas-drawing-editor.umd.js",
|