dishui 0.0.64 → 0.0.65
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.
- package/dist/components/Badge/index.js +12 -9
- package/dist/components/Badge/index.js.map +1 -1
- package/dist/components/Button/index.js +43 -40
- package/dist/components/Button/index.js.map +1 -1
- package/dist/components/Card/index.d.ts +11 -0
- package/dist/components/Card/index.js +62 -37
- package/dist/components/Card/index.js.map +1 -1
- package/dist/components/Chart/Chart.js.map +1 -1
- package/dist/components/Checkbox/index.js +32 -30
- package/dist/components/Checkbox/index.js.map +1 -1
- package/dist/components/Demo/index.js.map +1 -1
- package/dist/components/EmptyState/index.d.ts +4 -1
- package/dist/components/EmptyState/index.js +3 -3
- package/dist/components/EmptyState/index.js.map +1 -1
- package/dist/components/FileUploader/DropZone.js.map +1 -1
- package/dist/components/FileUploader/FileItem.js.map +1 -1
- package/dist/components/FileUploader/FileUploader.js.map +1 -1
- package/dist/components/FileUploader/UploadQueue.js.map +1 -1
- package/dist/components/Input/index.js +30 -30
- package/dist/components/Input/index.js.map +1 -1
- package/dist/components/Label/index.js +41 -40
- package/dist/components/Label/index.js.map +1 -1
- package/dist/components/List/index.js +47 -32
- package/dist/components/List/index.js.map +1 -1
- package/dist/components/Markdown/Markdown.js +61 -57
- package/dist/components/Markdown/Markdown.js.map +1 -1
- package/dist/components/Markdown/markdownComponents.js +49 -49
- package/dist/components/Markdown/markdownComponents.js.map +1 -1
- package/dist/components/Modal/index.d.ts +7 -3
- package/dist/components/Modal/index.js +77 -65
- package/dist/components/Modal/index.js.map +1 -1
- package/dist/components/Page/index.d.ts +58 -0
- package/dist/components/Page/index.js +74 -0
- package/dist/components/Page/index.js.map +1 -0
- package/dist/components/PageHeader/index.js.map +1 -1
- package/dist/components/Select/index.js +0 -3
- package/dist/components/Select/index.js.map +1 -1
- package/dist/components/SidebarToggleButton/index.js.map +1 -1
- package/dist/components/StatCard/index.d.ts +3 -1
- package/dist/components/StatCard/index.js +39 -11
- package/dist/components/StatCard/index.js.map +1 -1
- package/dist/components/Table/index.js +103 -85
- package/dist/components/Table/index.js.map +1 -1
- package/dist/components/Tabs/index.d.ts +19 -5
- package/dist/components/Tabs/index.js +32 -13
- package/dist/components/Tabs/index.js.map +1 -1
- package/dist/components/Tree/Tree.js.map +1 -1
- package/dist/components/pro/ArticleContextMenu/index.js.map +1 -1
- package/dist/components/pro/ArticleControl/ArticleControl2.js.map +1 -1
- package/dist/components/pro/CodeEditor/editors/CodeEditor.js +141 -134
- package/dist/components/pro/CodeEditor/editors/CodeEditor.js.map +1 -1
- package/dist/components/pro/CodeEditor/editors/MarkdownEditor.js +81 -78
- package/dist/components/pro/CodeEditor/editors/MarkdownEditor.js.map +1 -1
- package/dist/components/pro/CodeEditor/panels/FootnotePanel.js.map +1 -1
- package/dist/components/pro/CodeEditor/panels/HistoryPanel.js.map +1 -1
- package/dist/components/pro/CodeEditor/panels/OutlinePanel.js.map +1 -1
- package/dist/components/pro/CodeEditor/panels/TableOfContentsPanel.js.map +1 -1
- package/dist/components/pro/CodeEditor/panels/VariablePanel.js.map +1 -1
- package/dist/components/pro/CodeEditor/themes.js +59 -59
- package/dist/components/pro/CodeEditor/themes.js.map +1 -1
- package/dist/components/pro/DataTable/DataTable.js +49 -48
- package/dist/components/pro/DataTable/DataTable.js.map +1 -1
- package/dist/components/pro/DataTable/Filters.js +42 -42
- package/dist/components/pro/DataTable/Filters.js.map +1 -1
- package/dist/components/pro/DataTable/PivotPanel.js.map +1 -1
- package/dist/components/pro/DataTable/PivotView.js +35 -32
- package/dist/components/pro/DataTable/PivotView.js.map +1 -1
- package/dist/components/pro/DataTable/components/BulkActions.js.map +1 -1
- package/dist/components/pro/DataTable/components/ColumnSelector.js.map +1 -1
- package/dist/components/pro/DataTable/components/FilterBar.js.map +1 -1
- package/dist/components/pro/DataTable/components/TableBody.js.map +1 -1
- package/dist/components/pro/DataTable/components/TableHeader.js.map +1 -1
- package/dist/components/pro/DataTable/components/TablePagination.js.map +1 -1
- package/dist/components/pro/DataTable/components/TableToolbar.js.map +1 -1
- package/dist/components/pro/DataTable/pivotExtension.js.map +1 -1
- package/dist/components/pro/DataTable/rowDetailExtension.js.map +1 -1
- package/dist/components/pro/DataTable/tanstack-table.js +37 -37
- package/dist/components/pro/DataTable/tanstack-table.js.map +1 -1
- package/dist/components/pro/FileExplorer/Breadcrumb.js +53 -53
- package/dist/components/pro/FileExplorer/Breadcrumb.js.map +1 -1
- package/dist/components/pro/FileExplorer/CreateDialog.js.map +1 -1
- package/dist/components/pro/FileExplorer/FileExplorer.js.map +1 -1
- package/dist/components/pro/FileExplorer/FileIcon.js +22 -22
- package/dist/components/pro/FileExplorer/FileIcon.js.map +1 -1
- package/dist/components/pro/FileExplorer/GridView.js.map +1 -1
- package/dist/components/pro/FileExplorer/ListView.js.map +1 -1
- package/dist/components/pro/FileExplorer/Toolbar.js.map +1 -1
- package/dist/components/pro/Flow/Flow.js +496 -494
- package/dist/components/pro/Flow/Flow.js.map +1 -1
- package/dist/components/pro/Flow/FlowCanvas.js +916 -917
- package/dist/components/pro/Flow/FlowCanvas.js.map +1 -1
- package/dist/components/pro/Flow/context/FlowUIContext.js.map +1 -1
- package/dist/components/pro/Flow/edges/EdgeRenderer.js +59 -59
- package/dist/components/pro/Flow/edges/EdgeRenderer.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useClipboard.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useDeleteSelection.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useEdgeMutations.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useLayoutActions.js +9 -11
- package/dist/components/pro/Flow/hooks/useLayoutActions.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useLineMutations.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useMindMap.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useNodeMutations.js.map +1 -1
- package/dist/components/pro/Flow/lines/FreehandTool.js +9 -9
- package/dist/components/pro/Flow/lines/FreehandTool.js.map +1 -1
- package/dist/components/pro/Flow/lines/LineRenderer.js +5 -5
- package/dist/components/pro/Flow/lines/LineRenderer.js.map +1 -1
- package/dist/components/pro/Flow/nodes/DataNodeView.js +113 -93
- package/dist/components/pro/Flow/nodes/DataNodeView.js.map +1 -1
- package/dist/components/pro/Flow/nodes/MediaContent.js.map +1 -1
- package/dist/components/pro/Flow/nodes/MediaOverlay.js.map +1 -1
- package/dist/components/pro/Flow/nodes/Model3DView.js +1 -1
- package/dist/components/pro/Flow/nodes/Model3DView.js.map +1 -1
- package/dist/components/pro/Flow/nodes/NodeRenderer.js +118 -118
- package/dist/components/pro/Flow/nodes/NodeRenderer.js.map +1 -1
- package/dist/components/pro/Flow/nodes/dataUtils.js.map +1 -1
- package/dist/components/pro/Flow/nodes/shapes.js +1 -3
- package/dist/components/pro/Flow/nodes/shapes.js.map +1 -1
- package/dist/components/pro/Flow/panels/AIPanel.js.map +1 -1
- package/dist/components/pro/Flow/panels/Breadcrumb.js.map +1 -1
- package/dist/components/pro/Flow/panels/ContextMenu.js.map +1 -1
- package/dist/components/pro/Flow/panels/DataInspectorSection.js.map +1 -1
- package/dist/components/pro/Flow/panels/ExpandableTextarea.js.map +1 -1
- package/dist/components/pro/Flow/panels/FlowPanelGroup.js.map +1 -1
- package/dist/components/pro/Flow/panels/FlowToolbar.js +97 -97
- package/dist/components/pro/Flow/panels/FlowToolbar.js.map +1 -1
- package/dist/components/pro/Flow/panels/InspectorPanel.js +57 -57
- package/dist/components/pro/Flow/panels/InspectorPanel.js.map +1 -1
- package/dist/components/pro/Flow/panels/OutlinePanel.js +26 -22
- package/dist/components/pro/Flow/panels/OutlinePanel.js.map +1 -1
- package/dist/components/pro/Flow/panels/PresentationMode.js +18 -16
- package/dist/components/pro/Flow/panels/PresentationMode.js.map +1 -1
- package/dist/components/pro/Flow/panels/ProjectTitle.js.map +1 -1
- package/dist/components/pro/Flow/panels/ShapePalette.js +109 -104
- package/dist/components/pro/Flow/panels/ShapePalette.js.map +1 -1
- package/dist/components/pro/Flow/panels/toolbarIcons.js.map +1 -1
- package/dist/components/pro/RichTextEditor/AIRewrite.js.map +1 -1
- package/dist/components/pro/RichTextEditor/BlockHandle.js.map +1 -1
- package/dist/components/pro/RichTextEditor/BubbleToolbar.js.map +1 -1
- package/dist/components/pro/RichTextEditor/CommentDialog.js.map +1 -1
- package/dist/components/pro/RichTextEditor/CommentPanel.js.map +1 -1
- package/dist/components/pro/RichTextEditor/CommentPopover.js.map +1 -1
- package/dist/components/pro/RichTextEditor/ContextMenu.js.map +1 -1
- package/dist/components/pro/RichTextEditor/RichTextEditor.js.map +1 -1
- package/dist/components/pro/RichTextEditor/SlashMenu.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/ColorPicker.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/FloatingDialogMenu.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/MarkdownTemplates.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/SelectDropdown.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/TableOpsMenu.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/CodeBlockView.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/FloatingDialog.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/MarkdownBlock.js.map +1 -1
- package/dist/contexts/AppContext.js.map +1 -1
- package/dist/dishui.css +1 -1
- package/dist/hooks/useTableColumns.js +7 -8
- package/dist/hooks/useTableColumns.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +227 -221
- package/dist/layouts/MainLayout.js +22 -22
- package/dist/layouts/MainLayout.js.map +1 -1
- package/dist/layouts/Navbar.js.map +1 -1
- package/dist/layouts/Sidebar.js +94 -73
- package/dist/layouts/Sidebar.js.map +1 -1
- package/dist/layouts/headbar/Headbar.js.map +1 -1
- package/dist/layouts/headbar/HeadbarLangSwitcher.js.map +1 -1
- package/dist/layouts/headbar/HeadbarSearch.js.map +1 -1
- package/dist/layouts/headbar/HeadbarThemeSwitcher.js +11 -11
- package/dist/layouts/headbar/HeadbarThemeSwitcher.js.map +1 -1
- package/dist/layouts/headbar/HeadbarTitle.js.map +1 -1
- package/dist/utils/i18n.js +10 -10
- package/dist/utils/i18n.js.map +1 -1
- package/dist/utils/menu.js.map +1 -1
- package/dist/utils/routerBuilder.js +17 -15
- package/dist/utils/routerBuilder.js.map +1 -1
- package/dist/utils/themes.js.map +1 -1
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMindMap.js","names":[],"sources":["../../../../../src/components/pro/Flow/hooks/useMindMap.ts"],"sourcesContent":["import { useCallback, useEffect } from 'react';\nimport { useFlowContext } from '../context/FlowContext';\nimport { useFlowUI } from '../context/FlowUIContext';\nimport { DEFAULT_EDGE_DATA, DEFAULT_NODE_DATA } from '../constants';\nimport { generateId } from '../nodes/nodeUtils';\nimport type { FlowCanvasData, FlowNode } from '../types';\n\nconst NODE_WIDTH = 150;\nconst NODE_HEIGHT = 52;\nconst LEVEL_GAP = 100;\nconst ROW_GAP = 26;\n\nfunction layoutMindMap(\n canvas: FlowCanvasData,\n rootId: string,\n fixed?: { id: string; position: { x: number; y: number } },\n): Map<string, { x: number; y: number }> {\n const nodes = canvas.nodes.filter(node => node.data.isMindMapNode);\n const nodeMap = new Map(nodes.map(node => [node.id, node]));\n const children = new Map<string, FlowNode[]>();\n for (const node of nodes) {\n const parentId = node.data.mindMapParentId;\n if (!parentId || !nodeMap.has(parentId)) continue;\n const list = children.get(parentId) ?? [];\n list.push(node);\n children.set(parentId, list);\n }\n\n const root = nodeMap.get(rootId);\n if (!root) return new Map();\n const positions = new Map<string, { x: number; y: number }>();\n let nextY = root.position.y;\n\n const place = (node: FlowNode, depth: number): number => {\n const kids = children.get(node.id) ?? [];\n let centerY: number;\n if (kids.length === 0) {\n centerY = nextY;\n nextY += NODE_HEIGHT + ROW_GAP;\n } else {\n const childYs = kids.map(child => place(child, depth + 1));\n centerY = (childYs[0] + childYs[childYs.length - 1]) / 2;\n }\n positions.set(node.id, {\n x: root.position.x + depth * (NODE_WIDTH + LEVEL_GAP),\n y: centerY,\n });\n return centerY;\n };\n\n place(root, 0);\n if (fixed) {\n const computed = positions.get(fixed.id);\n if (computed) {\n const dx = fixed.position.x - computed.x;\n const dy = fixed.position.y - computed.y;\n for (const [id, position] of positions) {\n positions.set(id, { x: position.x + dx, y: position.y + dy });\n }\n }\n }\n return positions;\n}\n\nexport function useMindMap() {\n const { setEditingNodeId, focusOnRect, autoFocus } = useFlowUI();\n const { currentCanvas, currentCanvasId, selection, setSelection, setDoc } = useFlowContext();\n\n const focusNode = useCallback((node: FlowNode | undefined) => {\n if (!node) return;\n window.setTimeout(() => {\n focusOnRect(node.position.x, node.position.y, node.width, node.height, {\n padding: 80,\n preserveZoom: true,\n duration: 280,\n });\n }, 0);\n }, [focusOnRect]);\n\n const createNode = useCallback((kind: 'child' | 'sibling-after' | 'sibling-before') => {\n const selectedId = selection.nodeIds.size === 1 ? [...selection.nodeIds][0] : null;\n const selected = selectedId ? currentCanvas.nodes.find(node => node.id === selectedId) : undefined;\n if (!selected) return;\n\n // A regular Flow node can become the root of a mind map on first use.\n const parentId = kind === 'child' ? selected.id : selected.data.mindMapParentId;\n if (kind !== 'child' && !parentId) return;\n const id = generateId('mind');\n const node: FlowNode = {\n id,\n type: 'shapeRoundRect',\n position: { x: selected.position.x + NODE_WIDTH + LEVEL_GAP, y: selected.position.y + NODE_HEIGHT + ROW_GAP },\n width: NODE_WIDTH,\n height: NODE_HEIGHT,\n zIndex: Math.max(0, ...currentCanvas.nodes.map(item => item.zIndex ?? 0)) + 1,\n data: {\n // Colors follow the theme (`theme:*` tokens from DEFAULT_NODE_DATA) so\n // mind maps re-color automatically when the DishUI theme changes.\n ...DEFAULT_NODE_DATA,\n label: kind === 'child' ? '子主题' : '主题',\n isMindMapNode: true,\n mindMapParentId: parentId,\n },\n };\n\n setDoc(prev => {\n const canvas = prev.canvases[currentCanvasId];\n if (!canvas) return prev;\n const rootId = (() => {\n let cursor = selected;\n const map = new Map(canvas.nodes.map(item => [item.id, item]));\n while (cursor.data.mindMapParentId && map.has(cursor.data.mindMapParentId)) {\n cursor = map.get(cursor.data.mindMapParentId)!;\n }\n return cursor.id;\n })();\n const normalizedNodes = canvas.nodes.map(item => item.id === selected.id && !item.data.isMindMapNode\n ? { ...item, data: { ...item.data, isMindMapNode: true } }\n : item);\n const selectedIndex = normalizedNodes.findIndex(item => item.id === selected.id);\n const insertIndex = kind === 'sibling-before'\n ? selectedIndex\n : selectedIndex + 1;\n normalizedNodes.splice(Math.max(0, insertIndex), 0, node);\n const nextCanvas: FlowCanvasData = {\n ...canvas,\n nodes: normalizedNodes,\n edges: [...canvas.edges, {\n id: generateId('edge'),\n source: parentId!,\n target: id,\n // Mindmap layout grows strictly left-to-right: always connect the\n // side midpoints (parent right-center → child left-center), matching\n // the pinned-handle behavior of manual connections.\n sourceHandle: 'r_0.5',\n targetHandle: 'l_0.5',\n type: 'simplebezier',\n data: { ...DEFAULT_EDGE_DATA, markerEnd: 'none', strokeWidth: 1.5 },\n }],\n };\n // Child insertion keeps the current node fixed. Sibling insertion keeps\n // their shared parent fixed, so adding nodes never makes the parent jump.\n const fixedNode = kind === 'child'\n ? selected\n : canvas.nodes.find(item => item.id === parentId) ?? selected;\n const positions = layoutMindMap(nextCanvas, rootId, {\n id: fixedNode.id,\n position: fixedNode.position,\n });\n nextCanvas.nodes = nextCanvas.nodes.map(item => {\n const pos = positions.get(item.id);\n return pos ? { ...item, position: pos } : item;\n });\n return { ...prev, canvases: { ...prev.canvases, [currentCanvasId]: nextCanvas } };\n });\n setSelection({ nodeIds: new Set([id]), edgeIds: new Set(), lineIds: new Set() });\n }, [selection, currentCanvas, currentCanvasId, setDoc, setSelection]);\n\n const createRoot = useCallback(() => {\n if (selection.nodeIds.size !== 0) return false;\n const id = generateId('mind');\n const highestZ = Math.max(0, ...currentCanvas.nodes.map(node => node.zIndex ?? 0));\n const node: FlowNode = {\n id,\n type: 'shapeRoundRect',\n position: { x: 120, y: 120 },\n width: NODE_WIDTH,\n height: NODE_HEIGHT,\n zIndex: highestZ + 1,\n // Root keeps a primary-colored outline for hierarchy emphasis; every\n // color is still a theme token, so it follows the active theme.\n data: { ...DEFAULT_NODE_DATA, label: '中心主题', stroke: 'theme:primary', isMindMapNode: true },\n };\n setDoc(prev => {\n const canvas = prev.canvases[currentCanvasId];\n if (!canvas) return prev;\n return { ...prev, canvases: { ...prev.canvases, [currentCanvasId]: { ...canvas, nodes: [...canvas.nodes, node] } } };\n });\n setSelection({ nodeIds: new Set([id]), edgeIds: new Set(), lineIds: new Set() });\n return true;\n }, [selection, currentCanvas, currentCanvasId, setDoc, setSelection]);\n\n const focusedNodeId = selection.nodeIds.size === 1 ? [...selection.nodeIds][0] : null;\n\n // Center only when keyboard focus/selection moves to another node. Node drag\n // updates currentCanvas continuously; depending on currentCanvas here would\n // make the viewport chase the mouse while an object is being repositioned.\n useEffect(() => {\n if (!autoFocus || !focusedNodeId) return;\n const node = currentCanvas.nodes.find(item => item.id === focusedNodeId);\n if (!node) return;\n const timer = window.setTimeout(() => focusNode(node), 20);\n return () => window.clearTimeout(timer);\n // currentCanvas is intentionally excluded: position-only updates must not\n // retrigger viewport focus while dragging.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [autoFocus, focusedNodeId, focusNode]);\n\n useEffect(() => {\n const onKey = (event: KeyboardEvent) => {\n const target = event.target as HTMLElement;\n // Never intercept native editing keys from form controls. In particular,\n // inspector textareas must keep Enter/Tab for multiline media source.\n if (target.matches('input, textarea, select, .flow-label-editor') || target.isContentEditable) return;\n const selectedId = selection.nodeIds.size === 1 ? [...selection.nodeIds][0] : null;\n const selected = selectedId ? currentCanvas.nodes.find(node => node.id === selectedId) : undefined;\n\n const consume = () => {\n event.preventDefault();\n event.stopPropagation();\n event.stopImmediatePropagation();\n };\n\n if (event.key === 'Tab') {\n consume();\n if (!selected) createRoot();\n else createNode('child');\n } else if (event.key === 'Enter' && selected) {\n consume();\n createNode(event.shiftKey ? 'sibling-before' : 'sibling-after');\n } else if ((event.key === ' ' || event.code === 'Space') && selected) {\n consume();\n setEditingNodeId(selected.id);\n } else if (selected && ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key)) {\n const nodeMap = new Map(currentCanvas.nodes.map(node => [node.id, node]));\n const siblings = currentCanvas.nodes.filter(node =>\n node.data.isMindMapNode && node.data.mindMapParentId === selected.data.mindMapParentId,\n );\n const siblingIndex = siblings.findIndex(node => node.id === selected.id);\n const children = currentCanvas.nodes.filter(node => node.data.mindMapParentId === selected.id);\n let targetNode: FlowNode | undefined;\n if (event.key === 'ArrowLeft' && selected.data.mindMapParentId) {\n targetNode = nodeMap.get(selected.data.mindMapParentId);\n } else if (event.key === 'ArrowRight') {\n targetNode = children[0];\n } else if (event.key === 'ArrowUp' && siblingIndex > 0) {\n targetNode = siblings[siblingIndex - 1];\n } else if (event.key === 'ArrowDown' && siblingIndex >= 0 && siblingIndex < siblings.length - 1) {\n targetNode = siblings[siblingIndex + 1];\n }\n\n // Regular Flow nodes have no mind-map relationship metadata. Fall back\n // to spatial navigation, choosing the nearest node in the requested\n // direction. The perpendicular penalty favors visually aligned nodes.\n if (!targetNode) {\n const sx = selected.position.x + selected.width / 2;\n const sy = selected.position.y + selected.height / 2;\n const candidates = currentCanvas.nodes\n .filter(node => node.id !== selected.id && node.type !== 'animAnchor')\n .map(node => {\n const dx = node.position.x + node.width / 2 - sx;\n const dy = node.position.y + node.height / 2 - sy;\n const inDirection = event.key === 'ArrowLeft' ? dx < 0\n : event.key === 'ArrowRight' ? dx > 0\n : event.key === 'ArrowUp' ? dy < 0\n : dy > 0;\n const primary = event.key === 'ArrowLeft' || event.key === 'ArrowRight'\n ? Math.abs(dx)\n : Math.abs(dy);\n const perpendicular = event.key === 'ArrowLeft' || event.key === 'ArrowRight'\n ? Math.abs(dy)\n : Math.abs(dx);\n return { node, inDirection, score: primary + perpendicular * 1.75 };\n })\n .filter(candidate => candidate.inDirection)\n .sort((a, b) => a.score - b.score);\n targetNode = candidates[0]?.node;\n }\n\n if (targetNode) {\n consume();\n setSelection({ nodeIds: new Set([targetNode.id]), edgeIds: new Set(), lineIds: new Set() });\n }\n }\n };\n window.addEventListener('keydown', onKey, true);\n return () => window.removeEventListener('keydown', onKey, true);\n }, [selection, currentCanvas, createNode, createRoot, setEditingNodeId, setSelection]);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useMindMap.js","names":[],"sources":["../../../../../src/components/pro/Flow/hooks/useMindMap.ts"],"sourcesContent":["import { useCallback, useEffect } from 'react';\nimport { useFlowContext } from '../context/FlowContext';\nimport { useFlowUI } from '../context/FlowUIContext';\nimport { DEFAULT_EDGE_DATA, DEFAULT_NODE_DATA } from '../constants';\nimport { generateId } from '../nodes/nodeUtils';\nimport type { FlowCanvasData, FlowNode } from '../types';\n\nconst NODE_WIDTH = 150;\nconst NODE_HEIGHT = 52;\nconst LEVEL_GAP = 100;\nconst ROW_GAP = 26;\n\nfunction layoutMindMap(\n canvas: FlowCanvasData,\n rootId: string,\n fixed?: { id: string; position: { x: number; y: number } },\n): Map<string, { x: number; y: number }> {\n const nodes = canvas.nodes.filter(node => node.data.isMindMapNode);\n const nodeMap = new Map(nodes.map(node => [node.id, node]));\n const children = new Map<string, FlowNode[]>();\n for (const node of nodes) {\n const parentId = node.data.mindMapParentId;\n if (!parentId || !nodeMap.has(parentId)) continue;\n const list = children.get(parentId) ?? [];\n list.push(node);\n children.set(parentId, list);\n }\n\n const root = nodeMap.get(rootId);\n if (!root) return new Map();\n const positions = new Map<string, { x: number; y: number }>();\n let nextY = root.position.y;\n\n const place = (node: FlowNode, depth: number): number => {\n const kids = children.get(node.id) ?? [];\n let centerY: number;\n if (kids.length === 0) {\n centerY = nextY;\n nextY += NODE_HEIGHT + ROW_GAP;\n } else {\n const childYs = kids.map(child => place(child, depth + 1));\n centerY = (childYs[0] + childYs[childYs.length - 1]) / 2;\n }\n positions.set(node.id, {\n x: root.position.x + depth * (NODE_WIDTH + LEVEL_GAP),\n y: centerY,\n });\n return centerY;\n };\n\n place(root, 0);\n if (fixed) {\n const computed = positions.get(fixed.id);\n if (computed) {\n const dx = fixed.position.x - computed.x;\n const dy = fixed.position.y - computed.y;\n for (const [id, position] of positions) {\n positions.set(id, { x: position.x + dx, y: position.y + dy });\n }\n }\n }\n return positions;\n}\n\nexport function useMindMap() {\n const { setEditingNodeId, focusOnRect, autoFocus } = useFlowUI();\n const { currentCanvas, currentCanvasId, selection, setSelection, setDoc } = useFlowContext();\n\n const focusNode = useCallback((node: FlowNode | undefined) => {\n if (!node) return;\n window.setTimeout(() => {\n focusOnRect(node.position.x, node.position.y, node.width, node.height, {\n padding: 80,\n preserveZoom: true,\n duration: 280,\n });\n }, 0);\n }, [focusOnRect]);\n\n const createNode = useCallback((kind: 'child' | 'sibling-after' | 'sibling-before') => {\n const selectedId = selection.nodeIds.size === 1 ? [...selection.nodeIds][0] : null;\n const selected = selectedId ? currentCanvas.nodes.find(node => node.id === selectedId) : undefined;\n if (!selected) return;\n\n // A regular Flow node can become the root of a mind map on first use.\n const parentId = kind === 'child' ? selected.id : selected.data.mindMapParentId;\n if (kind !== 'child' && !parentId) return;\n const id = generateId('mind');\n const node: FlowNode = {\n id,\n type: 'shapeRoundRect',\n position: { x: selected.position.x + NODE_WIDTH + LEVEL_GAP, y: selected.position.y + NODE_HEIGHT + ROW_GAP },\n width: NODE_WIDTH,\n height: NODE_HEIGHT,\n zIndex: Math.max(0, ...currentCanvas.nodes.map(item => item.zIndex ?? 0)) + 1,\n data: {\n // Colors follow the theme (`theme:*` tokens from DEFAULT_NODE_DATA) so\n // mind maps re-color automatically when the DishUI theme changes.\n ...DEFAULT_NODE_DATA,\n label: kind === 'child' ? '子主题' : '主题',\n isMindMapNode: true,\n mindMapParentId: parentId,\n },\n };\n\n setDoc(prev => {\n const canvas = prev.canvases[currentCanvasId];\n if (!canvas) return prev;\n const rootId = (() => {\n let cursor = selected;\n const map = new Map(canvas.nodes.map(item => [item.id, item]));\n while (cursor.data.mindMapParentId && map.has(cursor.data.mindMapParentId)) {\n cursor = map.get(cursor.data.mindMapParentId)!;\n }\n return cursor.id;\n })();\n const normalizedNodes = canvas.nodes.map(item => item.id === selected.id && !item.data.isMindMapNode\n ? { ...item, data: { ...item.data, isMindMapNode: true } }\n : item);\n const selectedIndex = normalizedNodes.findIndex(item => item.id === selected.id);\n const insertIndex = kind === 'sibling-before'\n ? selectedIndex\n : selectedIndex + 1;\n normalizedNodes.splice(Math.max(0, insertIndex), 0, node);\n const nextCanvas: FlowCanvasData = {\n ...canvas,\n nodes: normalizedNodes,\n edges: [...canvas.edges, {\n id: generateId('edge'),\n source: parentId!,\n target: id,\n // Mindmap layout grows strictly left-to-right: always connect the\n // side midpoints (parent right-center → child left-center), matching\n // the pinned-handle behavior of manual connections.\n sourceHandle: 'r_0.5',\n targetHandle: 'l_0.5',\n type: 'simplebezier',\n data: { ...DEFAULT_EDGE_DATA, markerEnd: 'none', strokeWidth: 1.5 },\n }],\n };\n // Child insertion keeps the current node fixed. Sibling insertion keeps\n // their shared parent fixed, so adding nodes never makes the parent jump.\n const fixedNode = kind === 'child'\n ? selected\n : canvas.nodes.find(item => item.id === parentId) ?? selected;\n const positions = layoutMindMap(nextCanvas, rootId, {\n id: fixedNode.id,\n position: fixedNode.position,\n });\n nextCanvas.nodes = nextCanvas.nodes.map(item => {\n const pos = positions.get(item.id);\n return pos ? { ...item, position: pos } : item;\n });\n return { ...prev, canvases: { ...prev.canvases, [currentCanvasId]: nextCanvas } };\n });\n setSelection({ nodeIds: new Set([id]), edgeIds: new Set(), lineIds: new Set() });\n }, [selection, currentCanvas, currentCanvasId, setDoc, setSelection]);\n\n const createRoot = useCallback(() => {\n if (selection.nodeIds.size !== 0) return false;\n const id = generateId('mind');\n const highestZ = Math.max(0, ...currentCanvas.nodes.map(node => node.zIndex ?? 0));\n const node: FlowNode = {\n id,\n type: 'shapeRoundRect',\n position: { x: 120, y: 120 },\n width: NODE_WIDTH,\n height: NODE_HEIGHT,\n zIndex: highestZ + 1,\n // Root keeps a primary-colored outline for hierarchy emphasis; every\n // color is still a theme token, so it follows the active theme.\n data: { ...DEFAULT_NODE_DATA, label: '中心主题', stroke: 'theme:primary', isMindMapNode: true },\n };\n setDoc(prev => {\n const canvas = prev.canvases[currentCanvasId];\n if (!canvas) return prev;\n return { ...prev, canvases: { ...prev.canvases, [currentCanvasId]: { ...canvas, nodes: [...canvas.nodes, node] } } };\n });\n setSelection({ nodeIds: new Set([id]), edgeIds: new Set(), lineIds: new Set() });\n return true;\n }, [selection, currentCanvas, currentCanvasId, setDoc, setSelection]);\n\n const focusedNodeId = selection.nodeIds.size === 1 ? [...selection.nodeIds][0] : null;\n\n // Center only when keyboard focus/selection moves to another node. Node drag\n // updates currentCanvas continuously; depending on currentCanvas here would\n // make the viewport chase the mouse while an object is being repositioned.\n useEffect(() => {\n if (!autoFocus || !focusedNodeId) return;\n const node = currentCanvas.nodes.find(item => item.id === focusedNodeId);\n if (!node) return;\n const timer = window.setTimeout(() => focusNode(node), 20);\n return () => window.clearTimeout(timer);\n // currentCanvas is intentionally excluded: position-only updates must not\n // retrigger viewport focus while dragging.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [autoFocus, focusedNodeId, focusNode]);\n\n useEffect(() => {\n const onKey = (event: KeyboardEvent) => {\n const target = event.target as HTMLElement;\n // Never intercept native editing keys from form controls. In particular,\n // inspector textareas must keep Enter/Tab for multiline media source.\n if (target.matches('input, textarea, select, .flow-label-editor') || target.isContentEditable) return;\n const selectedId = selection.nodeIds.size === 1 ? [...selection.nodeIds][0] : null;\n const selected = selectedId ? currentCanvas.nodes.find(node => node.id === selectedId) : undefined;\n\n const consume = () => {\n event.preventDefault();\n event.stopPropagation();\n event.stopImmediatePropagation();\n };\n\n if (event.key === 'Tab') {\n consume();\n if (!selected) createRoot();\n else createNode('child');\n } else if (event.key === 'Enter' && selected) {\n consume();\n createNode(event.shiftKey ? 'sibling-before' : 'sibling-after');\n } else if ((event.key === ' ' || event.code === 'Space') && selected) {\n consume();\n setEditingNodeId(selected.id);\n } else if (selected && ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key)) {\n const nodeMap = new Map(currentCanvas.nodes.map(node => [node.id, node]));\n const siblings = currentCanvas.nodes.filter(node =>\n node.data.isMindMapNode && node.data.mindMapParentId === selected.data.mindMapParentId,\n );\n const siblingIndex = siblings.findIndex(node => node.id === selected.id);\n const children = currentCanvas.nodes.filter(node => node.data.mindMapParentId === selected.id);\n let targetNode: FlowNode | undefined;\n if (event.key === 'ArrowLeft' && selected.data.mindMapParentId) {\n targetNode = nodeMap.get(selected.data.mindMapParentId);\n } else if (event.key === 'ArrowRight') {\n targetNode = children[0];\n } else if (event.key === 'ArrowUp' && siblingIndex > 0) {\n targetNode = siblings[siblingIndex - 1];\n } else if (event.key === 'ArrowDown' && siblingIndex >= 0 && siblingIndex < siblings.length - 1) {\n targetNode = siblings[siblingIndex + 1];\n }\n\n // Regular Flow nodes have no mind-map relationship metadata. Fall back\n // to spatial navigation, choosing the nearest node in the requested\n // direction. The perpendicular penalty favors visually aligned nodes.\n if (!targetNode) {\n const sx = selected.position.x + selected.width / 2;\n const sy = selected.position.y + selected.height / 2;\n const candidates = currentCanvas.nodes\n .filter(node => node.id !== selected.id && node.type !== 'animAnchor')\n .map(node => {\n const dx = node.position.x + node.width / 2 - sx;\n const dy = node.position.y + node.height / 2 - sy;\n const inDirection = event.key === 'ArrowLeft' ? dx < 0\n : event.key === 'ArrowRight' ? dx > 0\n : event.key === 'ArrowUp' ? dy < 0\n : dy > 0;\n const primary = event.key === 'ArrowLeft' || event.key === 'ArrowRight'\n ? Math.abs(dx)\n : Math.abs(dy);\n const perpendicular = event.key === 'ArrowLeft' || event.key === 'ArrowRight'\n ? Math.abs(dy)\n : Math.abs(dx);\n return { node, inDirection, score: primary + perpendicular * 1.75 };\n })\n .filter(candidate => candidate.inDirection)\n .sort((a, b) => a.score - b.score);\n targetNode = candidates[0]?.node;\n }\n\n if (targetNode) {\n consume();\n setSelection({ nodeIds: new Set([targetNode.id]), edgeIds: new Set(), lineIds: new Set() });\n }\n }\n };\n window.addEventListener('keydown', onKey, true);\n return () => window.removeEventListener('keydown', onKey, true);\n }, [selection, currentCanvas, createNode, createRoot, setEditingNodeId, setSelection]);\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useNodeMutations.js","names":[],"sources":["../../../../../src/components/pro/Flow/hooks/useNodeMutations.ts"],"sourcesContent":["import { useCallback } from 'react';\nimport { useFlowContext } from '../context/FlowContext';\nimport type { FlowNode, FlowNodeData, FlowShapeType } from '../types';\nimport { DEFAULT_NODE_DATA } from '../constants';\nimport { generateId } from '../nodes/nodeUtils';\n\n/**\n * Provides CRUD operations for nodes on the current canvas.\n */\nexport function useNodeMutations() {\n const { setDoc, currentCanvasId } = useFlowContext();\n\n const addNode = useCallback(\n (type: FlowShapeType, x: number, y: number, width: number, height: number, data?: Partial<FlowNodeData>): string => {\n const id = generateId('node');\n const node: FlowNode = {\n id,\n type,\n position: { x, y },\n width,\n height,\n data: { ...DEFAULT_NODE_DATA, ...data },\n };\n setDoc(prev => {\n const canvas = prev.canvases[currentCanvasId];\n if (!canvas) return prev;\n return {\n ...prev,\n canvases: {\n ...prev.canvases,\n [currentCanvasId]: {\n ...canvas,\n nodes: [...canvas.nodes, node],\n },\n },\n };\n });\n return id;\n },\n [setDoc, currentCanvasId],\n );\n\n const updateNode = useCallback(\n (id: string, updates: Partial<Pick<FlowNode, 'position' | 'width' | 'height' | 'zIndex'>> & { data?: Partial<FlowNodeData> }) => {\n setDoc(prev => {\n const canvas = prev.canvases[currentCanvasId];\n if (!canvas) return prev;\n return {\n ...prev,\n canvases: {\n ...prev.canvases,\n [currentCanvasId]: {\n ...canvas,\n nodes: canvas.nodes.map(n => {\n if (n.id !== id) return n;\n return {\n ...n,\n ...('position' in updates ? { position: updates.position! } : {}),\n ...('width' in updates ? { width: updates.width! } : {}),\n ...('height' in updates ? { height: updates.height! } : {}),\n ...('zIndex' in updates ? { zIndex: updates.zIndex } : {}),\n data: updates.data ? { ...n.data, ...updates.data } : n.data,\n };\n }),\n },\n },\n };\n });\n },\n [setDoc, currentCanvasId],\n );\n\n const moveNodes = useCallback(\n (ids: Set<string>, dx: number, dy: number) => {\n setDoc(prev => {\n const canvas = prev.canvases[currentCanvasId];\n if (!canvas) return prev;\n return {\n ...prev,\n canvases: {\n ...prev.canvases,\n [currentCanvasId]: {\n ...canvas,\n nodes: canvas.nodes.map(n => {\n if (!ids.has(n.id)) return n;\n return { ...n, position: { x: n.position.x + dx, y: n.position.y + dy } };\n }),\n },\n },\n };\n });\n },\n [setDoc, currentCanvasId],\n );\n\n const deleteNodes = useCallback(\n (ids: Set<string>) => {\n setDoc(prev => {\n const canvas = prev.canvases[currentCanvasId];\n if (!canvas) return prev;\n return {\n ...prev,\n canvases: {\n ...prev.canvases,\n [currentCanvasId]: {\n ...canvas,\n nodes: canvas.nodes.filter(n => !ids.has(n.id)),\n edges: canvas.edges.filter(e => !ids.has(e.source) && !ids.has(e.target)),\n },\n },\n };\n });\n },\n [setDoc, currentCanvasId],\n );\n\n return { addNode, updateNode, moveNodes, deleteNodes };\n}\n"],"mappings":";;;;AASA,SAAgB,IAAmB;AACjC,QAAM,EAAE,QAAA,GAAQ,iBAAA,EAAA,IAAoB,EAAe;AA0GnD,SAAO;AAAA,IAAE,SAxGO,EAAA,CACb,GAAqB,GAAW,GAAW,GAAe,GAAgB,MAAyC;AAClH,YAAM,IAAK,EAAW,MAAM,GACtB,IAAiB;AAAA,QACrB,IAAA;AAAA,QACA,MAAA;AAAA,QACA,UAAU;AAAA,UAAE,GAAA;AAAA,UAAG,GAAA;AAAA,QAAE;AAAA,QACjB,OAAA;AAAA,QACA,QAAA;AAAA,QACA,MAAM;AAAA,UAAE,GAAG;AAAA,UAAmB,GAAG;AAAA,QAAK;AAAA,MACxC;AACA,aAAA,EAAA,CAAO,MAAQ;AACb,cAAM,IAAS,EAAK,SAAS,CAAA;AAC7B,eAAK,IACE;AAAA,UACL,GAAG;AAAA,UACH,UAAU;AAAA,YACR,GAAG,EAAK;AAAA,
|
|
1
|
+
{"version":3,"file":"useNodeMutations.js","names":[],"sources":["../../../../../src/components/pro/Flow/hooks/useNodeMutations.ts"],"sourcesContent":["import { useCallback } from 'react';\nimport { useFlowContext } from '../context/FlowContext';\nimport type { FlowNode, FlowNodeData, FlowShapeType } from '../types';\nimport { DEFAULT_NODE_DATA } from '../constants';\nimport { generateId } from '../nodes/nodeUtils';\n\n/**\n * Provides CRUD operations for nodes on the current canvas.\n */\nexport function useNodeMutations() {\n const { setDoc, currentCanvasId } = useFlowContext();\n\n const addNode = useCallback(\n (type: FlowShapeType, x: number, y: number, width: number, height: number, data?: Partial<FlowNodeData>): string => {\n const id = generateId('node');\n const node: FlowNode = {\n id,\n type,\n position: { x, y },\n width,\n height,\n data: { ...DEFAULT_NODE_DATA, ...data },\n };\n setDoc(prev => {\n const canvas = prev.canvases[currentCanvasId];\n if (!canvas) return prev;\n return {\n ...prev,\n canvases: {\n ...prev.canvases,\n [currentCanvasId]: {\n ...canvas,\n nodes: [...canvas.nodes, node],\n },\n },\n };\n });\n return id;\n },\n [setDoc, currentCanvasId],\n );\n\n const updateNode = useCallback(\n (id: string, updates: Partial<Pick<FlowNode, 'position' | 'width' | 'height' | 'zIndex'>> & { data?: Partial<FlowNodeData> }) => {\n setDoc(prev => {\n const canvas = prev.canvases[currentCanvasId];\n if (!canvas) return prev;\n return {\n ...prev,\n canvases: {\n ...prev.canvases,\n [currentCanvasId]: {\n ...canvas,\n nodes: canvas.nodes.map(n => {\n if (n.id !== id) return n;\n return {\n ...n,\n ...('position' in updates ? { position: updates.position! } : {}),\n ...('width' in updates ? { width: updates.width! } : {}),\n ...('height' in updates ? { height: updates.height! } : {}),\n ...('zIndex' in updates ? { zIndex: updates.zIndex } : {}),\n data: updates.data ? { ...n.data, ...updates.data } : n.data,\n };\n }),\n },\n },\n };\n });\n },\n [setDoc, currentCanvasId],\n );\n\n const moveNodes = useCallback(\n (ids: Set<string>, dx: number, dy: number) => {\n setDoc(prev => {\n const canvas = prev.canvases[currentCanvasId];\n if (!canvas) return prev;\n return {\n ...prev,\n canvases: {\n ...prev.canvases,\n [currentCanvasId]: {\n ...canvas,\n nodes: canvas.nodes.map(n => {\n if (!ids.has(n.id)) return n;\n return { ...n, position: { x: n.position.x + dx, y: n.position.y + dy } };\n }),\n },\n },\n };\n });\n },\n [setDoc, currentCanvasId],\n );\n\n const deleteNodes = useCallback(\n (ids: Set<string>) => {\n setDoc(prev => {\n const canvas = prev.canvases[currentCanvasId];\n if (!canvas) return prev;\n return {\n ...prev,\n canvases: {\n ...prev.canvases,\n [currentCanvasId]: {\n ...canvas,\n nodes: canvas.nodes.filter(n => !ids.has(n.id)),\n edges: canvas.edges.filter(e => !ids.has(e.source) && !ids.has(e.target)),\n },\n },\n };\n });\n },\n [setDoc, currentCanvasId],\n );\n\n return { addNode, updateNode, moveNodes, deleteNodes };\n}\n"],"mappings":"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"}
|
|
@@ -9,8 +9,8 @@ var v = class {
|
|
|
9
9
|
rawPoints = [];
|
|
10
10
|
drawing = !1;
|
|
11
11
|
_active = !1;
|
|
12
|
-
constructor(t,
|
|
13
|
-
this.stage = t, this.callbacks =
|
|
12
|
+
constructor(t, e, i) {
|
|
13
|
+
this.stage = t, this.callbacks = i, this.preview = new a(), this.preview.label = "freehand-preview", this.preview.visible = !1, e.addChild(this.preview);
|
|
14
14
|
}
|
|
15
15
|
get active() {
|
|
16
16
|
return this._active;
|
|
@@ -23,15 +23,15 @@ var v = class {
|
|
|
23
23
|
}
|
|
24
24
|
_onDown = (t) => {
|
|
25
25
|
if (t.button !== 0) return;
|
|
26
|
-
const
|
|
27
|
-
this.drawing = !0, this.rawPoints = [
|
|
26
|
+
const e = this.callbacks.screenToWorld(t.global.x, t.global.y);
|
|
27
|
+
this.drawing = !0, this.rawPoints = [e], this.preview.visible = !0, this.preview.clear();
|
|
28
28
|
};
|
|
29
29
|
_onMove = (t) => {
|
|
30
30
|
if (!this.drawing) return;
|
|
31
|
-
const
|
|
32
|
-
if (this.rawPoints.push(
|
|
31
|
+
const e = this.callbacks.screenToWorld(t.global.x, t.global.y);
|
|
32
|
+
if (this.rawPoints.push(e), this.preview.clear(), !(this.rawPoints.length < 2)) {
|
|
33
33
|
this.preview.moveTo(this.rawPoints[0].x, this.rawPoints[0].y);
|
|
34
|
-
for (let
|
|
34
|
+
for (let i = 1; i < this.rawPoints.length; i++) this.preview.lineTo(this.rawPoints[i].x, this.rawPoints[i].y);
|
|
35
35
|
this.preview.stroke({
|
|
36
36
|
color: s("theme:base-content", "#374151"),
|
|
37
37
|
width: 2,
|
|
@@ -45,10 +45,10 @@ var v = class {
|
|
|
45
45
|
this.rawPoints = [];
|
|
46
46
|
return;
|
|
47
47
|
}
|
|
48
|
-
const t =
|
|
48
|
+
const t = r(this.rawPoints, 2), e = h(t, 4), i = {
|
|
49
49
|
id: o("line"),
|
|
50
50
|
type: "freehand",
|
|
51
|
-
points:
|
|
51
|
+
points: e,
|
|
52
52
|
strokeColor: "theme:base-content",
|
|
53
53
|
strokeWidth: 2,
|
|
54
54
|
lineStyle: "solid"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FreehandTool.js","names":[],"sources":["../../../../../src/components/pro/Flow/lines/FreehandTool.ts"],"sourcesContent":["import { Graphics, Container, FederatedPointerEvent } from 'pixi.js';\nimport { simplifyPath, smoothCatmullRom, type Point } from './lineSmoothing';\nimport type { FlowLine } from '../types';\nimport { generateId } from '../nodes/nodeUtils';\nimport { resolveThemeColor } from '../utils/themeColor';\n\nexport interface FreehandToolCallbacks {\n /** Called when a freehand line is finished */\n onLineComplete: (line: FlowLine) => void;\n /** Convert screen coords to world coords */\n screenToWorld: (sx: number, sy: number) => { x: number; y: number };\n}\n\n/**\n * Captures pointer trail for freehand drawing, smooths and stores as FlowLine.\n */\nexport class FreehandTool {\n private stage: Container;\n private preview: Graphics;\n private callbacks: FreehandToolCallbacks;\n private rawPoints: Point[] = [];\n private drawing = false;\n private _active = false;\n\n constructor(stage: Container, world: Container, callbacks: FreehandToolCallbacks) {\n this.stage = stage;\n this.callbacks = callbacks;\n this.preview = new Graphics();\n this.preview.label = 'freehand-preview';\n this.preview.visible = false;\n world.addChild(this.preview);\n }\n\n get active(): boolean { return this._active; }\n\n activate(): void {\n this._active = true;\n this.stage.on('pointerdown', this._onDown, this);\n this.stage.on('globalpointermove', this._onMove, this);\n this.stage.on('pointerup', this._onUp, this);\n this.stage.on('pointerupoutside', this._onUp, this);\n }\n\n deactivate(): void {\n this._active = false;\n this.drawing = false;\n this.rawPoints = [];\n if (!this.preview.destroyed) {\n this.preview.clear();\n this.preview.visible = false;\n }\n this.stage.off('pointerdown', this._onDown, this);\n this.stage.off('globalpointermove', this._onMove, this);\n this.stage.off('pointerup', this._onUp, this);\n this.stage.off('pointerupoutside', this._onUp, this);\n }\n\n private _onDown = (e: FederatedPointerEvent): void => {\n if (e.button !== 0) return;\n const world = this.callbacks.screenToWorld(e.global.x, e.global.y);\n this.drawing = true;\n this.rawPoints = [world];\n this.preview.visible = true;\n this.preview.clear();\n };\n\n private _onMove = (e: FederatedPointerEvent): void => {\n if (!this.drawing) return;\n const world = this.callbacks.screenToWorld(e.global.x, e.global.y);\n this.rawPoints.push(world);\n\n // Draw preview\n this.preview.clear();\n if (this.rawPoints.length < 2) return;\n this.preview.moveTo(this.rawPoints[0].x, this.rawPoints[0].y);\n for (let i = 1; i < this.rawPoints.length; i++) {\n this.preview.lineTo(this.rawPoints[i].x, this.rawPoints[i].y);\n }\n this.preview.stroke({ color: resolveThemeColor('theme:base-content', '#374151'), width: 2, alpha: 0.6 });\n };\n\n private _onUp = (): void => {\n if (!this.drawing) return;\n this.drawing = false;\n this.preview.clear();\n this.preview.visible = false;\n\n if (this.rawPoints.length < 3) {\n this.rawPoints = [];\n return;\n }\n\n const simplified = simplifyPath(this.rawPoints, 2);\n const smoothed = smoothCatmullRom(simplified, 4);\n\n const line: FlowLine = {\n id: generateId('line'),\n type: 'freehand',\n points: smoothed,\n strokeColor: 'theme:base-content',\n strokeWidth: 2,\n lineStyle: 'solid',\n };\n\n this.callbacks.onLineComplete(line);\n this.rawPoints = [];\n };\n\n destroy(): void {\n this.deactivate();\n if (!this.preview.destroyed) this.preview.destroy();\n }\n}\n"],"mappings":";;;;AAgBA,IAAa,IAAb,MAA0B;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAA6B,CAAC;AAAA,EAC9B,UAAkB;AAAA,EAClB,UAAkB;AAAA,EAElB,YAAY,GAAkB,GAAkB,GAAkC;AAChF,SAAK,QAAQ,GACb,KAAK,YAAY,GACjB,KAAK,UAAU,IAAI,EAAS,GAC5B,KAAK,QAAQ,QAAQ,oBACrB,KAAK,QAAQ,UAAU,IACvB,EAAM,SAAS,KAAK,OAAO;AAAA,EAC7B;AAAA,EAEA,IAAI,SAAkB;AAAE,WAAO,KAAK;AAAA,EAAS;AAAA,EAE7C,WAAiB;AACf,SAAK,UAAU,IACf,KAAK,MAAM,GAAG,eAAe,KAAK,SAAS,IAAI,GAC/C,KAAK,MAAM,GAAG,qBAAqB,KAAK,SAAS,IAAI,GACrD,KAAK,MAAM,GAAG,aAAa,KAAK,OAAO,IAAI,GAC3C,KAAK,MAAM,GAAG,oBAAoB,KAAK,OAAO,IAAI;AAAA,EACpD;AAAA,EAEA,aAAmB;AACjB,SAAK,UAAU,IACf,KAAK,UAAU,IACf,KAAK,YAAY,CAAC,GACb,KAAK,QAAQ,cAChB,KAAK,QAAQ,MAAM,GACnB,KAAK,QAAQ,UAAU,KAEzB,KAAK,MAAM,IAAI,eAAe,KAAK,SAAS,IAAI,GAChD,KAAK,MAAM,IAAI,qBAAqB,KAAK,SAAS,IAAI,GACtD,KAAK,MAAM,IAAI,aAAa,KAAK,OAAO,IAAI,GAC5C,KAAK,MAAM,IAAI,oBAAoB,KAAK,OAAO,IAAI;AAAA,EACrD;AAAA,EAEA,UAAA,CAAmB,MAAmC;AACpD,QAAI,EAAE,WAAW,EAAG;AACpB,UAAM,IAAQ,KAAK,UAAU,cAAc,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC;AACjE,SAAK,UAAU,IACf,KAAK,YAAY,CAAC,CAAK,GACvB,KAAK,QAAQ,UAAU,IACvB,KAAK,QAAQ,MAAM;AAAA,EACrB;AAAA,EAEA,UAAA,CAAmB,MAAmC;AACpD,QAAI,CAAC,KAAK,QAAS;AACnB,UAAM,IAAQ,KAAK,UAAU,cAAc,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC;AAKjE,QAJA,KAAK,UAAU,KAAK,CAAK,GAGzB,KAAK,QAAQ,MAAM,GACf,OAAK,UAAU,SAAS,IAC5B;AAAA,WAAK,QAAQ,OAAO,KAAK,UAAU,CAAA,EAAG,GAAG,KAAK,UAAU,CAAA,EAAG,CAAC;AAC5D,eAAS,IAAI,GAAG,IAAI,KAAK,UAAU,QAAQ,IACzC,MAAK,QAAQ,OAAO,KAAK,UAAU,CAAA,EAAG,GAAG,KAAK,UAAU,CAAA,EAAG,CAAC;AAE9D,WAAK,QAAQ,OAAO;AAAA,QAAE,OAAO,EAAkB,sBAAsB,SAAS;AAAA,QAAG,OAAO;AAAA,QAAG,OAAO;AAAA,MAAI,CAAC;AAAA;AAAA,EACzG;AAAA,EAEA,QAAA,MAA4B;AAC1B,QAAI,CAAC,KAAK,QAAS;AAKnB,QAJA,KAAK,UAAU,IACf,KAAK,QAAQ,MAAM,GACnB,KAAK,QAAQ,UAAU,IAEnB,KAAK,UAAU,SAAS,GAAG;AAC7B,WAAK,YAAY,CAAC;AAClB;AAAA,IACF;
|
|
1
|
+
{"version":3,"file":"FreehandTool.js","names":[],"sources":["../../../../../src/components/pro/Flow/lines/FreehandTool.ts"],"sourcesContent":["import { Graphics, Container, FederatedPointerEvent } from 'pixi.js';\nimport { simplifyPath, smoothCatmullRom, type Point } from './lineSmoothing';\nimport type { FlowLine } from '../types';\nimport { generateId } from '../nodes/nodeUtils';\nimport { resolveThemeColor } from '../utils/themeColor';\n\nexport interface FreehandToolCallbacks {\n /** Called when a freehand line is finished */\n onLineComplete: (line: FlowLine) => void;\n /** Convert screen coords to world coords */\n screenToWorld: (sx: number, sy: number) => { x: number; y: number };\n}\n\n/**\n * Captures pointer trail for freehand drawing, smooths and stores as FlowLine.\n */\nexport class FreehandTool {\n private stage: Container;\n private preview: Graphics;\n private callbacks: FreehandToolCallbacks;\n private rawPoints: Point[] = [];\n private drawing = false;\n private _active = false;\n\n constructor(stage: Container, world: Container, callbacks: FreehandToolCallbacks) {\n this.stage = stage;\n this.callbacks = callbacks;\n this.preview = new Graphics();\n this.preview.label = 'freehand-preview';\n this.preview.visible = false;\n world.addChild(this.preview);\n }\n\n get active(): boolean { return this._active; }\n\n activate(): void {\n this._active = true;\n this.stage.on('pointerdown', this._onDown, this);\n this.stage.on('globalpointermove', this._onMove, this);\n this.stage.on('pointerup', this._onUp, this);\n this.stage.on('pointerupoutside', this._onUp, this);\n }\n\n deactivate(): void {\n this._active = false;\n this.drawing = false;\n this.rawPoints = [];\n if (!this.preview.destroyed) {\n this.preview.clear();\n this.preview.visible = false;\n }\n this.stage.off('pointerdown', this._onDown, this);\n this.stage.off('globalpointermove', this._onMove, this);\n this.stage.off('pointerup', this._onUp, this);\n this.stage.off('pointerupoutside', this._onUp, this);\n }\n\n private _onDown = (e: FederatedPointerEvent): void => {\n if (e.button !== 0) return;\n const world = this.callbacks.screenToWorld(e.global.x, e.global.y);\n this.drawing = true;\n this.rawPoints = [world];\n this.preview.visible = true;\n this.preview.clear();\n };\n\n private _onMove = (e: FederatedPointerEvent): void => {\n if (!this.drawing) return;\n const world = this.callbacks.screenToWorld(e.global.x, e.global.y);\n this.rawPoints.push(world);\n\n // Draw preview\n this.preview.clear();\n if (this.rawPoints.length < 2) return;\n this.preview.moveTo(this.rawPoints[0].x, this.rawPoints[0].y);\n for (let i = 1; i < this.rawPoints.length; i++) {\n this.preview.lineTo(this.rawPoints[i].x, this.rawPoints[i].y);\n }\n this.preview.stroke({ color: resolveThemeColor('theme:base-content', '#374151'), width: 2, alpha: 0.6 });\n };\n\n private _onUp = (): void => {\n if (!this.drawing) return;\n this.drawing = false;\n this.preview.clear();\n this.preview.visible = false;\n\n if (this.rawPoints.length < 3) {\n this.rawPoints = [];\n return;\n }\n\n const simplified = simplifyPath(this.rawPoints, 2);\n const smoothed = smoothCatmullRom(simplified, 4);\n\n const line: FlowLine = {\n id: generateId('line'),\n type: 'freehand',\n points: smoothed,\n strokeColor: 'theme:base-content',\n strokeWidth: 2,\n lineStyle: 'solid',\n };\n\n this.callbacks.onLineComplete(line);\n this.rawPoints = [];\n };\n\n destroy(): void {\n this.deactivate();\n if (!this.preview.destroyed) this.preview.destroy();\n }\n}\n"],"mappings":"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"}
|
|
@@ -49,10 +49,10 @@ var L = class {
|
|
|
49
49
|
if (t.length < 2) return;
|
|
50
50
|
const a = s ? "#3b82f6" : x(e.strokeColor, "#374151"), d = e.strokeWidth;
|
|
51
51
|
r.clear();
|
|
52
|
-
const
|
|
53
|
-
if (
|
|
54
|
-
const i = e.lineStyle === "dynamic" ? this._dynamicOffset : 0;
|
|
55
|
-
g(r,
|
|
52
|
+
const c = u(e.lineStyle, d);
|
|
53
|
+
if (c) {
|
|
54
|
+
const i = e.lineStyle === "dynamic" ? this._dynamicOffset : 0, l = e.closed ? [...t, t[0]] : t;
|
|
55
|
+
g(r, l, c, i), r.stroke({
|
|
56
56
|
color: a,
|
|
57
57
|
width: d,
|
|
58
58
|
cap: "round"
|
|
@@ -70,7 +70,7 @@ var L = class {
|
|
|
70
70
|
f(r, e.markerStart, t[0].x, t[0].y, i, a);
|
|
71
71
|
}
|
|
72
72
|
if (e.markerEnd && e.markerEnd !== "none" && t.length >= 2) {
|
|
73
|
-
const i = t[t.length - 1],
|
|
73
|
+
const i = t[t.length - 1], l = t[t.length - 2], p = h(l.x, l.y, i.x, i.y);
|
|
74
74
|
f(r, e.markerEnd, i.x, i.y, p, a);
|
|
75
75
|
}
|
|
76
76
|
o.clear(), o.moveTo(t[0].x, t[0].y);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LineRenderer.js","names":[],"sources":["../../../../../src/components/pro/Flow/lines/LineRenderer.ts"],"sourcesContent":["import { Container, Graphics } from 'pixi.js';\nimport type { FlowLine } from '../types';\nimport { drawMarker, angleBetween } from '../edges/edgeMarkers';\nimport { drawDashedPolyline } from '../utils/dashedLine';\nimport { resolveThemeColor } from '../utils/themeColor';\n\nfunction getLineDash(style?: string, width = 2): number[] | undefined {\n if (!style || style === 'solid') return undefined;\n if (style === 'dynamic') return [width * 4, width * 3];\n if (style === 'dotted') return [width, width * 2];\n if (style === 'dashed') return [width * 3, width * 2];\n return undefined;\n}\n\ninterface LineDisplay {\n container: Container;\n gfx: Graphics;\n hitArea: Graphics;\n lineId: string;\n}\n\n/**\n * Renders independent FlowLine[] objects on the canvas.\n */\nexport class LineRenderer {\n private world: Container;\n private lineLayer: Container;\n private lines = new Map<string, LineDisplay>();\n private _dynamicOffset = 0;\n\n /** Call once per frame to advance the dynamic dash animation. */\n advanceAnimation(deltaMs: number): void {\n this._dynamicOffset = (this._dynamicOffset + deltaMs * 0.06) % 1000;\n }\n\n constructor(world: Container) {\n this.world = world;\n this.lineLayer = new Container({ label: 'lines', sortableChildren: true });\n // Lines on top of edges but below nodes\n this.world.addChildAt(this.lineLayer, Math.min(1, this.world.children.length));\n }\n\n sync(flowLines: FlowLine[], selectedIds: Set<string>): void {\n const seen = new Set<string>();\n\n for (const line of flowLines) {\n seen.add(line.id);\n let display = this.lines.get(line.id);\n if (!display) {\n display = this._create(line);\n this.lines.set(line.id, display);\n }\n this._update(display, line, selectedIds.has(line.id));\n }\n\n for (const [id, display] of this.lines) {\n if (!seen.has(id)) {\n this.lineLayer.removeChild(display.container);\n display.container.destroy({ children: true });\n this.lines.delete(id);\n }\n }\n }\n\n private _create(line: FlowLine): LineDisplay {\n const container = new Container({ label: `line-${line.id}` });\n\n const hitArea = new Graphics();\n hitArea.label = 'line-hitarea';\n hitArea.eventMode = 'static';\n hitArea.cursor = 'pointer';\n hitArea.alpha = 0.001;\n container.addChild(hitArea);\n\n const gfx = new Graphics();\n gfx.label = 'line-gfx';\n container.addChild(gfx);\n\n this.lineLayer.addChild(container);\n return { container, gfx, hitArea, lineId: line.id };\n }\n\n private _update(display: LineDisplay, line: FlowLine, selected: boolean): void {\n display.container.zIndex = line.zIndex ?? 0;\n const { gfx, hitArea } = display;\n const pts = line.points;\n if (pts.length < 2) return;\n\n const color = selected ? '#3b82f6' : resolveThemeColor(line.strokeColor, '#374151');\n const width = line.strokeWidth;\n\n gfx.clear();\n const dash = getLineDash(line.lineStyle, width);\n if (dash) {\n const offset = line.lineStyle === 'dynamic' ? this._dynamicOffset : 0;\n const drawPts = line.closed ? [...pts, pts[0]] : pts;\n drawDashedPolyline(gfx, drawPts, dash, offset);\n gfx.stroke({ color, width, cap: 'round' as const });\n } else {\n gfx.moveTo(pts[0].x, pts[0].y);\n for (let i = 1; i < pts.length; i++) {\n gfx.lineTo(pts[i].x, pts[i].y);\n }\n if (line.closed) gfx.closePath();\n gfx.stroke({ color, width });\n }\n\n // Markers\n if (line.markerStart && line.markerStart !== 'none' && pts.length >= 2) {\n const angle = angleBetween(pts[1].x, pts[1].y, pts[0].x, pts[0].y);\n drawMarker(gfx, line.markerStart, pts[0].x, pts[0].y, angle, color);\n }\n if (line.markerEnd && line.markerEnd !== 'none' && pts.length >= 2) {\n const last = pts[pts.length - 1];\n const prev = pts[pts.length - 2];\n const angle = angleBetween(prev.x, prev.y, last.x, last.y);\n drawMarker(gfx, line.markerEnd, last.x, last.y, angle, color);\n }\n\n // Hit area\n hitArea.clear();\n hitArea.moveTo(pts[0].x, pts[0].y);\n for (let i = 1; i < pts.length; i++) {\n hitArea.lineTo(pts[i].x, pts[i].y);\n }\n hitArea.stroke({ color: '#000000', width: Math.max(width + 10, 14) });\n hitArea.alpha = 0.001;\n }\n\n destroy(): void {\n for (const [, display] of this.lines) {\n display.container.destroy({ children: true });\n }\n this.lines.clear();\n this.lineLayer.destroy({ children: true });\n }\n}\n"],"mappings":";;;;AAMA,SAAS,EAAY,GAAgB,IAAQ,GAAyB;AACpE,MAAI,GAAC,KAAS,MAAU,UACxB;AAAA,QAAI,MAAU,UAAW,QAAO,CAAC,IAAQ,GAAG,IAAQ,CAAC;AACrD,QAAI,MAAU,SAAU,QAAO,CAAC,GAAO,IAAQ,CAAC;AAChD,QAAI,MAAU,SAAU,QAAO,CAAC,IAAQ,GAAG,IAAQ,CAAC;AAAA;AAEtD;AAYA,IAAa,IAAb,MAA0B;AAAA,EACxB;AAAA,EACA;AAAA,EACA,QAAgB,oBAAI,IAAyB;AAAA,EAC7C,iBAAyB;AAAA,EAGzB,iBAAiB,GAAuB;AACtC,SAAK,kBAAkB,KAAK,iBAAiB,IAAU,QAAQ;AAAA,EACjE;AAAA,EAEA,YAAY,GAAkB;AAC5B,SAAK,QAAQ,GACb,KAAK,YAAY,IAAI,EAAU;AAAA,MAAE,OAAO;AAAA,MAAS,kBAAkB;AAAA,IAAK,CAAC,GAEzE,KAAK,MAAM,WAAW,KAAK,WAAW,KAAK,IAAI,GAAG,KAAK,MAAM,SAAS,MAAM,CAAC;AAAA,EAC/E;AAAA,EAEA,KAAK,GAAuB,GAAgC;AAC1D,UAAM,IAAO,oBAAI,IAAY;AAE7B,eAAW,KAAQ,GAAW;AAC5B,MAAA,EAAK,IAAI,EAAK,EAAE;AAChB,UAAI,IAAU,KAAK,MAAM,IAAI,EAAK,EAAE;AACpC,MAAK,MACH,IAAU,KAAK,QAAQ,CAAI,GAC3B,KAAK,MAAM,IAAI,EAAK,IAAI,CAAO,IAEjC,KAAK,QAAQ,GAAS,GAAM,EAAY,IAAI,EAAK,EAAE,CAAC;AAAA,IACtD;AAEA,eAAW,CAAC,GAAI,CAAA,KAAY,KAAK,MAC/B,CAAK,EAAK,IAAI,CAAE,MACd,KAAK,UAAU,YAAY,EAAQ,SAAS,GAC5C,EAAQ,UAAU,QAAQ,EAAE,UAAU,GAAK,CAAC,GAC5C,KAAK,MAAM,OAAO,CAAE;AAAA,EAG1B;AAAA,EAEA,QAAgB,GAA6B;AAC3C,UAAM,IAAY,IAAI,EAAU,EAAE,OAAO,QAAQ,EAAK,EAAA,GAAK,CAAC,GAEtD,IAAU,IAAI,EAAS;AAC7B,IAAA,EAAQ,QAAQ,gBAChB,EAAQ,YAAY,UACpB,EAAQ,SAAS,WACjB,EAAQ,QAAQ,MAChB,EAAU,SAAS,CAAO;AAE1B,UAAM,IAAM,IAAI,EAAS;AACzB,WAAA,EAAI,QAAQ,YACZ,EAAU,SAAS,CAAG,GAEtB,KAAK,UAAU,SAAS,CAAS,GAC1B;AAAA,MAAE,WAAA;AAAA,MAAW,KAAA;AAAA,MAAK,SAAA;AAAA,MAAS,QAAQ,EAAK;AAAA,IAAG;AAAA,EACpD;AAAA,EAEA,QAAgB,GAAsB,GAAgB,GAAyB;AAC7E,IAAA,EAAQ,UAAU,SAAS,EAAK,UAAU;AAC1C,UAAM,EAAE,KAAA,GAAK,SAAA,EAAA,IAAY,GACnB,IAAM,EAAK;AACjB,QAAI,EAAI,SAAS,EAAG;AAEpB,UAAM,IAAQ,IAAW,YAAY,EAAkB,EAAK,aAAa,SAAS,GAC5E,IAAQ,EAAK;AAEnB,IAAA,EAAI,MAAM;AACV,UAAM,IAAO,EAAY,EAAK,WAAW,CAAK;AAC9C,QAAI,GAAM;AACR,YAAM,IAAS,EAAK,cAAc,YAAY,KAAK,iBAAiB
|
|
1
|
+
{"version":3,"file":"LineRenderer.js","names":[],"sources":["../../../../../src/components/pro/Flow/lines/LineRenderer.ts"],"sourcesContent":["import { Container, Graphics } from 'pixi.js';\nimport type { FlowLine } from '../types';\nimport { drawMarker, angleBetween } from '../edges/edgeMarkers';\nimport { drawDashedPolyline } from '../utils/dashedLine';\nimport { resolveThemeColor } from '../utils/themeColor';\n\nfunction getLineDash(style?: string, width = 2): number[] | undefined {\n if (!style || style === 'solid') return undefined;\n if (style === 'dynamic') return [width * 4, width * 3];\n if (style === 'dotted') return [width, width * 2];\n if (style === 'dashed') return [width * 3, width * 2];\n return undefined;\n}\n\ninterface LineDisplay {\n container: Container;\n gfx: Graphics;\n hitArea: Graphics;\n lineId: string;\n}\n\n/**\n * Renders independent FlowLine[] objects on the canvas.\n */\nexport class LineRenderer {\n private world: Container;\n private lineLayer: Container;\n private lines = new Map<string, LineDisplay>();\n private _dynamicOffset = 0;\n\n /** Call once per frame to advance the dynamic dash animation. */\n advanceAnimation(deltaMs: number): void {\n this._dynamicOffset = (this._dynamicOffset + deltaMs * 0.06) % 1000;\n }\n\n constructor(world: Container) {\n this.world = world;\n this.lineLayer = new Container({ label: 'lines', sortableChildren: true });\n // Lines on top of edges but below nodes\n this.world.addChildAt(this.lineLayer, Math.min(1, this.world.children.length));\n }\n\n sync(flowLines: FlowLine[], selectedIds: Set<string>): void {\n const seen = new Set<string>();\n\n for (const line of flowLines) {\n seen.add(line.id);\n let display = this.lines.get(line.id);\n if (!display) {\n display = this._create(line);\n this.lines.set(line.id, display);\n }\n this._update(display, line, selectedIds.has(line.id));\n }\n\n for (const [id, display] of this.lines) {\n if (!seen.has(id)) {\n this.lineLayer.removeChild(display.container);\n display.container.destroy({ children: true });\n this.lines.delete(id);\n }\n }\n }\n\n private _create(line: FlowLine): LineDisplay {\n const container = new Container({ label: `line-${line.id}` });\n\n const hitArea = new Graphics();\n hitArea.label = 'line-hitarea';\n hitArea.eventMode = 'static';\n hitArea.cursor = 'pointer';\n hitArea.alpha = 0.001;\n container.addChild(hitArea);\n\n const gfx = new Graphics();\n gfx.label = 'line-gfx';\n container.addChild(gfx);\n\n this.lineLayer.addChild(container);\n return { container, gfx, hitArea, lineId: line.id };\n }\n\n private _update(display: LineDisplay, line: FlowLine, selected: boolean): void {\n display.container.zIndex = line.zIndex ?? 0;\n const { gfx, hitArea } = display;\n const pts = line.points;\n if (pts.length < 2) return;\n\n const color = selected ? '#3b82f6' : resolveThemeColor(line.strokeColor, '#374151');\n const width = line.strokeWidth;\n\n gfx.clear();\n const dash = getLineDash(line.lineStyle, width);\n if (dash) {\n const offset = line.lineStyle === 'dynamic' ? this._dynamicOffset : 0;\n const drawPts = line.closed ? [...pts, pts[0]] : pts;\n drawDashedPolyline(gfx, drawPts, dash, offset);\n gfx.stroke({ color, width, cap: 'round' as const });\n } else {\n gfx.moveTo(pts[0].x, pts[0].y);\n for (let i = 1; i < pts.length; i++) {\n gfx.lineTo(pts[i].x, pts[i].y);\n }\n if (line.closed) gfx.closePath();\n gfx.stroke({ color, width });\n }\n\n // Markers\n if (line.markerStart && line.markerStart !== 'none' && pts.length >= 2) {\n const angle = angleBetween(pts[1].x, pts[1].y, pts[0].x, pts[0].y);\n drawMarker(gfx, line.markerStart, pts[0].x, pts[0].y, angle, color);\n }\n if (line.markerEnd && line.markerEnd !== 'none' && pts.length >= 2) {\n const last = pts[pts.length - 1];\n const prev = pts[pts.length - 2];\n const angle = angleBetween(prev.x, prev.y, last.x, last.y);\n drawMarker(gfx, line.markerEnd, last.x, last.y, angle, color);\n }\n\n // Hit area\n hitArea.clear();\n hitArea.moveTo(pts[0].x, pts[0].y);\n for (let i = 1; i < pts.length; i++) {\n hitArea.lineTo(pts[i].x, pts[i].y);\n }\n hitArea.stroke({ color: '#000000', width: Math.max(width + 10, 14) });\n hitArea.alpha = 0.001;\n }\n\n destroy(): void {\n for (const [, display] of this.lines) {\n display.container.destroy({ children: true });\n }\n this.lines.clear();\n this.lineLayer.destroy({ children: true });\n }\n}\n"],"mappings":"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"}
|
|
@@ -10,11 +10,11 @@ import { scaleLinear as h } from "@tanstack/charts/scales/linear";
|
|
|
10
10
|
import { scalePoint as k } from "@tanstack/charts/scales/point";
|
|
11
11
|
import { pie as V, polar as B, radialArc as L } from "@tanstack/charts/polar";
|
|
12
12
|
function O({ config: e }) {
|
|
13
|
-
const o = v(() => e.columns.map((r) => R(r.key, r.label ?? r.key, { enableSorting: !0 })), [e.columns]),
|
|
13
|
+
const o = v(() => e.columns.map((r) => R(r.key, r.label ?? r.key, { enableSorting: !0 })), [e.columns]), l = v(() => e.columns.map((r) => ({
|
|
14
14
|
field: r.key,
|
|
15
15
|
label: r.label ?? r.key,
|
|
16
16
|
numeric: r.type === "number"
|
|
17
|
-
})), [e.columns]), t = e.pivot,
|
|
17
|
+
})), [e.columns]), t = e.pivot, s = JSON.stringify({
|
|
18
18
|
e: !!t?.enabled,
|
|
19
19
|
r: t?.rowFields ?? [],
|
|
20
20
|
c: t?.colFields ?? [],
|
|
@@ -25,13 +25,13 @@ function O({ config: e }) {
|
|
|
25
25
|
children: /* @__PURE__ */ u(Y, {
|
|
26
26
|
config: e,
|
|
27
27
|
columns: o,
|
|
28
|
-
pivotFields:
|
|
29
|
-
},
|
|
28
|
+
pivotFields: l
|
|
29
|
+
}, s)
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
|
-
function Y({ config: e, columns: o, pivotFields:
|
|
33
|
-
const t = e.pivot,
|
|
34
|
-
fields:
|
|
32
|
+
function Y({ config: e, columns: o, pivotFields: l }) {
|
|
33
|
+
const t = e.pivot, s = F({
|
|
34
|
+
fields: l,
|
|
35
35
|
initialActive: !!t?.enabled,
|
|
36
36
|
initialRowFields: t?.rowFields ?? [],
|
|
37
37
|
initialColFields: t?.colFields ?? [],
|
|
@@ -46,132 +46,152 @@ function Y({ config: e, columns: o, pivotFields: n }) {
|
|
|
46
46
|
enableSorting: !0,
|
|
47
47
|
enablePagination: e.rows.length > 50,
|
|
48
48
|
pageSize: 50,
|
|
49
|
-
extensions: [
|
|
49
|
+
extensions: [s]
|
|
50
50
|
});
|
|
51
51
|
}
|
|
52
52
|
function _(e, o) {
|
|
53
53
|
return v(() => {
|
|
54
|
-
const
|
|
55
|
-
if (!
|
|
56
|
-
const t =
|
|
57
|
-
if (!t ||
|
|
58
|
-
const r = e.rows, f =
|
|
59
|
-
switch (
|
|
54
|
+
const l = e.chart;
|
|
55
|
+
if (!l) return null;
|
|
56
|
+
const t = l.xField, s = (l.yFields ?? []).filter(Boolean);
|
|
57
|
+
if (!t || s.length === 0) return null;
|
|
58
|
+
const r = e.rows, f = l.palette?.length ? l.palette : null, d = (a, n) => l.seriesColors?.[a] ?? f?.[n % f.length] ?? o ?? w[n % w.length];
|
|
59
|
+
switch (l.type) {
|
|
60
60
|
case "line":
|
|
61
61
|
return p({
|
|
62
|
-
|
|
63
|
-
y: {
|
|
64
|
-
scale: h,
|
|
65
|
-
nice: !0,
|
|
66
|
-
grid: !0
|
|
67
|
-
},
|
|
68
|
-
marks: i.map((a, l) => S(r, {
|
|
62
|
+
marks: s.map((a, n) => S(r, {
|
|
69
63
|
id: a,
|
|
70
64
|
x: t,
|
|
71
65
|
y: a,
|
|
72
|
-
stroke: d(a,
|
|
66
|
+
stroke: d(a, n),
|
|
73
67
|
points: !0
|
|
74
|
-
}))
|
|
68
|
+
})),
|
|
69
|
+
scales: {
|
|
70
|
+
x: { scale: () => k().padding(0.35) },
|
|
71
|
+
y: {
|
|
72
|
+
scale: h,
|
|
73
|
+
nice: !0,
|
|
74
|
+
grid: !0
|
|
75
|
+
}
|
|
76
|
+
}
|
|
75
77
|
});
|
|
76
78
|
case "area":
|
|
77
79
|
return p({
|
|
78
|
-
|
|
79
|
-
y: {
|
|
80
|
-
scale: h,
|
|
81
|
-
nice: !0,
|
|
82
|
-
grid: !0
|
|
83
|
-
},
|
|
84
|
-
marks: i.map((a, l) => T(r, {
|
|
80
|
+
marks: s.map((a, n) => T(r, {
|
|
85
81
|
id: a,
|
|
86
82
|
x: t,
|
|
87
83
|
y: a,
|
|
88
|
-
fill: d(a,
|
|
84
|
+
fill: d(a, n),
|
|
89
85
|
fillOpacity: 0.35,
|
|
90
|
-
stroke: d(a,
|
|
91
|
-
}))
|
|
86
|
+
stroke: d(a, n)
|
|
87
|
+
})),
|
|
88
|
+
scales: {
|
|
89
|
+
x: { scale: () => k().padding(0.35) },
|
|
90
|
+
y: {
|
|
91
|
+
scale: h,
|
|
92
|
+
nice: !0,
|
|
93
|
+
grid: !0
|
|
94
|
+
}
|
|
95
|
+
}
|
|
92
96
|
});
|
|
93
97
|
case "scatter":
|
|
94
98
|
return p({
|
|
95
|
-
x: {
|
|
96
|
-
scale: h,
|
|
97
|
-
nice: !0,
|
|
98
|
-
grid: !0
|
|
99
|
-
},
|
|
100
|
-
y: {
|
|
101
|
-
scale: h,
|
|
102
|
-
nice: !0,
|
|
103
|
-
grid: !0
|
|
104
|
-
},
|
|
105
99
|
marks: [P(r, {
|
|
106
100
|
id: "points",
|
|
107
101
|
x: t,
|
|
108
|
-
y:
|
|
102
|
+
y: s[0],
|
|
109
103
|
r: 6,
|
|
110
|
-
fill: d(
|
|
111
|
-
})]
|
|
104
|
+
fill: d(s[0], 0)
|
|
105
|
+
})],
|
|
106
|
+
scales: {
|
|
107
|
+
x: {
|
|
108
|
+
scale: h,
|
|
109
|
+
nice: !0,
|
|
110
|
+
grid: !0
|
|
111
|
+
},
|
|
112
|
+
y: {
|
|
113
|
+
scale: h,
|
|
114
|
+
nice: !0,
|
|
115
|
+
grid: !0
|
|
116
|
+
}
|
|
117
|
+
}
|
|
112
118
|
});
|
|
113
119
|
case "pie": {
|
|
114
|
-
const a =
|
|
115
|
-
for (const
|
|
116
|
-
const m = String(
|
|
117
|
-
|
|
120
|
+
const a = s[0], n = /* @__PURE__ */ new Map();
|
|
121
|
+
for (const i of r) {
|
|
122
|
+
const m = String(i[t] ?? "");
|
|
123
|
+
n.set(m, (n.get(m) ?? 0) + (Number(i[a]) || 0));
|
|
118
124
|
}
|
|
119
|
-
const c = Array.from(
|
|
120
|
-
cat:
|
|
125
|
+
const c = Array.from(n, ([i, m]) => ({
|
|
126
|
+
cat: i,
|
|
121
127
|
value: m
|
|
122
|
-
})), g = V(c, { value: "value" }), b =
|
|
128
|
+
})), g = V(c, { value: "value" }), b = l.palette?.length ? l.palette : w;
|
|
123
129
|
return p({
|
|
124
|
-
marks: [B({
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
marks: [B({
|
|
131
|
+
marks: [L(g, {
|
|
132
|
+
startAngle: "startAngle",
|
|
133
|
+
endAngle: "endAngle",
|
|
134
|
+
padAngle: "padAngle",
|
|
135
|
+
innerRadius: 0,
|
|
136
|
+
color: "cat",
|
|
137
|
+
key: "cat"
|
|
138
|
+
})],
|
|
139
|
+
scales: {
|
|
140
|
+
angle: null,
|
|
141
|
+
radius: null
|
|
142
|
+
}
|
|
143
|
+
})],
|
|
144
|
+
scales: {
|
|
145
|
+
x: null,
|
|
146
|
+
y: null
|
|
147
|
+
},
|
|
132
148
|
color: {
|
|
133
|
-
domain: c.map((
|
|
149
|
+
domain: c.map((i) => i.cat),
|
|
134
150
|
range: b
|
|
135
151
|
}
|
|
136
152
|
});
|
|
137
153
|
}
|
|
138
154
|
case "barHorizontal":
|
|
139
155
|
return p({
|
|
140
|
-
|
|
141
|
-
x: {
|
|
142
|
-
scale: h,
|
|
143
|
-
nice: !0,
|
|
144
|
-
grid: !0
|
|
145
|
-
},
|
|
146
|
-
marks: i.map((a, l) => M(r, {
|
|
156
|
+
marks: s.map((a, n) => M(r, {
|
|
147
157
|
id: a,
|
|
148
158
|
y: t,
|
|
149
159
|
x: a,
|
|
150
|
-
fill: d(a,
|
|
160
|
+
fill: d(a, n),
|
|
151
161
|
radius: 4
|
|
152
|
-
}))
|
|
162
|
+
})),
|
|
163
|
+
scales: {
|
|
164
|
+
y: { scale: () => x().padding(0.25) },
|
|
165
|
+
x: {
|
|
166
|
+
scale: h,
|
|
167
|
+
nice: !0,
|
|
168
|
+
grid: !0
|
|
169
|
+
}
|
|
170
|
+
}
|
|
153
171
|
});
|
|
154
172
|
default:
|
|
155
173
|
return p({
|
|
156
|
-
|
|
157
|
-
y: {
|
|
158
|
-
scale: h,
|
|
159
|
-
nice: !0,
|
|
160
|
-
grid: !0
|
|
161
|
-
},
|
|
162
|
-
marks: i.map((a, l) => N(r, {
|
|
174
|
+
marks: s.map((a, n) => N(r, {
|
|
163
175
|
id: a,
|
|
164
176
|
x: t,
|
|
165
177
|
y: a,
|
|
166
|
-
fill: d(a,
|
|
178
|
+
fill: d(a, n),
|
|
167
179
|
radius: 4
|
|
168
|
-
}))
|
|
180
|
+
})),
|
|
181
|
+
scales: {
|
|
182
|
+
x: { scale: () => x().padding(0.25) },
|
|
183
|
+
y: {
|
|
184
|
+
scale: h,
|
|
185
|
+
nice: !0,
|
|
186
|
+
grid: !0
|
|
187
|
+
}
|
|
188
|
+
}
|
|
169
189
|
});
|
|
170
190
|
}
|
|
171
191
|
}, [e, o]);
|
|
172
192
|
}
|
|
173
|
-
function j({ config: e, surfaceColor: o, textColor:
|
|
174
|
-
const
|
|
193
|
+
function j({ config: e, surfaceColor: o, textColor: l, primaryColor: t }) {
|
|
194
|
+
const s = _(e, t), r = e.chart, f = D(null), [d, a] = E({
|
|
175
195
|
w: 0,
|
|
176
196
|
h: 0
|
|
177
197
|
});
|
|
@@ -179,45 +199,45 @@ function j({ config: e, surfaceColor: o, textColor: n, primaryColor: t }) {
|
|
|
179
199
|
const c = f.current;
|
|
180
200
|
if (!c) return;
|
|
181
201
|
const g = () => {
|
|
182
|
-
const
|
|
202
|
+
const i = c.getBoundingClientRect(), m = i.width && c.offsetWidth ? i.width / c.offsetWidth : 1;
|
|
183
203
|
a({
|
|
184
|
-
w: Math.max(1, Math.round(
|
|
185
|
-
h: Math.max(1, Math.round(
|
|
204
|
+
w: Math.max(1, Math.round(i.width / (m || 1))),
|
|
205
|
+
h: Math.max(1, Math.round(i.height / (m || 1)))
|
|
186
206
|
});
|
|
187
207
|
};
|
|
188
208
|
g();
|
|
189
209
|
const b = new ResizeObserver(g);
|
|
190
210
|
return b.observe(c), () => b.disconnect();
|
|
191
|
-
}, []), !
|
|
211
|
+
}, []), !s) return /* @__PURE__ */ u("div", {
|
|
192
212
|
className: "flow-data-empty",
|
|
193
213
|
children: e.columns.length === 0 ? "尚无数据,请在属性面板上传或填写数据" : "请在属性面板选择 X 轴与至少一个数值字段"
|
|
194
214
|
});
|
|
195
|
-
const
|
|
215
|
+
const n = r && r.xField ? `${y(e.columns, r.xField)} · ${(r.yFields ?? []).map((c) => y(e.columns, c)).join(", ")}` : "Chart";
|
|
196
216
|
return /* @__PURE__ */ u("div", {
|
|
197
217
|
className: "flow-data-chart",
|
|
198
218
|
ref: f,
|
|
199
|
-
style:
|
|
219
|
+
style: l ? { color: l } : void 0,
|
|
200
220
|
children: d.h > 0 && /* @__PURE__ */ u(C, {
|
|
201
|
-
definition:
|
|
202
|
-
"aria-label":
|
|
221
|
+
definition: s,
|
|
222
|
+
"aria-label": n,
|
|
203
223
|
height: d.h,
|
|
204
224
|
style: {
|
|
205
225
|
background: o ?? "transparent",
|
|
206
226
|
borderColor: "transparent",
|
|
207
|
-
color:
|
|
227
|
+
color: l ?? "inherit",
|
|
208
228
|
padding: 0
|
|
209
229
|
}
|
|
210
230
|
})
|
|
211
231
|
});
|
|
212
232
|
}
|
|
213
|
-
function ee({ config: e, surfaceColor: o, textColor:
|
|
233
|
+
function ee({ config: e, surfaceColor: o, textColor: l, primaryColor: t }) {
|
|
214
234
|
return !e || e.columns.length === 0 ? /* @__PURE__ */ u("div", {
|
|
215
235
|
className: "flow-data-empty",
|
|
216
236
|
children: "尚无数据,请在属性面板上传或填写数据"
|
|
217
237
|
}) : e.view === "chart" ? /* @__PURE__ */ u(j, {
|
|
218
238
|
config: e,
|
|
219
239
|
surfaceColor: o,
|
|
220
|
-
textColor:
|
|
240
|
+
textColor: l,
|
|
221
241
|
primaryColor: t
|
|
222
242
|
}) : /* @__PURE__ */ u(O, { config: e });
|
|
223
243
|
}
|