@8btc/whiteboard 0.0.3 → 0.0.5

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.umd.js","sources":["../src/app/core/stage.ts","../src/app/core/transformer.ts","../src/app/core/state.ts","../src/app/core/utils/const.ts","../src/const/shape.ts","../src/lib/math.ts","../src/lib/shape.ts","../src/app/canvas/helpers/helpers.ts","../src/app/core/node/base.ts","../src/app/core/node/rect.ts","../src/app/core/node/image.ts","../src/app/core/node/image-marker.ts","../src/app/core/node/_factory.ts","../src/app/core/utils/draft.ts","../src/app/core/core.ts","../src/app/core/api.ts","../src/app/jsx/GridBackground.tsx","../src/lib/utils.ts","../src/components/ui/button.tsx","../src/app/jsx/ZoomPanel.tsx","../src/app/jsx/HistoryPanel.tsx","../src/app/React.tsx"],"sourcesContent":["import Konva from \"konva\";\nimport type { KonvaEventObject } from \"konva/lib/Node\";\nimport type { CanvasCore } from \"./core\";\n\nexport type StageConfig = {\n container: HTMLDivElement;\n width: number;\n height: number;\n draggable?: boolean;\n className?: string;\n};\n\nexport type ViewportState = {\n x: number;\n y: number;\n scale: number;\n width?: number;\n height?: number;\n};\n\n/**\n * CanvasStage 封装了 Konva.Stage 的核心功能\n * 提供视口管理、事件处理、拖拽和缩放等能力\n */\nexport class CanvasStage {\n #core: CanvasCore;\n #stage: Konva.Stage;\n #viewport: ViewportState = { x: 0, y: 0, scale: 1 };\n\n constructor(core: CanvasCore, config: StageConfig) {\n this.#core = core;\n this.#stage = new Konva.Stage({\n container: config.container,\n width: config.width,\n height: config.height,\n x: 0,\n y: 0,\n scaleX: 1,\n scaleY: 1,\n draggable: config.draggable ?? false,\n className: config.className,\n });\n\n this.#setupEventListeners();\n }\n\n /**\n * 获取原生 Konva.Stage 实例\n */\n getStage(): Konva.Stage {\n return this.#stage;\n }\n\n /**\n * 获取当前视口状态\n */\n getViewport(): ViewportState {\n return { ...this.#viewport };\n }\n\n /**\n * 设置视口(包括位置、缩放和尺寸)\n */\n setViewport(viewport: Partial<ViewportState>): void {\n const newViewport = { ...this.#viewport, ...viewport };\n this.#viewport = newViewport;\n\n if (viewport.x !== undefined) {\n this.#stage.x(viewport.x);\n }\n if (viewport.y !== undefined) {\n this.#stage.y(viewport.y);\n }\n if (viewport.scale !== undefined) {\n this.#stage.scaleX(viewport.scale);\n this.#stage.scaleY(viewport.scale);\n }\n if (viewport.width !== undefined) {\n this.#stage.width(viewport.width);\n }\n if (viewport.height !== undefined) {\n this.#stage.height(viewport.height);\n }\n }\n\n /**\n * 设置是否可拖拽\n */\n setDraggable(draggable: boolean): void {\n this.#stage.draggable(draggable);\n }\n\n /**\n * 设置光标样式\n */\n setCursor(cursor: string): void {\n const container = this.#stage.container();\n container.style.cursor = cursor;\n }\n\n /**\n * 重置光标样式\n */\n resetCursor(): void {\n const container = this.#stage.container();\n const toolType = this.#core.getState().toolType;\n if (toolType === \"hand\") {\n container.style.cursor = \"grab\";\n return;\n }\n container.style.cursor = \"default\";\n }\n\n /**\n * 销毁 Stage\n */\n destroy(): void {\n this.#stage.destroy();\n }\n\n /**\n * 处理滚轮缩放和平移\n */\n #handleWheel = (e: KonvaEventObject<WheelEvent>) => {\n e.evt.preventDefault();\n\n const stage = this.#stage;\n const pointer = stage.getPointerPosition();\n if (!pointer) return;\n\n // 检测是否为捏合缩放手势(触控板捏合时 ctrlKey 为 true)\n if (e.evt.ctrlKey) {\n // 缩放操作\n const oldScale = this.#viewport.scale;\n const mousePointTo = {\n x: (pointer.x - this.#viewport.x) / oldScale,\n y: (pointer.y - this.#viewport.y) / oldScale,\n };\n\n const scaleBy = 1.01;\n const direction = e.evt.deltaY > 0 ? -1 : 1;\n const steps = Math.min(Math.abs(e.evt.deltaY), 10);\n let newScale = oldScale;\n\n for (let i = 0; i < steps; i++) {\n newScale = direction > 0 ? newScale * scaleBy : newScale / scaleBy;\n }\n\n // 限制缩放范围 (10% ~ 500%)\n const scale = Math.max(0.1, Math.min(5, newScale));\n\n const newPos = {\n x: pointer.x - mousePointTo.x * scale,\n y: pointer.y - mousePointTo.y * scale,\n };\n\n this.#core.updateViewport({ x: newPos.x, y: newPos.y, scale });\n } else {\n // 平移操作(双指滑动或鼠标滚轮)\n const deltaX = e.evt.shiftKey ? e.evt.deltaY : e.evt.deltaX;\n const deltaY = e.evt.shiftKey ? 0 : e.evt.deltaY;\n\n this.#core.updateViewport({\n x: this.#viewport.x - deltaX,\n y: this.#viewport.y - deltaY,\n });\n }\n };\n\n #handlePointerDown = (event: KonvaEventObject<PointerEvent>): void => {\n const toolType = this.#core.getState().toolType;\n if (event.evt.button !== 0 || toolType === \"hand\") {\n return;\n }\n\n const clickedOnEmpty = event.target === this.#stage;\n const pointerPos = this.#stage.getRelativePointerPosition();\n\n if (toolType === \"select\" && !clickedOnEmpty) {\n const nodeId = event.target.id();\n if (nodeId) {\n this.#core.selectNode(nodeId, event.evt.shiftKey);\n }\n return;\n }\n\n if (toolType === \"rectangle\" && pointerPos) {\n this.#core.createDraftNode(toolType, pointerPos);\n }\n\n if (toolType === \"image-marker\" && pointerPos) {\n // 查找点击位置的图片\n const imageShape = this.#core.findImageAtPosition(pointerPos);\n console.log(imageShape, \"imageShape\");\n if (imageShape) {\n const width = imageShape.width();\n const height = imageShape.height();\n if (width && height) {\n // 设置图片边界用于限制绘制区域\n const imageBounds = {\n x: imageShape.x(),\n y: imageShape.y(),\n width,\n height,\n };\n this.#core.createDraftNode(toolType, pointerPos, {\n parent: imageShape.id(),\n bounds: imageBounds,\n startPosition: pointerPos,\n });\n }\n }\n }\n\n this.#core.selectNode();\n };\n\n #handlePointerMove = (): void => {\n const toolType = this.#core.getState().toolType;\n if (toolType === \"hand\") {\n return;\n }\n\n const pointerPos = this.#stage.getRelativePointerPosition();\n\n if (\n (toolType === \"rectangle\" || toolType === \"image-marker\") &&\n pointerPos\n ) {\n this.#core.updateDraftNode(pointerPos);\n }\n };\n\n #handlePointerUp = (): void => {\n const toolType = this.#core.getState().toolType;\n if (toolType === \"hand\") {\n return;\n }\n\n if (toolType === \"rectangle\" || toolType === \"image-marker\") {\n this.#core.finalizeDraftNode();\n }\n };\n\n #handleDragStart = (event: KonvaEventObject<DragEvent>): void => {\n if (event.target !== this.#stage) {\n return;\n }\n const toolType = this.#core.getState().toolType;\n if (toolType === \"hand\") {\n this.setCursor(\"grabbing\");\n } else if (toolType === \"select\") {\n this.setCursor(\"all-scroll\");\n }\n };\n\n #handleDragMove = (event: KonvaEventObject<DragEvent>): void => {\n if (event.target !== this.#stage) {\n return;\n }\n this.#core.updateViewport({\n x: this.#stage.x(),\n y: this.#stage.y(),\n });\n };\n\n #handleDragEnd = (event: KonvaEventObject<DragEvent>): void => {\n if (event.target !== this.#stage) {\n return;\n }\n this.#core.updateViewport({\n x: this.#stage.x(),\n y: this.#stage.y(),\n });\n this.resetCursor();\n };\n\n /**\n * 设置事件监听器\n */\n #setupEventListeners(): void {\n this.#stage.on(\"wheel\", this.#handleWheel);\n this.#stage.on(\"pointerdown\", this.#handlePointerDown);\n this.#stage.on(\"pointermove\", this.#handlePointerMove);\n this.#stage.on(\"pointerup\", this.#handlePointerUp);\n this.#stage.on(\"dragstart\", this.#handleDragStart);\n this.#stage.on(\"dragmove\", this.#handleDragMove);\n this.#stage.on(\"dragend\", this.#handleDragEnd);\n }\n}\n","import Konva from \"konva\";\nimport type { CanvasCore } from \"./core\";\nimport type { TransformerPosition } from \"@/types\";\n\nexport type TransformerConfig = {\n rotateEnabled?: boolean;\n ignoreStroke?: boolean;\n anchorSize?: number;\n borderDash?: number[];\n anchorCornerRadius?: number;\n padding?: number;\n};\n\n/**\n * CanvasTransformer 封装了 Konva.Transformer 的核心功能\n * 提供变换器管理、位置计算、事件处理等能力\n */\nexport class CanvasTransformer {\n #core: CanvasCore;\n #transformer: Konva.Transformer;\n\n constructor(core: CanvasCore, config?: TransformerConfig) {\n this.#core = core;\n this.#transformer = new Konva.Transformer({\n rotateEnabled: config?.rotateEnabled ?? true,\n ignoreStroke: config?.ignoreStroke ?? true,\n anchorSize: config?.anchorSize ?? 8,\n borderDash: config?.borderDash ?? [4, 4],\n anchorCornerRadius: config?.anchorCornerRadius ?? 4,\n padding: config?.padding ?? 6,\n });\n\n this.#setupEventListeners();\n }\n\n /**\n * 获取原生 Konva.Transformer 实例\n */\n getTransformer(): Konva.Transformer {\n return this.#transformer;\n }\n\n /**\n * 获取 Transformer 的位置信息\n */\n getPosition(): TransformerPosition | null {\n const nodes = this.#transformer.nodes();\n if (nodes.length === 0) {\n return null;\n }\n\n const box = this.#transformer.getClientRect();\n return {\n x: box.x,\n y: box.y,\n width: box.width,\n height: box.height,\n rotation: this.#transformer.rotation(),\n };\n }\n\n /**\n * 设置要变换的节点\n */\n setNodes(nodes: Konva.Node[]): void {\n if (nodes.length === 0) {\n this.clearNodes();\n return;\n }\n this.#transformer.nodes(nodes);\n this.#transformer.moveToTop();\n this.emitPositionChange();\n }\n\n /**\n * 获取当前变换的节点\n */\n getNodes(): Konva.Node[] {\n return this.#transformer.nodes();\n }\n\n /**\n * 清除所有节点\n */\n clearNodes(): void {\n this.#transformer.nodes([]);\n this.#transformer.moveToBottom();\n this.emitPositionChange();\n }\n\n /**\n * emit Transformer 位置\n */\n emitPositionChange(): void {\n const position = this.getPosition();\n this.#core.emitEvent(\"transformer:positionChange\", position);\n }\n\n /**\n * 处理 transformstart 事件\n */\n #handleTransformStart = (): void => {\n this.emitPositionChange();\n };\n\n /**\n * 处理 transform 事件\n */\n #handleTransform = (): void => {\n console.log(\"transforming...\");\n this.emitPositionChange();\n };\n\n /**\n * 处理 transformend 事件\n */\n #handleTransformEnd = (): void => {\n this.emitPositionChange();\n };\n\n /**\n * 处理 dragstart 事件\n */\n #handleDragStart = (): void => {\n this.emitPositionChange();\n };\n\n /**\n * 处理 dragmove 事件\n */\n #handleDragMove = (): void => {\n this.emitPositionChange();\n };\n\n /**\n * 处理 dragend 事件\n */\n #handleDragEnd = (): void => {\n this.emitPositionChange();\n };\n\n /**\n * 设置事件监听器\n */\n #setupEventListeners(): void {\n // Transform 事件\n this.#transformer.on(\"transformstart\", this.#handleTransformStart);\n this.#transformer.on(\"transform\", this.#handleTransform);\n this.#transformer.on(\"transformend\", this.#handleTransformEnd);\n\n // Drag 事件\n this.#transformer.on(\"dragstart\", this.#handleDragStart);\n this.#transformer.on(\"dragmove\", this.#handleDragMove);\n this.#transformer.on(\"dragend\", this.#handleDragEnd);\n }\n\n /**\n * 销毁 Transformer\n */\n destroy(): void {\n this.#transformer.destroy();\n }\n}\n","import mitt, { type Emitter } from \"mitt\";\nimport type { ICoreState, HistoryState } from \"./type\";\nimport type { TransformerPosition } from \"@/types\";\n\n/**\n * 状态事件类型定义\n */\nexport type StateEvents = {\n \"state:change\": ICoreState;\n \"state:undo\": ICoreState;\n \"state:redo\": ICoreState;\n \"state:reset\": ICoreState;\n \"viewport:change\": ICoreState[\"viewport\"];\n \"transformer:positionChange\": TransformerPosition | null;\n \"toolType:change\": ICoreState[\"toolType\"];\n};\n\n/**\n * CanvasState 类负责管理画布的状态\n * 包括历史记录(past/present/future)和状态监听\n */\nexport class CanvasState {\n private _past: ICoreState[] = [];\n private _present: ICoreState;\n private _future: ICoreState[] = [];\n private _emitter: Emitter<StateEvents>;\n\n constructor(initialState: ICoreState) {\n this._present = initialState;\n this._emitter = mitt<StateEvents>();\n }\n\n /**\n * 获取当前状态\n */\n getState(): ICoreState {\n return { ...this._present };\n }\n\n /**\n * 获取完整历史状态\n */\n getHistory(): HistoryState<ICoreState> {\n return {\n past: [...this._past],\n present: { ...this._present },\n future: [...this._future],\n };\n }\n\n /**\n * 是否可以撤销\n */\n canUndo(): boolean {\n return this._past.length > 0;\n }\n\n /**\n * 是否可以重做\n */\n canRedo(): boolean {\n return this._future.length > 0;\n }\n\n /**\n * 订阅状态事件\n */\n on<K extends keyof StateEvents>(\n event: K,\n handler: (data: StateEvents[K]) => void\n ): void {\n this._emitter.on(event, handler);\n }\n\n /**\n * 取消订阅状态事件\n */\n off<K extends keyof StateEvents>(\n event: K,\n handler: (data: StateEvents[K]) => void\n ): void {\n this._emitter.off(event, handler);\n }\n\n /**\n * 发送事件\n */\n protected emit<K extends keyof StateEvents>(\n event: K,\n data: StateEvents[K]\n ): void {\n this._emitter.emit(event, data);\n }\n\n /**\n * 撤销操作\n */\n undo(): void {\n if (this._past.length === 0) return;\n\n const previous = this._past[this._past.length - 1];\n const newPast = this._past.slice(0, this._past.length - 1);\n\n this._past = newPast;\n this._future = [this._present, ...this._future];\n this._present = previous;\n\n // 同步状态(由子类实现)\n this._syncState(previous);\n this._emitter.emit(\"state:undo\", previous);\n this._emitter.emit(\"state:change\", previous);\n }\n\n /**\n * 重做操作\n */\n redo(): void {\n if (this._future.length === 0) return;\n\n const next = this._future[0];\n const newFuture = this._future.slice(1);\n\n this._past = [...this._past, this._present];\n this._future = newFuture;\n this._present = next;\n\n // 同步状态(由子类实现)\n this._syncState(next);\n this._emitter.emit(\"state:redo\", next);\n this._emitter.emit(\"state:change\", next);\n }\n\n /**\n * 重置历史记录\n */\n resetHistory(): void {\n this._past = [];\n this._future = [];\n this._emitter.emit(\"state:reset\", this._present);\n this._emitter.emit(\"state:change\", this._present);\n }\n\n /**\n * 更新状态\n * @param partial - 部分状态更新\n * @param addToHistory - 是否添加到历史记录\n */\n protected _updateState(\n partial: Partial<ICoreState>,\n addToHistory = true\n ): void {\n const newState = { ...this._present, ...partial };\n\n if (addToHistory) {\n this._past = [...this._past, this._present];\n this._future = [];\n }\n\n this._present = newState;\n this._emitter.emit(\"state:change\", newState);\n }\n\n /**\n * 同步状态到外部系统(由子类实现)\n * @param _state - 要同步的状态\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n protected _syncState(_state: ICoreState): void {\n // 空实现,由子类覆盖\n }\n\n /**\n * 清理资源\n */\n protected _dispose(): void {\n this._emitter.all.clear();\n }\n}\n","export const NODE_NAME_FOR_SELECT = \"shapeNameForSelect\";\n\nexport const RECT = {\n CORNER_RADIUS: 6,\n MIN_SIZE: 10,\n};\n\nexport const IMAGE = {\n MIN_SIZE: 10,\n};\n","import { defaultTheme } from \"./theme\";\n\nexport const TRANSFORMER = {\n NAME: \"transformer\",\n MIN_SIZE: 10,\n ROTATION_SNAPS: [0, 90, 180, 270],\n ROTATION_ANCHOR_OFFSET: 24,\n PADDING: 6,\n ANCHOR_CORNER_RADIUS: 5,\n ANCHOR_SIZE: 9,\n ANCHOR_STROKE_WIDTH: 1.5,\n ANCHOR_STROKE: defaultTheme.colors.green300,\n BORDER_STROKE: defaultTheme.colors.green300,\n};\n\nexport const ARROW_TRANSFORMER = {\n RADIUS: 3.75,\n ANCHOR_STROKE_WIDTH: 2.75,\n ANCHOR_STROKE_WIDTH_HOVER: 11,\n HIT_STROKE_WIDTH: 16,\n STROKE: defaultTheme.colors.green300,\n NAME: \"arrow-transformer\",\n ANCHOR_NAME: \"arrow-transformer-anchor\",\n SNAP_OFFSET: 8,\n} as const;\n\nexport const ARROW = {\n HEAD_WIDTH: 6,\n HEAD_LENGTH: 6,\n DEFAULT_BEND: 0.5,\n};\n\nexport const FREE_PATH = {\n TENSION: 0.5,\n};\n\nexport const RECT = {\n CORNER_RADIUS: 6,\n MIN_SIZE: 10,\n};\n\nexport const ELLIPSE = {\n MIN_RADIUS: 5,\n} as const;\n\nexport const TEXT = {\n PADDING: 4,\n LINE_HEIGHT: 1,\n FONT_FAMILY: \"Klee One\",\n FONT_WEIGHT: \"bold\",\n NAME: \"text\",\n};\n\nexport const SELECT_RECT = {\n STROKE: defaultTheme.colors.red500,\n FILL: defaultTheme.colors.gray400,\n CORNER_RADIUS: 1,\n OPACITY: 0.1,\n};\n\nexport const LASER = {\n TRIM_COUNT: 2,\n TRIM_INTERVAL: 24,\n TRIM_DELAY: 250,\n MAX_LENGTH: 50,\n WIDTH: 3.5,\n COLOR: defaultTheme.colors.red500,\n} as const;\n\nexport const IMAGE = {\n MIN_SIZE: 20,\n} as const;\n","import type { IRect, Vector2d } from \"konva/lib/types\";\nimport type { NodeObject, Point } from \"@/types\";\nimport { RECT } from \"@/const/shape\";\n\nexport function getRatioFromValue(value: number, min: number, max: number) {\n return max === min ? 1 : (value - min) / (max - min);\n}\n\nexport function getValueFromRatio(ratio: number, min: number, max: number) {\n return ratio * (max - min) + min;\n}\n\nexport function calculateMiddlePoint(rect: IRect): Vector2d {\n return {\n x: rect.x + rect.x + rect.width / 2,\n y: rect.y + rect.y + rect.height / 2,\n };\n}\n\nexport function calculateMidPointFromRange(start: Point, end: Point): Point {\n return [(start[0] + end[0]) / 2, (start[1] + end[1]) / 2];\n}\n\nexport function clamp(value: number, range: [min: number, max: number]) {\n return Math.min(Math.max(value, range[0]), range[1]);\n}\n\ninterface Bounds {\n x: number; // 矩形左上角 x\n y: number; // 矩形左上角 y\n width: number; // 宽度\n height: number; // 高度\n}\n\n/**\n * 限制坐标点在指定的矩形区域内\n * @param point 待处理的坐标 {x, y}\n * @param bounds 限制范围 {x, y, width, height}\n */\nexport const clampToBounds = (point: Point, bounds: Bounds): Point => {\n return [\n clamp(point[0], [bounds.x, bounds.x + bounds.width]),\n clamp(point[1], [bounds.y, bounds.y + bounds.height]),\n ];\n};\n\nexport function calculateLengthFromPoints(points: Point[]) {\n let length = 0;\n\n for (let i = 0; i < points.length - 1; i++) {\n const [x1, y1] = points[i];\n const [x2, y2] = points[i + 1];\n const deltaX = x2 - x1;\n const deltaY = y2 - y1;\n\n length += Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));\n }\n\n return length;\n}\n\nexport function calculatePerimeter(\n width: number,\n height: number,\n cornerRadius: number\n) {\n return 2 * (height + width - cornerRadius * (4 - Math.PI));\n}\n\nexport function calculateCircumference(rx: number, ry: number): number {\n const a = rx;\n const b = ry;\n const h = Math.pow(a - b, 2) / Math.pow(a + b, 2);\n\n return Math.PI * (a + b) * (1 + (3 * h) / (10 + Math.sqrt(4 - 3 * h)));\n}\n\nexport function getShapeLength(node: NodeObject): number {\n if (Array.isArray(node.nodeProps.points)) {\n return calculateLengthFromPoints([\n node.nodeProps.point,\n ...node.nodeProps.points,\n ]);\n }\n\n if (node.nodeProps.width && node.nodeProps.height) {\n if (node.type === \"ellipse\") {\n return calculateCircumference(\n node.nodeProps.width,\n node.nodeProps.height\n );\n }\n if (node.type === \"rectangle\") {\n return calculatePerimeter(\n node.nodeProps.width,\n node.nodeProps.height,\n RECT.CORNER_RADIUS\n );\n }\n }\n\n return 0;\n}\n","import { defaultTheme, darkTheme } from \"@/const/theme\";\nimport { hexToRGBa } from \"./string\";\nimport { getShapeLength } from \"./math\";\nimport type {\n NodeColor,\n NodeFill,\n NodeLine,\n NodeObject,\n NodeSize,\n ThemeColorValue,\n ThemeColors,\n} from \"@/types\";\nimport type { ShapeConfig } from \"konva/lib/Shape\";\n\nexport function getDashValue(\n shapeLength: number,\n strokeWidth: number,\n lineStyle: NodeLine\n) {\n let ratio = 1;\n let dashLength = 0;\n let dashGap = 0;\n\n switch (lineStyle) {\n case \"dashed\":\n dashLength = Math.min(strokeWidth * 2, shapeLength / 4);\n break;\n case \"dotted\":\n ratio = 8;\n dashLength = strokeWidth / ratio;\n break;\n default:\n return [];\n }\n\n let dashCount = Math.floor(shapeLength / dashLength / (2 * ratio));\n dashCount = Math.max(dashCount, 3);\n\n dashLength = shapeLength / dashCount / (2 * ratio);\n dashGap = (shapeLength - dashCount * dashLength) / dashCount;\n\n return [dashLength, dashGap];\n}\n\nexport function getSizeValue(key: NodeSize) {\n switch (key) {\n case \"small\":\n return 2;\n case \"medium\":\n return 3;\n case \"large\":\n return 5;\n case \"extra-large\":\n return 8;\n default:\n return 3;\n }\n}\n\nexport function getColorValue(\n key: NodeColor,\n themeColors: ThemeColors\n): ThemeColorValue {\n if (key in themeColors) {\n return themeColors[key as keyof ThemeColors];\n }\n\n return themeColors.black;\n}\n\nexport function getFillValue(fill: NodeFill, colorValue: ThemeColorValue) {\n switch (fill) {\n case \"semi\": {\n return \"transparent\";\n }\n case \"solid\": {\n return hexToRGBa(colorValue, 0.25);\n }\n default:\n return undefined;\n }\n}\n\nexport function getDashStyle(\n node: NodeObject,\n sizeValue: number,\n scale: number\n) {\n if (node.style.line === \"solid\") {\n return [];\n }\n\n const shapeLength = getShapeLength(node) * scale;\n const strokeWidth = sizeValue * scale;\n\n return getDashValue(shapeLength, strokeWidth, node.style.line);\n}\n\nexport function getTotalDashLength(dash: ShapeConfig[\"dash\"]) {\n return Array.isArray(dash) && dash.length > 1 ? dash[0] + dash[1] : 0;\n}\n\nexport function getFontSize(size: number) {\n return size * 8;\n}\n\nexport function getCurrentThemeColors({\n isDarkTheme,\n}: {\n isDarkTheme: boolean;\n}) {\n return isDarkTheme ? darkTheme.colors : defaultTheme.colors;\n}\n","import { RECT, TEXT, TRANSFORMER } from \"@/const/shape\";\nimport type Konva from \"konva\";\nimport type { Box } from \"konva/lib/shapes/Transformer\";\n\nexport function normalizeTransformerSize(oldBox: Box, newBox: Box) {\n if (\n newBox.width < TRANSFORMER.MIN_SIZE ||\n newBox.height < TRANSFORMER.MIN_SIZE\n ) {\n return oldBox;\n }\n\n return newBox;\n}\n\nexport function getNodeSize(width: number, scale: number, min = 20) {\n return Math.max(width * scale, min);\n}\n\nexport function getSizePropsFromTextValue(text: string, fontSize: number) {\n const lines = text.split(\"\\n\");\n const longestLine = Math.max(...lines.map((line) => line.length), 1);\n const numberOfLines = lines.length;\n\n return {\n width: `calc(${longestLine}ch + ${TEXT.PADDING}px)`,\n height: `${\n fontSize * numberOfLines * TEXT.LINE_HEIGHT + TEXT.PADDING * 4\n }px`,\n };\n}\n\nexport function getRectSize(rect: Konva.Rect) {\n return {\n width: Math.max(RECT.MIN_SIZE, rect.width() * rect.scaleX()),\n height: Math.max(RECT.MIN_SIZE, rect.height() * rect.scaleY()),\n };\n}\n","import type Konva from \"konva\";\nimport type { CanvasCore } from \"../core\";\nimport type { INode } from \"../type\";\nimport type { ICanvasNode } from \"../type\";\n\n/**\n * BaseCanvasNode 基类\n * 为所有 Canvas 节点提供通用功能,如监听 toolType 变化控制交互性\n */\nexport abstract class BaseCanvasNode<T extends INode = INode>\n implements ICanvasNode\n{\n protected core: CanvasCore;\n protected node: T;\n protected element: Konva.Shape | Konva.Group;\n private toolTypeChangeHandler: (toolType: string) => void;\n\n constructor(core: CanvasCore, node: T) {\n this.core = core;\n this.node = node;\n this.element = this.createElement();\n\n // 监听 toolType 变化\n this.toolTypeChangeHandler = (toolType: string) => {\n const isSelect = toolType === \"select\";\n this.element.listening(isSelect);\n };\n\n // 设置初始状态\n this.toolTypeChangeHandler(this.core.getToolType());\n\n // 监听变化\n this.core.on(\"toolType:change\", this.toolTypeChangeHandler);\n }\n\n /**\n * 获取 Konva 元素\n */\n getElement(): Konva.Shape | Konva.Group {\n return this.element;\n }\n\n /**\n * 获取节点数据\n */\n getNode(): INode {\n return this.node;\n }\n\n /**\n * 子类必须实现:创建 Konva 元素\n */\n protected abstract createElement(): Konva.Shape | Konva.Group;\n\n /**\n * 子类必须实现:更新节点数据\n */\n abstract updateNode(node: Partial<INode>): void;\n\n /**\n * 销毁节点\n */\n destroy(): void {\n // 移除事件监听\n this.core.off(\"toolType:change\", this.toolTypeChangeHandler);\n this.element.destroy();\n }\n}\n","import Konva from \"konva\";\nimport { RECT } from \"../utils/const\";\nimport { calculatePerimeter } from \"@/lib/math\";\nimport { getDashValue, getSizeValue, getTotalDashLength } from \"@/lib/shape\";\nimport { getRectSize } from \"@/app/canvas/helpers\";\nimport type { NodeObject } from \"@/types\";\nimport type { KonvaEventObject } from \"konva/lib/Node\";\nimport type { CanvasCore } from \"../core\";\nimport type { INode } from \"../type\";\nimport { NODE_NAME_FOR_SELECT } from \"../utils/const\";\nimport { BaseCanvasNode } from \"./base\";\n\nexport interface RectConfig {\n node: NodeObject<\"rectangle\">;\n stageScale: number;\n config: Konva.RectConfig;\n}\n\nexport interface AnimationControl {\n start: () => void;\n stop: () => void;\n isRunning: () => boolean;\n}\n\n/**\n * 创建 Rect 动画控制器\n */\nexport function createRectAnimation(\n rect: Konva.Rect,\n totalDashLength: number\n): AnimationControl | null {\n if (!totalDashLength || totalDashLength === 0) {\n return null;\n }\n\n const anim = new Konva.Animation((frame) => {\n if (!frame) return;\n const dashOffset = (-frame.time / 10) % totalDashLength;\n rect.dashOffset(dashOffset);\n }, rect.getLayer());\n\n return {\n start: () => anim.start(),\n stop: () => anim.stop(),\n isRunning: () => anim.isRunning(),\n };\n}\n\n/**\n * RectNode 类封装了 Konva.Rect 的业务逻辑\n */\nexport class RectNode extends BaseCanvasNode<INode<\"rectangle\">> {\n #animation: AnimationControl | null = null;\n\n constructor(core: CanvasCore, node: INode<\"rectangle\">) {\n super(core, node);\n\n // 初始化动画\n if (node.style.animated) {\n this.#initAnimation();\n }\n\n // 设置事件监听(必须在 super 之后,确保私有字段已初始化)\n this.#setupEventHandlers(this.getElement());\n }\n\n protected createElement(): Konva.Rect {\n // 计算尺寸\n const width = Math.max(\n this.node.props.width ?? RECT.MIN_SIZE,\n RECT.MIN_SIZE\n );\n const height = Math.max(\n this.node.props.height ?? RECT.MIN_SIZE,\n RECT.MIN_SIZE\n );\n\n // 创建 Rect\n const config: Konva.RectConfig = {\n id: this.node.id,\n ...this.node.props,\n ...this.node.style,\n width: width,\n height: height,\n cornerRadius: RECT.CORNER_RADIUS,\n name: NODE_NAME_FOR_SELECT,\n draggable: true,\n stroke: \"black\",\n strokeWidth: 2,\n };\n const rect = new Konva.Rect(config);\n // todo: 直接设置在 constructor 中不生效的问题\n rect.setAttrs({\n width,\n height,\n });\n\n return rect;\n }\n\n /**\n * 获取 Konva.Rect 实例\n */\n getElement(): Konva.Rect {\n return this.element as Konva.Rect;\n }\n\n /**\n * 更新节点数据\n */\n updateNode(node: Partial<INode<\"rectangle\">>): void {\n this.node = {\n ...this.node,\n ...node,\n props: {\n ...this.node.props,\n ...node.props,\n },\n style: {\n ...this.node.style,\n ...node.style,\n },\n };\n\n const rect = this.getElement();\n // 更新位置\n rect.x(this.node.props.x);\n rect.y(this.node.props.y);\n\n // 更新尺寸\n const width = Math.max(\n this.node.props.width ?? RECT.MIN_SIZE,\n RECT.MIN_SIZE\n );\n const height = Math.max(\n this.node.props.height ?? RECT.MIN_SIZE,\n RECT.MIN_SIZE\n );\n rect.width(width);\n rect.height(height);\n\n // 更新动画\n if (this.node.style.animated && !this.#animation) {\n this.#initAnimation();\n } else if (!this.node.style.animated && this.#animation) {\n this.#destroyAnimation();\n }\n }\n\n /**\n * 销毁\n */\n destroy(): void {\n this.#destroyAnimation();\n super.destroy();\n }\n\n /**\n * 初始化动画\n */\n #initAnimation(): void {\n const rect = this.getElement();\n const dash = rect.dash();\n if (!dash || dash.length === 0) return;\n\n const totalDashLength = getTotalDashLength(dash);\n this.#animation = createRectAnimation(rect, totalDashLength);\n\n if (this.#animation) {\n this.#animation.start();\n }\n }\n\n /**\n * 销毁动画\n */\n #destroyAnimation(): void {\n if (this.#animation) {\n this.#animation.stop();\n this.#animation = null;\n }\n }\n\n /**\n * 设置事件处理器\n */\n #setupEventHandlers(rect: Konva.Rect | undefined = undefined): void {\n const element = rect ?? (this.getElement() as Konva.Rect);\n // TransformStart\n element.on(\"transformstart\", () => {\n if (this.node.style.animated && this.#animation) {\n this.#animation.stop();\n }\n });\n\n // Transform\n element.on(\"transform\", (event: KonvaEventObject<Event>) => {\n const rect = event.target as Konva.Rect;\n const { width, height } = getRectSize(rect);\n\n const totalLength = calculatePerimeter(width, height, RECT.CORNER_RADIUS);\n const dash = getDashValue(\n totalLength,\n getSizeValue(this.node.style.size),\n this.node.style.line\n );\n\n rect.scale({ x: 1, y: 1 });\n rect.width(width);\n rect.height(height);\n rect.dash(dash.map((d) => d * this.core.getStageScale()));\n });\n\n // TransformEnd\n element.on(\"transformend\", (event: KonvaEventObject<Event>) => {\n const rect = event.target as Konva.Rect;\n const { width, height } = getRectSize(rect);\n const newProps = {\n ...this.node.props,\n x: rect.x(),\n y: rect.y(),\n width: width,\n height: height,\n rotation: rect.rotation(),\n };\n this.node.props = newProps;\n this.core._syncNodeFromElement(this.node.id, {\n props: newProps,\n });\n\n if (this.node.style.animated && this.#animation?.isRunning() === false) {\n this.#animation.start();\n }\n });\n\n element.on(\"dragend\", (event: KonvaEventObject<DragEvent>) => {\n const rect = event.target as Konva.Rect;\n\n const newProps = {\n ...this.node.props,\n x: rect.x(),\n y: rect.y(),\n };\n this.node.props = newProps;\n this.core._syncNodeFromElement(this.node.id, {\n props: newProps,\n });\n });\n }\n}\n","import Konva from \"konva\";\nimport { IMAGE } from \"../utils/const\";\nimport type { KonvaEventObject } from \"konva/lib/Node\";\nimport type { CanvasCore } from \"../core\";\nimport type { INode } from \"../type\";\nimport { NODE_NAME_FOR_SELECT } from \"../utils/const\";\nimport { BaseCanvasNode } from \"./base\";\n\n/**\n * ImageNode 类封装了 Konva.Image 的业务逻辑\n */\nexport class ImageNode extends BaseCanvasNode<INode<\"image\">> {\n constructor(core: CanvasCore, node: INode<\"image\">) {\n super(core, node);\n // 加载图片\n this.#loadImage();\n\n // 设置事件监听\n this.#setupEventHandlers(this.getElement());\n }\n\n protected createElement(): Konva.Image {\n // 创建一个空的 Image 元素(使用空画布作为占位符)\n const placeholder = document.createElement(\"canvas\");\n placeholder.width = 1;\n placeholder.height = 1;\n\n const img = new Konva.Image({\n id: this.node.id,\n x: this.node.props.x,\n y: this.node.props.y,\n name: NODE_NAME_FOR_SELECT,\n draggable: true,\n image: placeholder,\n });\n\n return img;\n }\n\n /**\n * 加载图片\n */\n #loadImage(): void {\n const imageUrl = this.node.meta.imageUrl;\n if (!imageUrl) {\n console.warn(\"Image URL is missing\");\n return;\n }\n\n const img = new window.Image();\n img.crossOrigin = \"anonymous\";\n img.src = imageUrl;\n\n img.onload = () => {\n this.getElement().image(img);\n\n // 计算尺寸\n const width = this.node.props.width ?? img.width;\n const height = this.node.props.height ?? img.height;\n\n this.getElement().width(Math.max(width, IMAGE.MIN_SIZE));\n this.getElement().height(Math.max(height, IMAGE.MIN_SIZE));\n };\n\n img.onerror = () => {\n console.error(\"Failed to load image:\", imageUrl);\n };\n }\n\n /**\n * 获取 Konva.Image 实例\n */\n getElement(): Konva.Image {\n return this.element as Konva.Image;\n }\n\n /**\n * 更新节点数据\n */\n updateNode(node: Partial<INode<\"image\">>): void {\n this.node = {\n ...this.node,\n ...node,\n props: {\n ...this.node.props,\n ...node.props,\n },\n style: {\n ...this.node.style,\n ...node.style,\n },\n meta: {\n ...this.node.meta,\n ...node.meta,\n },\n };\n\n const img = this.getElement();\n // 更新位置\n img.x(this.node.props.x);\n img.y(this.node.props.y);\n\n // 更新尺寸\n if (this.node.props.width && this.node.props.height) {\n const width = Math.max(this.node.props.width, IMAGE.MIN_SIZE);\n const height = Math.max(this.node.props.height, IMAGE.MIN_SIZE);\n img.width(width);\n img.height(height);\n }\n\n // 更新旋转\n if (this.node.props.rotation !== undefined) {\n img.rotation(this.node.props.rotation);\n }\n\n // 如果图片 URL 改变,重新加载\n if (node.meta?.imageUrl && node.meta.imageUrl !== this.node.meta.imageUrl) {\n this.#loadImage();\n }\n }\n\n /**\n * 销毁\n */\n destroy(): void {\n super.destroy();\n }\n\n /**\n * 设置事件处理器\n */\n #setupEventHandlers(img: Konva.Image): void {\n // Transform\n img.on(\"transform\", (event: KonvaEventObject<Event>) => {\n const img = event.target as Konva.Image;\n const width = Math.max(IMAGE.MIN_SIZE, img.width() * img.scaleX());\n const height = Math.max(IMAGE.MIN_SIZE, img.height() * img.scaleY());\n\n img.scale({ x: 1, y: 1 });\n img.width(width);\n img.height(height);\n\n // 同步更新关联的 image-marker 节点\n this.#syncImageMarkers();\n });\n\n // TransformEnd\n img.on(\"transformend\", (event: KonvaEventObject<Event>) => {\n const img = event.target as Konva.Image;\n const newProps = {\n ...this.node.props,\n x: img.x(),\n y: img.y(),\n width: img.width(),\n height: img.height(),\n rotation: img.rotation(),\n };\n this.node.props = newProps;\n this.core._syncNodeFromElement(this.node.id, {\n props: newProps,\n });\n\n // 同步更新关联的 image-marker 节点到状态\n this.#syncImageMarkersToState();\n });\n\n // DragMove\n img.on(\"dragmove\", () => {\n this.#syncImageMarkers();\n });\n\n // DragEnd\n img.on(\"dragend\", (event: KonvaEventObject<DragEvent>) => {\n const img = event.target as Konva.Image;\n const newProps = {\n ...this.node.props,\n x: img.x(),\n y: img.y(),\n };\n this.node.props = newProps;\n this.core._syncNodeFromElement(this.node.id, {\n props: newProps,\n });\n\n // 同步更新关联的 image-marker 节点到状态\n this.#syncImageMarkersToState();\n });\n }\n\n /**\n * 同步 image-marker 节点的位置(实时更新 Konva 元素)\n */\n #syncImageMarkers(): void {\n const img = this.getElement();\n const layer = img.getLayer();\n if (!layer) return;\n\n const imgX = img.x();\n const imgY = img.y();\n const imgWidth = img.width();\n const imgHeight = img.height();\n\n // 查找所有关联的 image-marker\n const imageMarkerElements = layer.find((node: Konva.Node) =>\n node.hasName(this.node.id)\n );\n\n const nodes = this.core.getState().nodes || [];\n\n imageMarkerElements.forEach((nodeElement: Konva.Node) => {\n const nodeData = nodes.find((n) => n.id === nodeElement.id());\n\n if (nodeData?.type === \"image-marker\" && nodeData.meta.relativePosition) {\n const { start, end } = nodeData.meta.relativePosition;\n\n // 根据百分比计算新的绝对位置\n const startX = imgX + (start.percentX / 100) * imgWidth;\n const startY = imgY + (start.percentY / 100) * imgHeight;\n const endX = imgX + (end.percentX / 100) * imgWidth;\n const endY = imgY + (end.percentY / 100) * imgHeight;\n\n // 计算标注的新位置和尺寸\n const newX = Math.min(startX, endX);\n const newY = Math.min(startY, endY);\n const newWidth = Math.abs(endX - startX);\n const newHeight = Math.abs(endY - startY);\n\n // 更新 Group 的位置和尺寸\n nodeElement.position({ x: newX, y: newY });\n nodeElement.setAttrs({ width: newWidth, height: newHeight });\n\n // 更新 Group 内部的子元素\n const children = (nodeElement as Konva.Group).getChildren();\n children.forEach((child) => {\n if (child.getClassName() === \"Rect\") {\n child.setAttrs({ width: newWidth, height: newHeight });\n } else if (child.getClassName() === \"Group\") {\n child.setAttrs({ x: newWidth, y: newHeight });\n }\n });\n }\n });\n }\n\n /**\n * 同步 image-marker 节点到状态\n */\n #syncImageMarkersToState(): void {\n const img = this.getElement();\n const layer = img.getLayer();\n if (!layer) return;\n\n const imageMarkerElements = layer.find((node: Konva.Node) =>\n node.hasName(this.node.id)\n );\n\n imageMarkerElements.forEach((nodeElement: Konva.Node) => {\n this.core._syncNodeFromElement(nodeElement.id(), {\n props: {\n x: nodeElement.x(),\n y: nodeElement.y(),\n width: nodeElement.width(),\n height: nodeElement.height(),\n },\n });\n });\n }\n}\n","import Konva from \"konva\";\nimport { RECT } from \"../utils/const\";\nimport type { CanvasCore } from \"../core\";\nimport type { INode } from \"../type\";\nimport { BaseCanvasNode } from \"./base\";\n\n/**\n * ImageMarkerNode 类封装了 Image Marker 的业务逻辑\n * Image Marker 是图片上的标注,使用 Group 包含 Rect 和 Circle+Text\n */\nexport class ImageMarkerNode extends BaseCanvasNode<INode<\"image-marker\">> {\n #rect: Konva.Rect;\n #markerGroup: Konva.Group;\n #circle: Konva.Circle;\n #text: Konva.Text;\n\n constructor(core: CanvasCore, node: INode<\"image-marker\">) {\n super(core, node);\n\n const group = this.getElement();\n this.#rect = group.findOne<Konva.Rect>(\".rect\")!;\n this.#markerGroup = group.findOne<Konva.Group>(\".marker-group\")!;\n this.#circle = this.#markerGroup.findOne<Konva.Circle>(\"Circle\")!;\n this.#text = this.#markerGroup.findOne<Konva.Text>(\"Text\")!;\n\n // 设置事件监听\n this.#setupEventHandlers();\n }\n\n protected createElement(): Konva.Group {\n // 计算尺寸\n const width = Math.max(\n this.node.props.width ?? RECT.MIN_SIZE,\n RECT.MIN_SIZE\n );\n const height = Math.max(\n this.node.props.height ?? RECT.MIN_SIZE,\n RECT.MIN_SIZE\n );\n\n // 创建主 Group\n const group = new Konva.Group({\n id: this.node.id,\n name: `static ${this.node.meta.parent}`,\n x: this.node.props.x,\n y: this.node.props.y,\n width,\n height,\n });\n\n // 创建矩形框\n const rect = new Konva.Rect({\n name: \"rect\",\n x: 0,\n y: 0,\n width,\n height,\n stroke: this.node.style.color,\n strokeWidth: 2,\n dash: [5, 5],\n fill: \"transparent\",\n cornerRadius: RECT.CORNER_RADIUS,\n });\n\n // 创建标记点 Group(圆圈 + 数字)\n const markerGroup = new Konva.Group({\n name: \"marker-group\",\n x: width,\n y: height,\n });\n\n const stageScale = this.core.getStageScale();\n const radius = 16 / stageScale;\n\n const circle = new Konva.Circle({\n radius,\n fill: \"red\",\n stroke: \"black\",\n strokeWidth: 2,\n });\n\n const text = new Konva.Text({\n x: -radius,\n y: -radius,\n width: radius * 2,\n height: radius * 2,\n text: String(this.node.meta.markerNumber || \"\"),\n align: \"center\",\n verticalAlign: \"middle\",\n fontSize: 16,\n fill: \"white\",\n });\n\n // 组装结构\n markerGroup.add(circle);\n markerGroup.add(text);\n group.add(rect);\n group.add(markerGroup);\n\n return group;\n }\n\n /**\n * 获取 Konva.Group 实例\n */\n getElement(): Konva.Group {\n return this.element as Konva.Group;\n }\n\n /**\n * 更新节点数据\n */\n updateNode(node: Partial<INode<\"image-marker\">>): void {\n this.node = {\n ...this.node,\n ...node,\n props: {\n ...this.node.props,\n ...node.props,\n },\n style: {\n ...this.node.style,\n ...node.style,\n },\n meta: {\n ...this.node.meta,\n ...node.meta,\n },\n };\n\n const group = this.getElement();\n // 更新位置\n group.x(this.node.props.x);\n group.y(this.node.props.y);\n\n // 更新尺寸\n const width = Math.max(\n this.node.props.width ?? RECT.MIN_SIZE,\n RECT.MIN_SIZE\n );\n const height = Math.max(\n this.node.props.height ?? RECT.MIN_SIZE,\n RECT.MIN_SIZE\n );\n\n group.width(width);\n group.height(height);\n this.#rect.width(width);\n this.#rect.height(height);\n this.#markerGroup.x(width);\n this.#markerGroup.y(height);\n\n // 更新样式\n if (node.style?.color) {\n this.#rect.stroke(node.style.color);\n }\n\n // 更新标记数字\n if (node.meta?.markerNumber !== undefined) {\n this.#text.text(String(node.meta.markerNumber));\n }\n }\n\n /**\n * 销毁\n */\n destroy(): void {\n super.destroy();\n }\n\n /**\n * 更新焦点状态(hover 或 selected)\n */\n setFocusState(isFocus: boolean): void {\n const strokeWidth = isFocus ? 3 : 2;\n const scale = isFocus ? 1.2 : 1;\n\n this.#rect.strokeWidth(strokeWidth);\n this.#circle.strokeWidth(strokeWidth);\n this.#markerGroup.scaleX(scale);\n this.#markerGroup.scaleY(scale);\n }\n\n /**\n * 设置事件处理器\n */\n #setupEventHandlers(): void {\n // 标记点的交互事件\n this.#markerGroup.on(\"pointerover\", () => {\n this.setFocusState(true);\n this.core.setCursor(\"pointer\");\n });\n\n this.#markerGroup.on(\"pointerout\", () => {\n const selectedIds = this.core.getState().selectedNodeIds || [];\n const isSelected = selectedIds.includes(this.node.id);\n this.setFocusState(isSelected);\n this.core.resetCursor();\n });\n\n this.#markerGroup.on(\"pointerdown\", () => {\n this.core.selectNode(this.node.id);\n });\n }\n}\n","import type { ICanvasNode, INode, NodeType } from \"../type\";\nimport { RectNode } from \"./rect\";\nimport { ImageNode } from \"./image\";\nimport { ImageMarkerNode } from \"./image-marker\";\nimport type { CanvasCore } from \"../core\";\n\nexport function createCanvasNodeByType(\n core: CanvasCore,\n type: NodeType,\n config: INode\n): ICanvasNode | null {\n switch (type) {\n case \"rectangle\":\n return new RectNode(core, config as INode<\"rectangle\">);\n case \"image\":\n return new ImageNode(core, config as INode<\"image\">);\n case \"image-marker\":\n return new ImageMarkerNode(core, config as INode<\"image-marker\">);\n default:\n return null;\n }\n}\n","import type { INode, NodeType } from \"../type\";\nimport { v4 as uuid } from \"uuid\";\nimport { RECT } from \"./const\";\n\nexport const createNodeByType = <T extends NodeType>(\n type: T,\n position: { x: number; y: number },\n style?: INode[\"style\"],\n meta?: Partial<INode[\"meta\"]>\n): INode<T> => {\n const baseNode = {\n type,\n id: uuid(),\n text: null,\n style: style ?? {\n opacity: 1,\n line: \"solid\",\n color: \"black\",\n size: \"medium\",\n animated: false,\n },\n props: {\n x: position.x,\n y: position.y,\n rotation: 0,\n visible: true,\n },\n meta: meta ?? {},\n };\n\n // image-marker 使用特殊的默认样式\n if (type === \"image-marker\") {\n return {\n ...baseNode,\n style: {\n ...baseNode.style,\n color: \"#ff0000\",\n line: \"dashed\",\n },\n } as INode<T>;\n }\n\n return baseNode;\n};\n\nexport function updateNodeByType<T extends NodeType>(\n node: INode<T>,\n position: { x: number; y: number },\n bounds?: { x: number; y: number; width: number; height: number }\n): INode<T> {\n let finalPosition = position;\n\n // 如果是 image-marker 且提供了边界,限制在边界内\n if (node.type === \"image-marker\" && bounds) {\n finalPosition = {\n x: Math.max(bounds.x, Math.min(bounds.x + bounds.width, position.x)),\n y: Math.max(bounds.y, Math.min(bounds.y + bounds.height, position.y)),\n };\n }\n\n const [p1, p2] = normalizePoints(\n { x: node.props.x, y: node.props.y },\n finalPosition\n );\n\n if (node.type === \"rectangle\" || node.type === \"image-marker\") {\n return {\n ...node,\n props: {\n ...node.props,\n x: p1.x,\n y: p1.y,\n width: Math.max(p2.x - p1.x, RECT.MIN_SIZE),\n height: Math.max(p2.y - p1.y, RECT.MIN_SIZE),\n },\n };\n }\n return node;\n}\n\nexport function normalizePoints(\n p1: { x: number; y: number },\n p2: { x: number; y: number }\n): { x: number; y: number }[] {\n let p1x = p1.x,\n p1y = p1.y,\n p2x = p2.x,\n p2y = p2.y,\n d;\n\n if (p1x > p2x) {\n d = Math.abs(p1x - p2x);\n p1x = p2x;\n p2x = p1x + d;\n }\n\n if (p1y > p2y) {\n d = Math.abs(p1y - p2y);\n p1y = p2y;\n p2y = p1y + d;\n }\n\n return [\n { x: p1x, y: p1y },\n { x: p2x, y: p2y },\n ];\n}\n","import Konva from \"konva\";\nimport type {\n ICanvasNode,\n ICoreState,\n INode,\n NodeType,\n ToolType,\n} from \"./type\";\nimport { CanvasStage } from \"./stage\";\nimport { CanvasTransformer } from \"./transformer\";\nimport { CanvasState } from \"./state\";\nimport { createCanvasNodeByType } from \"./node/_factory\";\nimport { NODE_NAME_FOR_SELECT } from \"./utils/const\";\nimport { createNodeByType, updateNodeByType } from \"./utils/draft\";\nimport { v4 as uuid } from \"uuid\";\n\nexport class CanvasCore extends CanvasState {\n #canvasStage: CanvasStage;\n #mainLayer: Konva.Layer;\n #canvasTransformer: CanvasTransformer;\n #draftNode: ICanvasNode | null = null;\n\n constructor(el: HTMLDivElement) {\n // 调用父类构造函数,初始化状态\n super({\n viewport: {\n x: 0,\n y: 0,\n width: el.clientWidth,\n height: el.clientHeight,\n scale: 1,\n },\n toolType: \"select\",\n nodes: [],\n });\n\n // 使用 CanvasStage 替代直接创建 Konva.Stage\n this.#canvasStage = new CanvasStage(this, {\n container: el,\n width: el.clientWidth,\n height: el.clientHeight,\n draggable: false,\n className: \"touch-none\",\n });\n\n this.#mainLayer = new Konva.Layer();\n this.#canvasTransformer = new CanvasTransformer(this);\n this.#canvasStage.getStage().add(this.#mainLayer);\n this.#mainLayer.add(this.#canvasTransformer.getTransformer());\n\n // 设置初始视口状态\n this.updateViewport(this.getState().viewport, false);\n }\n\n /**\n * 获取 CanvasStage 实例\n */\n getCanvasStage(): CanvasStage {\n return this.#canvasStage;\n }\n\n /**\n * 获取 CanvasTransformer 实例\n */\n getCanvasTransformer(): CanvasTransformer {\n return this.#canvasTransformer;\n }\n\n /**\n * 发射事件(供内部类使用)\n */\n emitEvent<K extends keyof import(\"./state\").StateEvents>(\n event: K,\n data: import(\"./state\").StateEvents[K]\n ): void {\n this.emit(event, data);\n }\n\n /**\n * 获取 Konva.Stage 实例\n */\n getStage(): Konva.Stage {\n return this.#canvasStage.getStage();\n }\n\n /**\n * 获取 Stage 容器元素\n */\n getContainer(): HTMLDivElement {\n return this.#canvasStage.getStage().container();\n }\n\n /**\n * 获取主图层\n */\n getMainLayer(): Konva.Layer {\n return this.#mainLayer;\n }\n\n /**\n * 获取当前工具类型\n */\n getToolType(): ToolType {\n return this.getState().toolType;\n }\n\n /**\n * 设置当前工具类型(内部使用)\n */\n setToolType(type: ToolType): void {\n this.selectNode(); // 取消选择所有节点\n\n this._updateState(\n {\n toolType: type,\n },\n false\n );\n\n // emit toolType 变化事件\n this.emit(\"toolType:change\", type);\n\n if (type === \"hand\") {\n this.#canvasStage.setDraggable(true);\n this.#canvasStage.setCursor(\"grab\");\n } else {\n this.#canvasStage.setDraggable(false);\n this.#canvasStage.resetCursor();\n }\n }\n\n /**\n * 设置是否可拖拽(内部使用)\n */\n protected setDraggable(draggable: boolean): void {\n this.#canvasStage.setDraggable(draggable);\n }\n\n /**\n * 设置光标\n * @internal 仅供内部使用\n */\n setCursor(cursor: string): void {\n this.#canvasStage.setCursor(cursor);\n }\n\n /**\n * 重置光标\n * @internal 仅供内部使用\n */\n resetCursor(): void {\n this.#canvasStage.resetCursor();\n }\n\n /**\n * 获取当前 Stage 缩放比例\n */\n getStageScale(): number {\n return this.#canvasStage.getStage().scaleX();\n }\n\n /**\n * 更新视口位置\n * @internal 仅供内部使用,外部请使用 CanvasApi\n */\n updateViewport(\n viewport: Partial<ICoreState[\"viewport\"]>,\n addToHistory = false\n ): void {\n this.#canvasStage.setViewport(viewport);\n\n const newViewport = {\n ...this.getState().viewport,\n ...viewport,\n };\n\n this._updateState(\n {\n viewport: newViewport,\n },\n addToHistory\n );\n\n // emit viewport 变化事件\n this.emit(\"viewport:change\", newViewport);\n\n // 计算并 emit transformer 位置 (由 transformer 内部处理)\n this.#canvasTransformer.emitPositionChange();\n }\n\n protected createNodes(nodes: INode[]): void {\n const canvasNodes = nodes\n .map((node) => createCanvasNodeByType(this, node.type, node))\n .filter((node): node is NonNullable<typeof node> => node !== null);\n\n canvasNodes.forEach((node) => {\n this.#mainLayer.add(node.getElement());\n });\n\n const newNodes = [...(this.getState().nodes || []), ...nodes];\n this._updateState(\n {\n nodes: newNodes,\n },\n true\n );\n }\n\n /**\n * 创建图片标注节点(内部使用)\n */\n protected createImageMarkerNode(\n parentImageId: string,\n startPosition: { x: number; y: number },\n endPosition: { x: number; y: number },\n imageBounds: { x: number; y: number; width: number; height: number }\n ): void {\n // 计算下一个标注编号\n const nodes = this.getState().nodes || [];\n let maxMarkerNumber = 0;\n nodes.forEach((node) => {\n if (\n node.type === \"image-marker\" &&\n node.meta.parent === parentImageId &&\n typeof node.meta.markerNumber === \"number\"\n ) {\n maxMarkerNumber = Math.max(maxMarkerNumber, node.meta.markerNumber);\n }\n });\n\n // 计算相对位置百分比\n const startPercentX =\n ((startPosition.x - imageBounds.x) / imageBounds.width) * 100;\n const startPercentY =\n ((startPosition.y - imageBounds.y) / imageBounds.height) * 100;\n const endPercentX =\n ((endPosition.x - imageBounds.x) / imageBounds.width) * 100;\n const endPercentY =\n ((endPosition.y - imageBounds.y) / imageBounds.height) * 100;\n\n // 计算标注的位置和尺寸\n const x = Math.min(startPosition.x, endPosition.x);\n const y = Math.min(startPosition.y, endPosition.y);\n const width = Math.abs(endPosition.x - startPosition.x);\n const height = Math.abs(endPosition.y - startPosition.y);\n\n const markerNode: INode<\"image-marker\"> = {\n id: uuid(),\n type: \"image-marker\",\n props: {\n x,\n y,\n width,\n height,\n rotation: 0,\n visible: true,\n },\n style: {\n color: \"#ff0000\",\n line: \"dashed\",\n size: \"medium\",\n opacity: 1,\n },\n meta: {\n parent: parentImageId,\n markerNumber: maxMarkerNumber + 1,\n relativePosition: {\n start: {\n percentX: Math.max(0, Math.min(100, startPercentX)),\n percentY: Math.max(0, Math.min(100, startPercentY)),\n },\n end: {\n percentX: Math.max(0, Math.min(100, endPercentX)),\n percentY: Math.max(0, Math.min(100, endPercentY)),\n },\n },\n },\n };\n\n this.createNodes([markerNode]);\n }\n\n /**\n * 在指定位置查找图片节点\n * @internal 仅供内部使用\n */\n findImageAtPosition(position: { x: number; y: number }): Konva.Image | null {\n const stage = this.#canvasStage.getStage();\n\n // 临时开启所有图片元素的 listening 状态\n const imageShapes = stage.find(\n (node: Konva.Node) => node.getClassName() === \"Image\"\n );\n const originalListeningStates = imageShapes.map((shape) =>\n shape.listening()\n );\n imageShapes.forEach((shape) => shape.listening(true));\n\n try {\n const shapes = stage.getAllIntersections(position);\n\n // 找到最上层的图片\n const imageShapesAtPos = shapes.filter(\n (shape) => shape.getClassName() === \"Image\"\n );\n if (imageShapesAtPos.length === 0) return null;\n\n return imageShapesAtPos[imageShapesAtPos.length - 1] as Konva.Image;\n } finally {\n // 恢复原始的 listening 状态\n imageShapes.forEach((shape, index) => {\n shape.listening(originalListeningStates[index]);\n });\n }\n }\n\n /**\n * @internal 仅供内部使用\n */\n createDraftNode(\n type: NodeType,\n position: { x: number; y: number },\n meta?: {\n parent?: string;\n bounds?: { x: number; y: number; width: number; height: number };\n startPosition?: { x: number; y: number };\n }\n ): void {\n if (this.#draftNode) {\n this.#draftNode.destroy();\n }\n\n const node = createNodeByType(type, position, undefined, meta);\n\n this.#draftNode = createCanvasNodeByType(this, type, node);\n\n console.log(this.#draftNode);\n if (!this.#draftNode) return;\n this.#mainLayer.add(this.#draftNode.getElement());\n }\n\n /**\n * @internal 仅供内部使用\n */\n updateDraftNode(\n position: { x: number; y: number },\n bounds?: { x: number; y: number; width: number; height: number }\n ): void {\n if (!this.#draftNode) return;\n const node = this.#draftNode.getNode();\n const updatedNode = updateNodeByType(node, position, bounds);\n this.#draftNode.updateNode(updatedNode);\n }\n\n /**\n * @internal 仅供内部使用\n */\n finalizeDraftNode(): void {\n if (!this.#draftNode) return;\n const id = uuid();\n\n const draftNode = this.#draftNode.getNode();\n\n // 处理 image-marker 的特殊逻辑\n if (draftNode.type === \"image-marker\" && draftNode.meta.parent) {\n const bounds = draftNode.meta.bounds as {\n x: number;\n y: number;\n width: number;\n height: number;\n };\n const startPosition = draftNode.meta.startPosition as {\n x: number;\n y: number;\n };\n const endPosition = {\n x: draftNode.props.x + (draftNode.props.width || 0),\n y: draftNode.props.y + (draftNode.props.height || 0),\n };\n\n // 计算下一个标注编号\n const nodes = this.getState().nodes || [];\n let maxMarkerNumber = 0;\n nodes.forEach((node) => {\n if (\n node.type === \"image-marker\" &&\n node.meta.parent === draftNode.meta.parent &&\n typeof node.meta.markerNumber === \"number\"\n ) {\n maxMarkerNumber = Math.max(maxMarkerNumber, node.meta.markerNumber);\n }\n });\n\n // 计算相对位置百分比\n const startPercentX = ((startPosition.x - bounds.x) / bounds.width) * 100;\n const startPercentY =\n ((startPosition.y - bounds.y) / bounds.height) * 100;\n const endPercentX = ((endPosition.x - bounds.x) / bounds.width) * 100;\n const endPercentY = ((endPosition.y - bounds.y) / bounds.height) * 100;\n\n const node: INode<\"image-marker\"> = {\n ...draftNode,\n props: {\n ...draftNode.props,\n },\n style: {\n ...draftNode.style,\n },\n meta: {\n parent: draftNode.meta.parent,\n markerNumber: maxMarkerNumber + 1,\n relativePosition: {\n start: {\n percentX: Math.max(0, Math.min(100, startPercentX)),\n percentY: Math.max(0, Math.min(100, startPercentY)),\n },\n end: {\n percentX: Math.max(0, Math.min(100, endPercentX)),\n percentY: Math.max(0, Math.min(100, endPercentY)),\n },\n },\n },\n id,\n type: \"image-marker\",\n };\n\n this.createNodes([node]);\n this.#draftNode.destroy();\n this.#draftNode = null;\n this.setToolType(\"select\");\n return;\n }\n\n const node: INode = {\n ...draftNode,\n props: {\n ...draftNode.props,\n },\n style: {\n ...draftNode.style,\n },\n meta: {\n ...draftNode.meta,\n },\n id,\n };\n\n this.createNodes([node]);\n this.#draftNode.destroy();\n this.#draftNode = null;\n this.setToolType(\"select\");\n }\n\n /**\n * 选择节点\n * @internal 仅供内部使用,外部请使用 CanvasApi\n */\n selectNode(nodeId?: string, multiSelect: boolean = false): void {\n const curSelectedNodeIds = this.getState().selectedNodeIds ?? [];\n\n if (curSelectedNodeIds.length === 0 && !nodeId) {\n return;\n }\n\n if (!nodeId) {\n this.#canvasTransformer.clearNodes();\n this._updateState(\n {\n selectedNodeIds: [],\n },\n false\n );\n return;\n }\n\n let selectedNodeIds: string[] = [];\n if (multiSelect) {\n selectedNodeIds = curSelectedNodeIds.length\n ? [...curSelectedNodeIds, nodeId]\n : [nodeId];\n } else {\n selectedNodeIds = [nodeId];\n }\n\n const nodes = this.getStage()\n .find(`.${NODE_NAME_FOR_SELECT}`)\n .filter((node) => {\n const id = node.id();\n return selectedNodeIds.includes(id);\n });\n\n this.#canvasTransformer.setNodes(nodes);\n\n this._updateState(\n {\n selectedNodeIds,\n },\n false\n );\n }\n\n /**\n * 销毁 canvas\n */\n dispose(): void {\n this.getCanvasTransformer().destroy();\n this.getMainLayer().destroy();\n this.getCanvasStage().destroy();\n this._dispose();\n }\n\n /**\n * 从元素同步节点数据(供节点类内部使用)\n */\n _syncNodeFromElement(nodeId: string, updates: Partial<INode>): void {\n const nodes = this.getState().nodes || [];\n const nodeIndex = nodes.findIndex((n) => n.id === nodeId);\n\n if (nodeIndex === -1) return;\n\n const updatedNode = {\n ...nodes[nodeIndex],\n ...updates,\n props: {\n ...nodes[nodeIndex].props,\n ...updates.props,\n },\n style: {\n ...nodes[nodeIndex].style,\n ...updates.style,\n },\n meta: {\n ...nodes[nodeIndex].meta,\n ...updates.meta,\n },\n };\n\n const newNodes = [...nodes];\n newNodes[nodeIndex] = updatedNode;\n\n this._updateState(\n {\n nodes: newNodes,\n },\n true\n );\n }\n\n /**\n * 实现父类的状态同步方法\n * 当 undo/redo 时被调用\n */\n protected _syncState(state: ICoreState): void {\n this.#canvasStage.setViewport({\n x: state.viewport.x,\n y: state.viewport.y,\n scale: state.viewport.scale,\n width: state.viewport.width,\n height: state.viewport.height,\n });\n }\n}\n","import type { ICoreState, ToolType, INode } from \"./type\";\nimport { CanvasCore } from \"./core\";\nimport { v4 as uuid } from \"uuid\";\nimport { NODE_NAME_FOR_SELECT } from \"./utils/const\";\n\n/**\n * CanvasApi 是面向外部使用的公开 API 类\n * 继承自 CanvasCore,只暴露必要的公开方法\n */\nexport class CanvasApi extends CanvasCore {\n /**\n * 获取所有可用的工具类型\n */\n getAvailableTools(): ToolType[] {\n return [\"select\", \"hand\", \"rectangle\", \"image-marker\"];\n }\n\n /**\n * 设置当前工具类型\n */\n override setToolType(type: ToolType): void {\n super.setToolType(type);\n }\n\n /**\n * 手动创建多个节点\n * 如果你不知道自己在干什么,请使用更高层的封装方法,如 createImageNode\n */\n public override createNodes(nodes: INode[]): void {\n super.createNodes(nodes);\n }\n\n /**\n * 更新视口位置\n */\n updateViewport(\n viewport: Partial<ICoreState[\"viewport\"]>,\n addToHistory = false\n ): void {\n super.updateViewport(viewport, addToHistory);\n }\n\n /**\n * 创建图片节点\n */\n createImageNode(imageUrl: string, position?: { x: number; y: number }): void {\n const pos = position ?? { x: 100, y: 100 };\n\n const imageNode: INode<\"image\"> = {\n id: uuid(),\n type: \"image\",\n props: {\n x: pos.x,\n y: pos.y,\n width: undefined,\n height: undefined,\n rotation: 0,\n visible: true,\n },\n style: {\n color: \"#000000\",\n line: \"solid\",\n size: \"medium\",\n opacity: 1,\n },\n meta: {\n imageUrl,\n },\n };\n\n this.createNodes([imageNode]);\n }\n\n /**\n * 导出全部图形为图片\n * @param options - 导出配置\n * @returns DataURL 格式的图片数据\n */\n exportAsImage(options?: {\n pixelRatio?: number;\n mimeType?: string;\n quality?: number;\n }): string {\n const stage = this.getStage();\n const transformer = this.getCanvasTransformer().getTransformer();\n const transformerVisible = transformer.visible();\n transformer.visible(false);\n\n try {\n return stage.toDataURL({\n pixelRatio: options?.pixelRatio ?? 2,\n mimeType: options?.mimeType ?? \"image/png\",\n quality: options?.quality ?? 1,\n });\n } finally {\n transformer.visible(transformerVisible);\n }\n }\n\n /**\n * 导出当前选区为图片\n * @param options - 导出配置\n * @returns DataURL 格式的图片数据,如果没有选区则返回 null\n */\n exportSelectionAsImage(options?: {\n pixelRatio?: number;\n mimeType?: string;\n quality?: number;\n padding?: number;\n }): string | null {\n const position = this.getCanvasTransformer().getPosition();\n if (!position) {\n console.warn(\"No selection to export\");\n return null;\n }\n\n const stage = this.getStage();\n const padding = options?.padding ?? 0;\n const transformer = this.getCanvasTransformer().getTransformer();\n const transformerVisible = transformer.visible();\n transformer.visible(false);\n\n try {\n return stage.toDataURL({\n x: position.x - padding,\n y: position.y - padding,\n width: position.width + padding * 2,\n height: position.height + padding * 2,\n pixelRatio: options?.pixelRatio ?? 1,\n mimeType: options?.mimeType ?? \"image/png\",\n quality: options?.quality ?? 1,\n });\n } finally {\n transformer.visible(transformerVisible);\n }\n }\n\n /**\n * 删除当前选中的节点\n * 如果删除的是 image 节点,会同步删除所有关联的 image-marker\n */\n deleteSelectedNodes(): void {\n const selectedNodeIds = this.getState().selectedNodeIds || [];\n if (selectedNodeIds.length === 0) return;\n this.deleteNodes(selectedNodeIds);\n }\n\n /**\n * 删除指定的节点\n * 如果删除的是 image 节点,会同步删除所有关联的 image-marker\n * @param nodeIds - 要删除的节点 ID 数组\n */\n deleteNodes(nodeIds: string[]): void {\n if (nodeIds.length === 0) return;\n\n const nodes = this.getState().nodes || [];\n const idsToDelete = new Set(nodeIds);\n\n // 查找所有需要删除的节点(包括 image 关联的 image-marker)\n nodeIds.forEach((id) => {\n const node = nodes.find((n) => n.id === id);\n if (node?.type === \"image\") {\n nodes.forEach((n) => {\n if (n.type === \"image-marker\" && n.meta.parent === id) {\n idsToDelete.add(n.id);\n }\n });\n }\n });\n\n // 从 stage 中移除元素\n idsToDelete.forEach((id) => {\n const shape = this.getStage().findOne(`#${id}`);\n if (shape) {\n shape.destroy();\n }\n });\n\n // 从状态中移除节点\n const newNodes = nodes.filter((n) => !idsToDelete.has(n.id));\n\n // 清除选区\n this.getCanvasTransformer().clearNodes();\n\n this._updateState(\n {\n nodes: newNodes,\n selectedNodeIds: [],\n },\n true\n );\n }\n\n /**\n * 滚动到内容区域\n * - 如果提供了 nodeIds,将指定的节点居中显示\n * - 如果没有提供 nodeIds 但有选中的节点,将选中节点居中显示\n * - 如果没有选中节点,将所有内容居中显示\n * @param options - 配置选项\n * @param options.padding - 内容周围的留白,默认 50px\n * @param options.scale - 是否自动调整缩放以适应内容,默认 false\n * @param options.nodeIds - 要滚动到的节点 ID 数组\n */\n scrollToContent(options?: {\n padding?: number;\n scale?: boolean;\n nodeIds?: string[];\n }): void {\n const nodes = this.getState().nodes || [];\n if (nodes.length === 0) return;\n\n const padding = options?.padding ?? 50;\n const shouldScale = options?.scale === true;\n const targetNodeIds = options?.nodeIds;\n\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n\n const mainLayer = this.getMainLayer();\n const selectedNodeIds = this.getState().selectedNodeIds || [];\n\n // 确定要显示的节点:优先使用 targetNodeIds,其次是选中的节点\n const hasTargetIds = targetNodeIds && targetNodeIds.length > 0;\n const hasSelection = !hasTargetIds && selectedNodeIds.length > 0;\n const idsToShow = hasTargetIds\n ? targetNodeIds\n : hasSelection\n ? selectedNodeIds\n : null;\n\n mainLayer.children.forEach((child) => {\n if (\n child.visible() &&\n child.getClassName() !== \"Transformer\" &&\n child.hasName(NODE_NAME_FOR_SELECT)\n ) {\n if (idsToShow) {\n const id = child.id();\n if (!idsToShow.includes(id)) return;\n }\n\n const attrs = child.getAttrs();\n const x = attrs.x || 0;\n const y = attrs.y || 0;\n const width = attrs.width || 0;\n const height = attrs.height || 0;\n const rotation = attrs.rotation || 0;\n\n if (rotation) {\n const box = child.getClientRect({ skipTransform: false });\n const stage = this.getStage();\n const currentScale = stage.scaleX();\n const currentX = stage.x();\n const currentY = stage.y();\n\n const worldMinX = (box.x - currentX) / currentScale;\n const worldMinY = (box.y - currentY) / currentScale;\n const worldMaxX = (box.x + box.width - currentX) / currentScale;\n const worldMaxY = (box.y + box.height - currentY) / currentScale;\n\n minX = Math.min(minX, worldMinX);\n minY = Math.min(minY, worldMinY);\n maxX = Math.max(maxX, worldMaxX);\n maxY = Math.max(maxY, worldMaxY);\n } else {\n minX = Math.min(minX, x);\n minY = Math.min(minY, y);\n maxX = Math.max(maxX, x + width);\n maxY = Math.max(maxY, y + height);\n }\n }\n });\n\n if (minX === Infinity || minY === Infinity) return;\n\n const contentWidth = maxX - minX;\n const contentHeight = maxY - minY;\n const contentCenterX = minX + contentWidth / 2;\n const contentCenterY = minY + contentHeight / 2;\n\n const viewport = this.getState().viewport;\n let newScale = viewport.scale;\n\n if (shouldScale) {\n const scaleX = (viewport.width - padding * 2) / contentWidth;\n const scaleY = (viewport.height - padding * 2) / contentHeight;\n newScale = Math.min(scaleX, scaleY, 1);\n }\n\n const x = viewport.width / 2 - contentCenterX * newScale;\n const y = viewport.height / 2 - contentCenterY * newScale;\n\n this.updateViewport({ x, y, scale: newScale }, true);\n }\n}\n","/**\n * Modulate a value between two ranges.\n *\n * @example\n *\n * ```ts\n * const A = modulate(0, [0, 1], [0, 100])\n * ```\n *\n * @param value - The interpolation value.\n * @param rangeA - From [low, high]\n * @param rangeB - To [low, high]\n * @param clamp - Whether to clamp the the result to [low, high]\n * @public\n */\nexport function modulate(\n value: number,\n rangeA: number[],\n rangeB: number[],\n clamp = false\n): number {\n const [fromLow, fromHigh] = rangeA;\n const [v0, v1] = rangeB;\n const result = v0 + ((value - fromLow) / (fromHigh - fromLow)) * (v1 - v0);\n\n return clamp\n ? v0 < v1\n ? Math.max(Math.min(result, v1), v0)\n : Math.max(Math.min(result, v0), v1)\n : result;\n}\n\nconst gridSteps = [\n {\n min: -1,\n mid: 0.15,\n step: 64,\n },\n {\n min: 0.05,\n mid: 0.375,\n step: 16,\n },\n {\n min: 0.15,\n mid: 1,\n step: 4,\n },\n {\n min: 0.7,\n mid: 2.5,\n step: 1,\n },\n];\n\ninterface GridBackgroundProps {\n viewportX: number;\n viewportY: number;\n scale: number;\n size?: number;\n showGrid?: boolean;\n}\n\nexport function GridBackground({\n viewportX,\n viewportY,\n scale,\n size = 20,\n showGrid = true,\n}: GridBackgroundProps) {\n const x = viewportX / scale;\n const y = viewportY / scale;\n const z = scale;\n\n if (!showGrid) {\n return null;\n }\n\n return (\n <svg\n className=\"canvas-grid w-full h-full absolute top-0 left-0\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <defs>\n {gridSteps.map(({ min, mid, step }, i) => {\n const s = step * size * z;\n const xo = 0.5 + x * z;\n const yo = 0.5 + y * z;\n const gxo = xo > 0 ? xo % s : s + (xo % s);\n const gyo = yo > 0 ? yo % s : s + (yo % s);\n const opacity = z < mid ? modulate(z, [min, mid], [0, 1]) : 1;\n\n return (\n <pattern\n key={i}\n id={`grid_${step}`}\n width={s}\n height={s}\n patternUnits=\"userSpaceOnUse\"\n >\n <circle\n className=\"tl-grid-dot\"\n cx={gxo}\n cy={gyo}\n r={1}\n opacity={opacity}\n />\n </pattern>\n );\n })}\n </defs>\n {gridSteps.map(({ step }, i) => (\n <rect key={i} width=\"100%\" height=\"100%\" fill={`url(#grid_${step})`} />\n ))}\n </svg>\n );\n}\n","import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","import * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60\",\n outline:\n \"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost:\n \"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-9 px-4 py-2 has-[>svg]:px-3\",\n sm: \"h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5\",\n lg: \"h-10 rounded-md px-6 has-[>svg]:px-4\",\n icon: \"size-9\",\n \"icon-sm\": \"size-8\",\n \"icon-lg\": \"size-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n asChild = false,\n ...props\n}: React.ComponentProps<\"button\"> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean\n }) {\n const Comp = asChild ? Slot : \"button\"\n\n return (\n <Comp\n data-slot=\"button\"\n data-variant={variant}\n data-size={size}\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\n","import { Button } from \"@/components/ui/button\";\nimport { Minus, Plus } from \"lucide-react\";\nimport type { CanvasApi } from \"../core/api\";\nimport type { ICoreState } from \"../core/type\";\nimport { useEffect, useState } from \"react\";\n\ninterface ZoomPanelProps {\n api: CanvasApi;\n}\n\nexport function ZoomPanel({ api }: ZoomPanelProps) {\n const [viewport, setViewport] = useState(api.getState().viewport);\n useEffect(() => {\n api.on(\"viewport:change\", (newViewport: ICoreState[\"viewport\"]) => {\n setViewport(newViewport);\n });\n }, [setViewport, api]);\n const updateScale = (scale: number) => {\n const halfWidth = viewport.width / 2;\n const halfHeight = viewport.height / 2;\n const worldCenterX = (halfWidth - viewport.x) / viewport.scale;\n const worldCenterY = (halfHeight - viewport.y) / viewport.scale;\n const x = halfWidth - worldCenterX * scale;\n const y = halfHeight - worldCenterY * scale;\n api.updateViewport({ x, y, scale });\n };\n\n const handleZoomIn = () => {\n const scale = Math.min(viewport.scale * 1.2, 5);\n updateScale(scale);\n };\n\n const handleZoomOut = () => {\n const scale = Math.max(viewport.scale / 1.2, 0.1);\n updateScale(scale);\n };\n\n const handleReset = () => {\n updateScale(1);\n };\n\n const percent = Math.round(viewport.scale * 100);\n\n return (\n <div className=\"zoom-panel flex items-center gap-2\">\n <Button\n size={\"sm\"}\n variant=\"secondary\"\n onClick={handleZoomOut}\n title=\"缩小\"\n >\n <Minus />\n </Button>\n <Button\n size={\"sm\"}\n variant=\"secondary\"\n onClick={handleReset}\n title={`${percent}%`}\n className=\"min-w-16\"\n >\n {percent}%\n </Button>\n <Button\n size={\"sm\"}\n variant=\"secondary\"\n onClick={handleZoomIn}\n title=\"放大\"\n >\n <Plus />\n </Button>\n </div>\n );\n}\n","import { Button } from \"@/components/ui/button\";\nimport { Undo2, Redo2 } from \"lucide-react\";\nimport type { CanvasApi } from \"../core/api\";\nimport { useState, useEffect } from \"react\";\n\ninterface HistoryPanelProps {\n api: CanvasApi;\n}\n\nexport function HistoryPanel({ api }: HistoryPanelProps) {\n const [canUndo, setCanUndo] = useState(api.canUndo());\n const [canRedo, setCanRedo] = useState(api.canRedo());\n\n useEffect(() => {\n // 监听状态变化\n const handleStateChange = () => {\n setCanUndo(api.canUndo());\n setCanRedo(api.canRedo());\n };\n\n api.on(\"state:change\", handleStateChange);\n\n return () => {\n api.off(\"state:change\", handleStateChange);\n };\n }, [api]);\n\n return (\n <div className=\"history-panel flex items-center gap-2\">\n <Button\n size={\"sm\"}\n variant=\"secondary\"\n disabled={!canUndo}\n onClick={() => api.undo()}\n title=\"撤销\"\n >\n <Undo2 />\n </Button>\n <Button\n size={\"sm\"}\n variant=\"secondary\"\n disabled={!canRedo}\n onClick={() => api.redo()}\n title=\"重做\"\n >\n <Redo2 />\n </Button>\n </div>\n );\n}\n","import { useEffect, useRef, useState } from \"react\";\nimport { CanvasApi } from \"./core/api\";\nimport { GridBackground } from \"./jsx/GridBackground\";\nimport { ZoomPanel } from \"./jsx/ZoomPanel\";\nimport { HistoryPanel } from \"./jsx/HistoryPanel\";\n\ninterface PureCanvasProps {\n setApi?: (core: CanvasApi) => void;\n}\n\nexport function PureCanvas({ setApi }: PureCanvasProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [_api, _setApi] = useState<CanvasApi | null>(null);\n\n const [viewport, setViewport] = useState({ x: 0, y: 0, scale: 1 });\n\n useEffect(() => {\n if (!containerRef.current) return;\n\n // 创建 Core 实例\n const core = new CanvasApi(containerRef.current);\n _setApi(core);\n setApi?.(core);\n\n // 设置事件处理器\n // core.subscribe((state) => {\n // console.log(\"Canvas state updated:\", state);\n // setViewport(state.viewport);\n // });\n\n core.on(\"viewport:change\", (newViewport) => {\n setViewport(newViewport);\n });\n\n core.on(\"transformer:positionChange\", (position) => {\n // 处理 Transformer 位置变化\n console.log(\"Transformer position changed:\", position);\n });\n\n // 清理\n return () => {\n core.dispose();\n };\n }, [setApi]);\n\n return (\n <div className=\"pure-canvas relative size-full\">\n <GridBackground\n viewportX={viewport.x}\n viewportY={viewport.y}\n scale={viewport.scale}\n />\n <div ref={containerRef} className=\"size-full\" />\n {_api && (\n <>\n <div className=\"history-panel-wrapper absolute bottom-4 left-4 z-10\">\n <HistoryPanel api={_api} />\n </div>\n <div className=\"zoom-panel-wrapper absolute bottom-4 right-4 z-10\">\n <ZoomPanel api={_api} />\n </div>\n </>\n )}\n </div>\n );\n}\n"],"names":["CanvasStage","core","config","__privateAdd","_CanvasStage_instances","_core","_stage","_viewport","_handleWheel","e","pointer","__privateGet","oldScale","mousePointTo","scaleBy","direction","steps","newScale","i","scale","newPos","deltaX","deltaY","_handlePointerDown","event","toolType","clickedOnEmpty","pointerPos","nodeId","imageShape","width","height","imageBounds","_handlePointerMove","_handlePointerUp","_handleDragStart","_handleDragMove","_handleDragEnd","__privateSet","Konva","__privateMethod","setupEventListeners_fn","viewport","newViewport","draggable","cursor","container","CanvasTransformer","_CanvasTransformer_instances","_transformer","_handleTransformStart","_handleTransform","_handleTransformEnd","box","nodes","position","CanvasState","initialState","__publicField","mitt","handler","data","previous","newPast","next","newFuture","partial","addToHistory","newState","_state","NODE_NAME_FOR_SELECT","RECT","IMAGE","calculatePerimeter","cornerRadius","getDashValue","shapeLength","strokeWidth","lineStyle","ratio","dashLength","dashGap","dashCount","getSizeValue","key","getTotalDashLength","dash","getRectSize","rect","BaseCanvasNode","node","isSelect","createRectAnimation","totalDashLength","anim","frame","dashOffset","RectNode","_RectNode_instances","_animation","initAnimation_fn","setupEventHandlers_fn","destroyAnimation_fn","element","totalLength","d","newProps","ImageNode","_ImageNode_instances","loadImage_fn","placeholder","img","imageUrl","syncImageMarkers_fn","syncImageMarkersToState_fn","layer","imgX","imgY","imgWidth","imgHeight","imageMarkerElements","nodeElement","nodeData","n","start","end","startX","startY","endX","endY","newX","newY","newWidth","newHeight","child","ImageMarkerNode","_ImageMarkerNode_instances","_rect","_markerGroup","_circle","_text","group","markerGroup","radius","circle","text","isFocus","isSelected","createCanvasNodeByType","type","createNodeByType","style","meta","baseNode","uuid","updateNodeByType","bounds","finalPosition","p1","p2","normalizePoints","p1x","p1y","p2x","p2y","CanvasCore","el","_canvasStage","_mainLayer","_canvasTransformer","_draftNode","newNodes","parentImageId","startPosition","endPosition","maxMarkerNumber","startPercentX","startPercentY","endPercentX","endPercentY","x","y","markerNode","stage","imageShapes","originalListeningStates","shape","imageShapesAtPos","index","updatedNode","id","draftNode","multiSelect","curSelectedNodeIds","selectedNodeIds","updates","nodeIndex","state","CanvasApi","pos","imageNode","options","transformer","transformerVisible","padding","nodeIds","idsToDelete","shouldScale","targetNodeIds","minX","minY","maxX","maxY","mainLayer","hasTargetIds","hasSelection","idsToShow","attrs","currentScale","currentX","currentY","worldMinX","worldMinY","worldMaxX","worldMaxY","contentWidth","contentHeight","contentCenterX","contentCenterY","scaleX","scaleY","modulate","value","rangeA","rangeB","clamp","fromLow","fromHigh","v0","v1","result","gridSteps","GridBackground","viewportX","viewportY","size","showGrid","z","jsxs","jsx","min","mid","step","s","xo","yo","gxo","gyo","opacity","cn","inputs","twMerge","clsx","buttonVariants","cva","Button","className","variant","asChild","props","Comp","Slot","ZoomPanel","api","setViewport","useState","useEffect","updateScale","halfWidth","halfHeight","worldCenterX","worldCenterY","handleZoomIn","handleZoomOut","handleReset","percent","Minus","Plus","HistoryPanel","canUndo","setCanUndo","canRedo","setCanRedo","handleStateChange","Undo2","Redo2","PureCanvas","setApi","containerRef","useRef","_api","_setApi","Fragment"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@8btc/whiteboard",
3
3
  "private": false,
4
- "version": "0.0.3",
4
+ "version": "0.0.5",
5
5
  "type": "module",
6
6
  "main": "./dist/index.umd.js",
7
7
  "module": "./dist/index.js",