@groupviz/react 2.1.3 → 2.1.4
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/index.js +866 -862
- package/index.js.map +1 -1
- package/package.json +2 -2
package/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/Canvas/SceneThemeRoot.tsx","../../../src/utils/texify.ts","../../../src/components/Canvas/SetView.tsx","../../../src/components/Canvas/CycleView.tsx","../../../src/utils/elementRef.ts","../../../src/context/cayleyActions.ts","../../../src/components/Canvas/CayleyView.tsx","../../../src/i18n/translations.ts","../../../src/i18n/I18nContext.tsx","../../../src/i18n/useTranslation.ts","../../../src/components/Canvas/CosetStripScene.tsx","../../../src/utils/download.ts","../../../src/components/Canvas/TableView.tsx","../../../src/components/Canvas/ActionScene.tsx","../../../src/components/Canvas/HomomorphismScene.tsx","../../../src/components/Canvas/SymmetryViewScene.tsx","../../../src/theme/ThemeContext.tsx","../../../src/theme/useTheme.ts","../../../src/utils/cayley3dControls.ts","../../../src/components/Canvas/Cayley3DScene.tsx","../../../src/components/Canvas/SublatticeScene.tsx","../../../src/components/Canvas/SceneWindow.tsx","../../../src/components/Canvas/SceneHoverBubble.tsx","../../../src/hooks/useSceneState.ts"],"sourcesContent":["import type { CSSProperties, ReactNode } from 'react'\n\n/**\n * SceneThemeRoot —— 视图主题作用域(FGVE「主题统一」)。\n *\n * 问题:主应用把主题做成**全局 CSS 变量**(`src/index.css` 的 `:root` /\n * `[data-theme=\"light\"]`);`@groupviz/react` 里 3D 系 Scene 各自带 `theme` prop,\n * 而全部 2D Scene 没有——外部嵌入想「单独把某张图切成浅色」只能靠外层 div 隐式挂\n * `data-theme`,且各视图行为不一致(`dark` / `theme` / 无)。\n *\n * 方案:2D Scene 统一新增 `theme?: 'dark' | 'light'`,内部用本组件包一层。\n * **缺省不传 → 直接渲染 children(零额外 DOM)**,完全保留「跟随外层主题」的既有行为,\n * 因此主应用与既有宿主不受影响;显式传值时才注入 `data-theme` 作用域,\n * 让 `theme.css` 里的浅/深色变量块在该子树内生效。\n */\nexport type SceneTheme = 'dark' | 'light'\n\nexport interface SceneThemeRootProps {\n /** 缺省 `undefined`(不注入作用域,继承外层主题) */\n theme?: SceneTheme\n children: ReactNode\n /** 附加样式(与内建 `width/height:100%` 合并,内建在前) */\n style?: CSSProperties\n className?: string\n}\n\nexport function SceneThemeRoot({ theme, children, style, className }: SceneThemeRootProps) {\n if (!theme) return <>{children}</>\n return (\n <div\n data-theme={theme}\n className={className}\n style={{\n width: '100%',\n height: '100%',\n background: 'var(--bg-canvas, #0a0a14)',\n ...style,\n }}\n >\n {children}\n </div>\n )\n}\n","import katex from 'katex'\n\nconst UNICODE_SUB: Record<string, string> = {\n '₀': '0', '₁': '1', '₂': '2', '₃': '3', '₄': '4',\n '₅': '5', '₆': '6', '₇': '7', '₈': '8', '₉': '9',\n 'ₐ': 'a', 'ₑ': 'e', 'ₒ': 'o', 'ₓ': 'x',\n 'ₙ': 'n', 'ₖ': 'k', 'ₗ': 'l', 'ₘ': 'm',\n}\n\nconst UNICODE_SUPER: Record<string, string> = {\n '⁰': '0', '¹': '1', '²': '2', '³': '3', '⁴': '4',\n '⁵': '5', '⁶': '6', '⁷': '7', '⁸': '8', '⁹': '9',\n '⁺': '+', '⁻': '-',\n}\n\nconst GREEK_MAP: Record<string, string> = {\n 'α': '\\\\alpha', 'β': '\\\\beta', 'γ': '\\\\gamma', 'δ': '\\\\delta',\n 'ε': '\\\\varepsilon', 'ζ': '\\\\zeta', 'η': '\\\\eta', 'θ': '\\\\theta',\n 'ι': '\\\\iota', 'κ': '\\\\kappa', 'λ': '\\\\lambda', 'μ': '\\\\mu',\n 'ν': '\\\\nu', 'ξ': '\\\\xi', 'π': '\\\\pi', 'ρ': '\\\\rho',\n 'σ': '\\\\sigma', 'τ': '\\\\tau', 'υ': '\\\\upsilon', 'φ': '\\\\phi',\n 'χ': '\\\\chi', 'ψ': '\\\\psi', 'ω': '\\\\omega',\n 'Α': 'A', 'Β': 'B', 'Γ': '\\\\Gamma', 'Δ': '\\\\Delta',\n 'Ε': 'E', 'Ζ': 'Z', 'Η': 'H', 'Θ': '\\\\Theta',\n 'Ι': 'I', 'Κ': 'K', 'Λ': '\\\\Lambda', 'Μ': 'M',\n 'Ν': 'N', 'Ξ': '\\\\Xi', 'Π': '\\\\Pi', 'Ρ': 'P',\n 'Σ': '\\\\Sigma', 'Τ': 'T', 'Υ': '\\\\Upsilon', 'Φ': '\\\\Phi',\n 'Χ': 'X', 'Ψ': '\\\\Psi', 'Ω': '\\\\Omega',\n}\n\nconst SPECIAL_MAP: Record<string, string> = {\n '×': '\\\\times',\n '≅': '\\\\cong',\n '→': '\\\\to',\n '∈': '\\\\in',\n '⊲': '\\\\triangleleft',\n 'ℤ': '\\\\mathbb{Z}',\n '⟨': '\\\\langle',\n '⟩': '\\\\rangle',\n '⁻': '^{-1}',\n}\n\nexport function texify(text: string): string {\n let result = ''\n\n for (let i = 0; i < text.length; i++) {\n const ch = text[i]\n const nextCh = i + 1 < text.length ? text[i + 1] : ''\n\n if (SPECIAL_MAP[ch]) {\n const tex = SPECIAL_MAP[ch]\n result += tex\n if (isBareCommand(tex) && isAlpha(nextCh)) {\n result += ' '\n }\n continue\n }\n\n if (GREEK_MAP[ch]) {\n const tex = GREEK_MAP[ch]\n result += tex\n if (isBareCommand(tex) && isAlpha(nextCh)) {\n result += ' '\n }\n continue\n }\n\n if (UNICODE_SUB[ch]) {\n result += '_{' + UNICODE_SUB[ch]\n let j = i + 1\n while (j < text.length && UNICODE_SUB[text[j]]) {\n result += UNICODE_SUB[text[j]]\n j++\n }\n result += '}'\n i = j - 1\n continue\n }\n\n if (UNICODE_SUPER[ch]) {\n result += '^{' + UNICODE_SUPER[ch]\n let j = i + 1\n while (j < text.length && UNICODE_SUPER[text[j]]) {\n result += UNICODE_SUPER[text[j]]\n j++\n }\n result += '}'\n i = j - 1\n continue\n }\n\n result += ch\n }\n\n return result\n}\n\nfunction isBareCommand(tex: string): boolean {\n if (!tex.startsWith('\\\\')) return false\n if (tex.length < 2) return false\n for (let i = 1; i < tex.length; i++) {\n const c = tex[i]\n if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) return false\n }\n return true\n}\n\nfunction isAlpha(ch: string): boolean {\n if (!ch) return false\n return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')\n}\n\nexport function renderTex(math: string, displayMode = false): string {\n try {\n return katex.renderToString(math, {\n displayMode,\n throwOnError: false,\n trust: false,\n strict: false,\n })\n } catch {\n return `<span class=\"tex-error\">${math}</span>`\n }\n}\n","import { useMemo } from 'react'\nimport { SceneThemeRoot, type SceneTheme } from './SceneThemeRoot'\nimport { texify, renderTex } from '../../utils/texify'\nimport type { Group } from '../../core/types'\nimport type { InternalEdgeData } from '../../core/types'\n\nexport interface SetViewProps {\n group: Group | null\n selectedElements: Set<string>\n canvasTransform: { x: number; y: number; scale: number }\n viewBoxSize: { width: number; height: number }\n subsets?: Array<{ elementIds: string[]; color: string }>\n selfInverseElementId?: string | null\n cosetElementMap?: Map<string, number>\n cosetHighlightSet?: Set<number>\n cosetColors?: string[]\n onSelect?: (elId: string, additive: boolean) => void\n onHover?: (el: Group['elements'][number] | null, anchor?: { x: number; y: number } | null) => void\n noGroupText?: string\n nodeRadius?: number\n gap?: number\n columns?: number\n showLabels?: boolean\n /** 节点标签自适应阈值:`group.order > 该值` 时仅选中节点显示常驻标签;缺省 60(主画布规则) */\n largeGroupThreshold?: number\n /** 视图主题作用域(`'dark' | 'light'`)。缺省不注入、跟随外层主题;显式传值时在本子树内\n * 应用 `theme.css` 对应变量块(需宿主已 `import '@groupviz/react/theme.css'`) */\n theme?: SceneTheme\n}\n\nexport function SetView(props: SetViewProps) {\n return (\n <SceneThemeRoot theme={props.theme}>\n <SetViewBody {...props} />\n </SceneThemeRoot>\n )\n}\n\nconst INNER_NODE_COLORS = [\n '#ff6b6b','#4ecdc4','#ffd93d','#a78bfa','#f97316','#06b6d4',\n '#84cc16','#f43f5e','#38bdf8','#a855f7','#14b8a6','#eab308',\n '#6366f1','#ec4899','#0ea5e9','#22c55e',\n]\n\nfunction renderCompoundNode(\n el: { cosetMemberLabels?: string[]; cosetInternalEdges?: InternalEdgeData[]; cosetInternalLayout?: { x: number; y: number }[] },\n outerR: number,\n isSelected: boolean,\n fillColor: string,\n strokeColor: string,\n strokeWidth: number,\n showInternalEdges: boolean = true,\n) {\n const members = el.cosetMemberLabels!\n const maxShow = 12\n const showCount = Math.min(members.length, maxShow)\n const innerR = Math.min(10, Math.max(4, Math.floor(outerR / (Math.max(3, Math.sqrt(showCount)) * 1.8))))\n const layoutScale = outerR * 0.72\n\n const hasLayout = el.cosetInternalLayout && el.cosetInternalLayout.length >= showCount\n const innerPos = (idx: number) => {\n if (hasLayout) {\n const p = el.cosetInternalLayout![idx]\n return { x: p.x * layoutScale, y: p.y * layoutScale }\n }\n const angle = (idx / showCount) * 2 * Math.PI - Math.PI / 2\n return {\n x: Math.cos(angle) * (outerR * 0.55),\n y: Math.sin(angle) * (outerR * 0.55),\n }\n }\n\n const circles = []\n for (let i = 0; i < showCount; i++) {\n const pos = innerPos(i)\n circles.push(\n <circle\n key={i}\n cx={pos.x}\n cy={pos.y}\n r={innerR}\n fill={INNER_NODE_COLORS[i % INNER_NODE_COLORS.length]}\n stroke=\"var(--node-stroke)\"\n strokeWidth={0.8}\n />\n )\n }\n\n const internalEdges = showInternalEdges ? el.cosetInternalEdges : undefined\n const edgeElements: React.ReactNode[] = []\n if (internalEdges && internalEdges.length > 0) {\n for (let i = 0; i < internalEdges.length; i++) {\n const edge = internalEdges[i]\n if (edge.fromInnerIdx >= showCount || edge.toInnerIdx >= showCount) continue\n const from = innerPos(edge.fromInnerIdx)\n const to = innerPos(edge.toInnerIdx)\n const dx = to.x - from.x\n const dy = to.y - from.y\n const dist = Math.sqrt(dx * dx + dy * dy)\n if (dist < 0.1) continue\n const ux = dx / dist\n const uy = dy / dist\n const sx = from.x + ux * innerR\n const sy = from.y + uy * innerR\n const ex = to.x - ux * innerR\n const ey = to.y - uy * innerR\n const midX = (sx + ex) / 2\n const midY = (sy + ey) / 2\n\n const edgeTitle = edge.actionLabel || edge.actionElementId || ''\n const titleEl = edgeTitle ? <title>{edgeTitle}</title> : null\n if (edge.isBidirectional) {\n edgeElements.push(\n <g key={`edge-${i}`}>\n <line\n x1={sx} y1={sy} x2={ex} y2={ey}\n stroke={edge.color}\n strokeWidth={1.5}\n strokeOpacity={0.75}\n strokeLinecap=\"round\"\n >{titleEl}</line>\n <line\n x1={sx} y1={sy} x2={ex} y2={ey}\n stroke=\"transparent\"\n strokeWidth={8}\n strokeLinecap=\"round\"\n style={{ pointerEvents: 'stroke' }}\n >{titleEl}</line>\n </g>\n )\n } else {\n const curveOffset = 2.5\n const nx = -uy * curveOffset\n const ny = ux * curveOffset\n const c1x = midX + nx\n const c1y = midY + ny\n const arrowSize = 2.5\n edgeElements.push(\n <g key={`edge-${i}`}>\n <path\n d={`M${sx},${sy} Q${c1x},${c1y} ${ex},${ey}`}\n stroke={edge.color}\n strokeWidth={1.5}\n strokeOpacity={0.75}\n fill=\"none\"\n >{titleEl}</path>\n <path\n d={`M${sx},${sy} Q${c1x},${c1y} ${ex},${ey}`}\n stroke=\"transparent\"\n strokeWidth={8}\n fill=\"none\"\n style={{ pointerEvents: 'stroke' }}\n >{titleEl}</path>\n </g>\n )\n const ax = ex - c1x\n const ay = ey - c1y\n const alen = Math.sqrt(ax * ax + ay * ay) || 1\n const aux = ax / alen\n const auy = ay / alen\n edgeElements.push(\n <polygon\n key={`arrow-${i}`}\n points={`${ex},${ey} ${ex - aux * arrowSize + auy * arrowSize * 0.5},${ey - auy * arrowSize - aux * arrowSize * 0.5} ${ex - aux * arrowSize - auy * arrowSize * 0.5},${ey - auy * arrowSize + aux * arrowSize * 0.5}`}\n fill={edge.color}\n stroke={edge.color}\n strokeWidth={0.5}\n />\n )\n }\n }\n }\n\n return (\n <>\n <circle\n r={outerR}\n fill={fillColor}\n stroke={strokeColor}\n strokeWidth={strokeWidth}\n strokeDasharray={isSelected ? undefined : \"4 2\"}\n filter=\"url(#node-shadow)\"\n />\n {edgeElements}\n {circles}\n {members.length > maxShow && (\n <text\n x={0} y={outerR - 2}\n textAnchor=\"middle\"\n fill=\"var(--text-secondary)\"\n fontSize={10}\n >\n +{members.length - maxShow}\n </text>\n )}\n </>\n )\n}\n\nfunction SetViewBody({\n group,\n selectedElements,\n canvasTransform,\n viewBoxSize,\n subsets,\n selfInverseElementId,\n cosetElementMap,\n cosetHighlightSet,\n cosetColors,\n onSelect,\n onHover,\n noGroupText,\n nodeRadius: nodeRadiusOverride,\n gap: gapOverride,\n columns: columnsOverride,\n showLabels: showLabelsOverride,\n largeGroupThreshold = 60,\n}: SetViewProps) {\n type SubsetView = { elementIds: string[]; color: string }\n const subsetDetailMap = useMemo(() => {\n const m = new Map<string, SubsetView>()\n subsets?.forEach(s => s.elementIds.forEach(id => { if (!m.has(id)) m.set(id, s) }))\n return m\n }, [subsets])\n\n // KaTeX 标签 HTML 开销大:每群只渲染一次(与 CayleyView 的 labelHtmlCache 一致)\n const labelHtmlCache = useMemo(() => {\n const m = new Map<string, string>()\n group?.elements.forEach(el => m.set(el.id, renderTex(texify(el.label))))\n return m\n }, [group])\n\n const cosetPalette = cosetColors ?? []\n\n if (!group) {\n return (\n <div className=\"view-empty\">\n <p>{noGroupText ?? ''}</p>\n </div>\n )\n }\n\n const isLarge = group.order > largeGroupThreshold\n const hasCompoundNodes = group.elements.some(el => el.cosetMemberLabels && el.cosetMemberLabels.length > 0)\n const nodeRadius = nodeRadiusOverride ?? (hasCompoundNodes ? 72 : 26)\n const gap = gapOverride ?? (hasCompoundNodes ? 12 : 8)\n const cellSize = nodeRadius * 2 + gap\n const cols = columnsOverride\n ? columnsOverride > 0 ? columnsOverride : Math.ceil(Math.sqrt(group.order))\n : hasCompoundNodes\n ? Math.min(group.order, Math.max(1, Math.floor(viewBoxSize.width / cellSize)))\n : Math.ceil(Math.sqrt(group.order))\n const rows = group.order / cols\n const totalWidth = cols * cellSize\n const totalHeight = rows * cellSize\n const startX = Math.max(nodeRadius, (viewBoxSize.width - totalWidth) / 2 + cellSize / 2)\n const startY = Math.max(nodeRadius, (viewBoxSize.height - totalHeight) / 2 + cellSize / 2)\n\n const getPos = (_elId: string, index: number) => {\n const col = index % cols\n const row = Math.floor(index / cols)\n return {\n x: startX + col * cellSize,\n y: startY + row * cellSize\n }\n }\n\n // Viewport culling for large groups — skip off-screen nodes\n const isNodeOnScreen = (px: number, py: number) => {\n if (!isLarge) return true\n const sx = px * canvasTransform.scale + canvasTransform.x\n const sy = py * canvasTransform.scale + canvasTransform.y\n const m = nodeRadius * canvasTransform.scale * 1.5\n return sx + m > 0 && sx - m < viewBoxSize.width &&\n sy + m > 0 && sy - m < viewBoxSize.height\n }\n\n return (\n <svg viewBox={`0 0 ${viewBoxSize.width} ${viewBoxSize.height}`} className=\"view-svg\" style={{ userSelect: 'none' }}>\n {!isLarge && (\n <defs>\n <filter id=\"node-shadow\" x=\"-30%\" y=\"-30%\" width=\"160%\" height=\"160%\">\n <feDropShadow dx=\"0\" dy=\"2\" stdDeviation=\"3\" floodColor=\"#000000\" floodOpacity=\"0.25\" />\n </filter>\n </defs>\n )}\n <g transform={`translate(${canvasTransform.x}, ${canvasTransform.y}) scale(${canvasTransform.scale})`}>\n {group.elements.map((el, i) => {\n const pos = getPos(el.id, i)\n if (!isNodeOnScreen(pos.x, pos.y)) return null\n const isSelected = selectedElements.has(el.id)\n const parentSubset = subsetDetailMap.get(el.id)\n const cosetIdx = cosetElementMap?.get(el.id)\n const isInHighlightedCoset = cosetIdx !== undefined && (cosetHighlightSet?.has(cosetIdx) ?? false)\n \n let fillColor = 'var(--node-fill)'\n let strokeColor = 'var(--node-stroke)'\n let strokeWidth = 2.5\n \n if (isSelected) {\n fillColor = 'var(--node-fill-selected)'\n strokeColor = '#ffd93d'\n strokeWidth = 3\n } else if (isInHighlightedCoset && cosetIdx !== undefined && cosetPalette[cosetIdx]) {\n fillColor = cosetPalette[cosetIdx] + '33'\n strokeColor = cosetPalette[cosetIdx]\n strokeWidth = 3\n } else if (parentSubset) {\n fillColor = parentSubset.color + '33'\n strokeColor = parentSubset.color\n strokeWidth = 2.5\n }\n \n const isCompound = !!(el.cosetMemberLabels && el.cosetMemberLabels.length > 0)\n \n return (\n <g\n key={el.id}\n transform={`translate(${pos.x}, ${pos.y})`}\n onClick={(e) => {\n e.stopPropagation()\n onSelect?.(el.id, e.ctrlKey || e.metaKey)\n }}\n onMouseEnter={() => onHover?.(el, { x: pos.x * canvasTransform.scale + canvasTransform.x, y: pos.y * canvasTransform.scale + canvasTransform.y })}\n onMouseLeave={() => onHover?.(null, null)}\n style={{ cursor: 'pointer' }}\n >\n {isCompound ? (\n renderCompoundNode(el, nodeRadius, isSelected, fillColor, strokeColor, strokeWidth, true)\n ) : (\n <>\n <circle\n r={nodeRadius}\n fill={fillColor}\n stroke={strokeColor}\n strokeWidth={strokeWidth}\n filter={isLarge ? undefined : \"url(#node-shadow)\"}\n />\n {isInHighlightedCoset && cosetIdx !== undefined && cosetPalette[cosetIdx] && (\n <circle\n r={nodeRadius}\n fill={`${cosetPalette[cosetIdx]}22`}\n stroke=\"none\"\n />\n )}\n {parentSubset && (\n <circle\n r={nodeRadius}\n fill={`${parentSubset.color}22`}\n stroke=\"none\"\n />\n )}\n{showLabelsOverride !== false && (!isLarge || isSelected || selectedElements.size === 0) && (\n <foreignObject\n x={-nodeRadius}\n y={-16}\n width={nodeRadius * 2}\n height={32}\n style={{ pointerEvents: 'none', userSelect: 'none' }}\n >\n <div\n style={{\n display: 'flex', alignItems: 'center', justifyContent: 'center',\n width: '100%', height: '100%', color: 'var(--node-text)', fontSize: isLarge ? '10px' : '15px'\n }}\n dangerouslySetInnerHTML={{\n __html: labelHtmlCache.get(el.id) ?? ''\n }}\n />\n </foreignObject>\n )}\n </>\n )}\n {isInHighlightedCoset && cosetIdx !== undefined && cosetPalette[cosetIdx] && isCompound && (\n <circle\n r={nodeRadius + 2}\n fill={`${cosetPalette[cosetIdx]}22`}\n stroke=\"none\"\n />\n )}\n {parentSubset && isCompound && (\n <circle\n r={nodeRadius + 2}\n fill={`${parentSubset.color}22`}\n stroke=\"none\"\n />\n )}\n {selfInverseElementId === el.id && (\n <g>\n <circle r={nodeRadius + 6} fill=\"none\" stroke=\"#ffd93d\" strokeWidth={2.5} strokeDasharray=\"6 3\" opacity={0.85}>\n <animate attributeName=\"stroke-dashoffset\" from=\"0\" to=\"-18\" dur=\"0.8s\" repeatCount=\"indefinite\" />\n </circle>\n <path\n d={`M ${nodeRadius + 3},-8 L ${nodeRadius + 14},-5 L ${nodeRadius + 10},-1`}\n fill=\"#ffd93d\"\n opacity={0.85}\n />\n </g>\n )}\n </g>\n )\n })}\n </g>\n </svg>\n )\n}\n","import { useCallback, useMemo, useState } from 'react'\nimport { SceneThemeRoot, type SceneTheme } from './SceneThemeRoot'\nimport { cycleGraphLayout } from '../../core/algebra/forceLayout'\nimport { texify, renderTex } from '../../utils/texify'\nimport type { CanvasTransform, Group, GroupElement, NodePosition } from '../../core/types'\n\nexport interface CycleViewProps {\n group: Group | null\n selectedElements: Set<string>\n canvasTransform: CanvasTransform\n viewBoxSize: { width: number; height: number }\n /** 缺省 false(显示全部循环子群);true 时仅显示极大循环并启用 planar 布局 */\n showMaximalCycles?: boolean\n /** 节点半径;缺省 24 */\n nodeRadius?: number\n /** 是否显示节点标签;缺省 true(>60 阶自适应) */\n showLabels?: boolean\n /** 是否显示每个循环的 ⟨g⟩ ≅ Z_n 标注;缺省 true */\n showCycleLabels?: boolean\n /** 缺省 false;true 时禁用节点拖拽(供 ViewWindow 锁定状态使用,点击选中仍保留) */\n locked?: boolean\n /** 子集着色(子集→元素映射);缺省空 */\n subsets?: Array<{ elementIds: string[]; color: string }>\n selfInverseElementId?: string | null\n cosetElementMap?: Map<string, number>\n cosetHighlightSet?: Set<number>\n cosetColors?: string[]\n /** 外部持久化节点位置(主画布共享位置);缺省使用本地拖拽态 */\n getNodePosition?: (elId: string) => NodePosition | undefined\n /** 拖拽回写节点位置;缺省写入本地拖拽态 */\n onNodePositionChange?: (elId: string, x: number, y: number) => void\n onSelect?: (elId: string, additive: boolean) => void\n onHover?: (el: GroupElement | null, anchor?: { x: number; y: number } | null) => void\n noGroupText?: string\n /** 节点标签自适应阈值:`group.order > 该值` 时仅选中节点显示常驻标签;缺省 60(主画布规则) */\n largeGroupThreshold?: number\n /** 视图主题作用域(`'dark' | 'light'`)。缺省不注入、跟随外层主题;显式传值时在本子树内\n * 应用 `theme.css` 对应变量块(需宿主已 `import '@groupviz/react/theme.css'`) */\n theme?: SceneTheme\n}\n\nexport function CycleView(props: CycleViewProps) {\n return (\n <SceneThemeRoot theme={props.theme}>\n <CycleViewBody {...props} />\n </SceneThemeRoot>\n )\n}\n\ninterface CycleEntry {\n generatorId: string\n generatorLabel: string\n elements: { id: string; label: string }[]\n order: number\n}\n\n// 每实例唯一前缀:同一文档内多个窗口 + 主画布的 <defs> filter id 不冲突\nlet _cycleViewInst = 0\n\nconst CYCLE_COLORS = ['#ff6b6b', '#4ecdc4', '#ffd93d', '#6bcb77', '#9b59b6', '#3498db', '#e67e22']\n\nfunction CycleViewBody({\n group,\n selectedElements,\n canvasTransform,\n viewBoxSize,\n showMaximalCycles = true,\n nodeRadius = 24,\n showLabels = true,\n showCycleLabels = true,\n locked = false,\n subsets,\n selfInverseElementId,\n cosetElementMap,\n cosetHighlightSet,\n cosetColors,\n getNodePosition,\n onNodePositionChange,\n onSelect,\n onHover,\n noGroupText,\n largeGroupThreshold = 60,\n}: CycleViewProps) {\n // 惰性初始化的每实例唯一前缀(useState 初始化器每实例只执行一次)\n const [filterPrefix] = useState(() => `cyv${++_cycleViewInst}`)\n\n // 本地拖拽覆盖位置(ViewWindow 无外部存储时使用)\n const posKey = group ? `${group.symbol}|${group.order}|${showMaximalCycles}` : ''\n const [dragState, setDragState] = useState<{ key: string; map: Map<string, NodePosition> }>({\n key: posKey,\n map: new Map(),\n })\n if (dragState.key !== posKey) {\n setDragState({ key: posKey, map: new Map() })\n }\n const localDragPositions = useMemo(\n () => (dragState.key === posKey ? dragState.map : new Map<string, NodePosition>()),\n [dragState, posKey],\n )\n const setLocalDragPosition = useCallback((elId: string, pos: NodePosition) => {\n setDragState(prev => {\n if (prev.key !== posKey) return prev\n const map = new Map(prev.map)\n map.set(elId, pos)\n return { key: prev.key, map }\n })\n }, [posKey])\n\n const cycles = useMemo<CycleEntry[]>(() => {\n if (!group) return []\n\n const allCycles: CycleEntry[] = []\n const visitedKeys = new Set<string>()\n\n for (const el of group.elements) {\n const subgroup: { id: string; label: string }[] = []\n const seen = new Set<string>()\n let current = el\n\n while (!seen.has(current.id)) {\n seen.add(current.id)\n subgroup.push({ id: current.id, label: current.label })\n current = group.multiply(current, el)\n }\n\n if (subgroup.length > 1) {\n const key = subgroup.map(e => e.id).sort().join(',')\n if (!visitedKeys.has(key)) {\n visitedKeys.add(key)\n allCycles.push({\n generatorId: el.id,\n generatorLabel: el.label,\n elements: subgroup,\n order: subgroup.length,\n })\n }\n }\n }\n\n if (!showMaximalCycles) {\n return allCycles.sort((a, b) => a.order - b.order)\n }\n\n const maximalCycles = allCycles.filter(cycle => {\n const cycleSet = new Set(cycle.elements.map(e => e.id))\n return !allCycles.some(other => {\n if (other.generatorId === cycle.generatorId) return false\n const otherSet = new Set(other.elements.map(e => e.id))\n return [...cycleSet].every(id => otherSet.has(id))\n })\n })\n\n return maximalCycles.sort((a, b) => a.order - b.order)\n }, [group, showMaximalCycles])\n\n const planarPositions = useMemo(() => {\n if (!group || !showMaximalCycles || cycles.length === 0) return null\n return cycleGraphLayout(\n group.elements,\n cycles.map(c => ({ elementIds: c.elements.map(e => e.id) })),\n viewBoxSize.width,\n viewBoxSize.height,\n group.identity.id,\n )\n }, [group, showMaximalCycles, cycles, viewBoxSize.width, viewBoxSize.height])\n\n const subsetDetailMap = useMemo(() => {\n const m = new Map<string, { elementIds: string[]; color: string }>()\n subsets?.forEach(s => s.elementIds.forEach(id => { if (!m.has(id)) m.set(id, s) }))\n return m\n }, [subsets])\n\n const cosetPalette = cosetColors ?? []\n\n const labelHtmlCache = useMemo(() => {\n const m = new Map<string, string>()\n group?.elements.forEach(el => m.set(el.id, renderTex(texify(el.label))))\n return m\n }, [group])\n\n if (!group) {\n return (\n <div className=\"view-empty\">\n <p>{noGroupText ?? ''}</p>\n </div>\n )\n }\n\n const isLarge = group.order > largeGroupThreshold\n const isNodeOnScreen = (px: number, py: number) => {\n if (!isLarge) return true\n const sx = px * canvasTransform.scale + canvasTransform.x\n const sy = py * canvasTransform.scale + canvasTransform.y\n const m = nodeRadius * canvasTransform.scale * 1.5\n return sx + m > 0 && sx - m < viewBoxSize.width &&\n sy + m > 0 && sy - m < viewBoxSize.height\n }\n\n const cx = viewBoxSize.width / 2\n const cy = viewBoxSize.height / 2\n const graphRadius = Math.min(viewBoxSize.width * 0.32, 160 + group.order * 16)\n\n const getPos = (elId: string): NodePosition => {\n const external = getNodePosition?.(elId)\n if (external) return external\n\n const local = localDragPositions.get(elId)\n if (local) return local\n\n if (planarPositions) {\n const p = planarPositions.get(elId)\n if (p) return p\n }\n\n const idx = group.elements.findIndex(e => e.id === elId)\n const angle = (idx * 2 * Math.PI / group.order) - Math.PI / 2\n return {\n x: cx + graphRadius * Math.cos(angle),\n y: cy + graphRadius * Math.sin(angle),\n }\n }\n\n return (\n <svg viewBox={`0 0 ${viewBoxSize.width} ${viewBoxSize.height}`} className=\"view-svg\" style={{ userSelect: 'none' }}>\n {!isLarge && (\n <defs>\n <filter id={`${filterPrefix}-node-shadow`} x=\"-30%\" y=\"-30%\" width=\"160%\" height=\"160%\">\n <feDropShadow dx=\"0\" dy=\"2\" stdDeviation=\"3\" floodColor=\"#000000\" floodOpacity=\"0.25\" />\n </filter>\n </defs>\n )}\n <g transform={`translate(${canvasTransform.x}, ${canvasTransform.y}) scale(${canvasTransform.scale})`}>\n {cycles.map((cycle, cycleIdx) => {\n const positions = cycle.elements.map(el => getPos(el.id))\n if (positions.length < 2) return null\n const pathD = positions.map((p, i) =>\n i === 0 ? `M ${p.x} ${p.y}` : `L ${p.x} ${p.y}`\n ).join(' ') + ' Z'\n\n const isHighlighted =\n selectedElements.size > 0 && cycle.elements.some(el => selectedElements.has(el.id))\n const cycleColor = CYCLE_COLORS[cycleIdx % CYCLE_COLORS.length]\n\n if (showMaximalCycles) {\n // GE 风格:细实线,无填充、无虚线、无 ⟨g⟩≅Z_n 标注;2 阶循环画成线段\n // 高亮模式(窗口点击元素后显示它所在的循环):彩色填充 + 加粗 + ⟨g⟩≅Z_n 标注\n if (positions.length === 2) {\n return (\n <line\n key={cycleIdx}\n x1={positions[0].x}\n y1={positions[0].y}\n x2={positions[1].x}\n y2={positions[1].y}\n stroke={isHighlighted ? cycleColor : 'var(--text-muted)'}\n strokeWidth={isHighlighted ? 4 : 1.5}\n strokeLinecap=\"round\"\n />\n )\n }\n const midX = positions.reduce((s, p) => s + p.x, 0) / positions.length\n const midY = positions.reduce((s, p) => s + p.y, 0) / positions.length\n return (\n <g key={cycleIdx}>\n <path\n d={pathD}\n fill={isHighlighted ? cycleColor : 'none'}\n fillOpacity={isHighlighted ? 0.18 : undefined}\n stroke={isHighlighted ? cycleColor : 'var(--text-muted)'}\n strokeWidth={isHighlighted ? 4 : 1.5}\n strokeLinejoin=\"round\"\n />\n {isHighlighted && showCycleLabels && (\n <text\n x={midX}\n y={midY - 12}\n textAnchor=\"middle\"\n fill={cycleColor}\n fontSize={10}\n fontFamily=\"serif\"\n >\n {'⟨'}{cycle.generatorLabel}{'⟩ ≅ Z'}{cycle.order}\n </text>\n )}\n </g>\n )\n }\n\n // 非极大模式:保留彩色虚线 + 循环标注(诊断对比用)\n if (!showCycleLabels) return null\n const color = CYCLE_COLORS[cycleIdx % CYCLE_COLORS.length]\n const pcx = positions.reduce((sum, p) => sum + p.x, 0) / positions.length\n const pcy = positions.reduce((sum, p) => sum + p.y, 0) / positions.length\n return (\n <g key={cycleIdx}>\n <path\n d={pathD}\n fill=\"none\"\n stroke={color}\n strokeWidth={2}\n strokeDasharray=\"6\"\n opacity={0.5}\n />\n <circle cx={pcx} cy={pcy} r={8} fill={color} opacity={0.3} />\n <text x={pcx} y={pcy - 12} textAnchor=\"middle\" fill={color} fontSize={10} fontFamily=\"serif\">\n {'⟨'}{cycle.generatorLabel}{'⟩ ≅ Z'}{cycle.order}\n </text>\n </g>\n )\n })}\n\n {group.elements.map((el) => {\n const pos = getPos(el.id)\n if (!isNodeOnScreen(pos.x, pos.y)) return null\n const isSelected = selectedElements.has(el.id)\n const parentSubset = subsetDetailMap.get(el.id)\n const cosetIdx = cosetElementMap?.get(el.id)\n const isInHighlightedCoset = cosetIdx !== undefined && (cosetHighlightSet?.has(cosetIdx) ?? false)\n\n let fillColor = 'var(--node-fill)'\n let strokeColor = 'var(--node-stroke)'\n let strokeWidth = 2.5\n\n if (isSelected) {\n fillColor = 'var(--node-fill-selected)'\n strokeColor = '#ffd93d'\n strokeWidth = 3\n } else if (isInHighlightedCoset && cosetIdx !== undefined && cosetPalette[cosetIdx]) {\n fillColor = cosetPalette[cosetIdx] + '33'\n strokeColor = cosetPalette[cosetIdx]\n strokeWidth = 3\n } else if (parentSubset) {\n fillColor = parentSubset.color + '33'\n strokeColor = parentSubset.color\n strokeWidth = 2.5\n }\n\n return (\n <g\n key={el.id}\n transform={`translate(${pos.x}, ${pos.y})`}\n onClick={(e) => {\n e.stopPropagation()\n onSelect?.(el.id, e.ctrlKey || e.metaKey)\n }}\n onMouseDown={(e) => {\n if (locked) return\n if (e.button !== 0) return\n e.stopPropagation()\n const svg = e.currentTarget.closest('svg')\n if (!svg) return\n const svgRect = svg.getBoundingClientRect()\n if (svgRect.width === 0 || svgRect.height === 0) return\n const scaleX = viewBoxSize.width / svgRect.width\n const scaleY = viewBoxSize.height / svgRect.height\n\n const startX = (e.clientX - svgRect.left) * scaleX\n const startY = (e.clientY - svgRect.top) * scaleY\n const startPos = getPos(el.id)\n\n const handleMove = (moveEvent: MouseEvent) => {\n const currentX = (moveEvent.clientX - svgRect.left) * scaleX\n const currentY = (moveEvent.clientY - svgRect.top) * scaleY\n const newX = startPos.x + (currentX - startX) / canvasTransform.scale\n const newY = startPos.y + (currentY - startY) / canvasTransform.scale\n if (onNodePositionChange) onNodePositionChange(el.id, newX, newY)\n else setLocalDragPosition(el.id, { x: newX, y: newY })\n }\n\n const handleUp = () => {\n window.removeEventListener('mousemove', handleMove)\n window.removeEventListener('mouseup', handleUp)\n }\n\n window.addEventListener('mousemove', handleMove)\n window.addEventListener('mouseup', handleUp)\n }}\n onMouseEnter={() => onHover?.(el, { x: pos.x * canvasTransform.scale + canvasTransform.x, y: pos.y * canvasTransform.scale + canvasTransform.y })}\n onMouseLeave={() => onHover?.(null, null)}\n style={{ cursor: 'grab' }}\n >\n <circle\n r={nodeRadius}\n fill={fillColor}\n stroke={strokeColor}\n strokeWidth={strokeWidth}\n filter={isLarge ? undefined : `url(#${filterPrefix}-node-shadow)`}\n />\n {parentSubset && (\n <circle\n r={nodeRadius}\n fill={`${parentSubset.color}22`}\n stroke=\"none\"\n />\n )}\n {isInHighlightedCoset && cosetIdx !== undefined && cosetPalette[cosetIdx] && (\n <circle\n r={nodeRadius}\n fill={`${cosetPalette[cosetIdx]}22`}\n stroke=\"none\"\n />\n )}\n {showLabels && (!isLarge || isSelected || selectedElements.size === 0) && (\n <foreignObject\n x={-nodeRadius}\n y={-15}\n width={nodeRadius * 2}\n height={30}\n style={{ pointerEvents: 'none', userSelect: 'none' }}\n >\n <div\n style={{\n display: 'flex', alignItems: 'center', justifyContent: 'center',\n width: '100%', height: '100%', color: 'var(--node-text)', fontSize: isLarge ? '10px' : '14px'\n }}\n dangerouslySetInnerHTML={{\n __html: labelHtmlCache.get(el.id) ?? ''\n }}\n />\n </foreignObject>\n )}\n {selfInverseElementId === el.id && (\n <g>\n <circle r={nodeRadius + 6} fill=\"none\" stroke=\"#ffd93d\" strokeWidth={2.5} strokeDasharray=\"6 3\" opacity={0.85}>\n <animate attributeName=\"stroke-dashoffset\" from=\"0\" to=\"-18\" dur=\"0.8s\" repeatCount=\"indefinite\" />\n </circle>\n <path\n d={`M ${nodeRadius + 3},-8 L ${nodeRadius + 14},-5 L ${nodeRadius + 10},-1`}\n fill=\"#ffd93d\"\n opacity={0.85}\n />\n </g>\n )}\n </g>\n )\n })}\n </g>\n </svg>\n )\n}\n","import type { Group, GroupElement } from '../core/types'\nimport { resolveElement } from '../core/algebra/elementRef'\n\n/**\n * 元素引用解析的「告警版」——把此前的**静默失败**变成一次可见的 `console.warn`。\n *\n * 用于所有「宿主经 props 传元素引用」的入口(`actionElementId` / `actions[].elementId` /\n * 陪集 H 列表 / `subsets[].elementIds`):解析不到时不再假装无事发生,而是:\n * 1. 返回 `null`,让组件走「忽略该项」的既有降级路径(渲染不炸,与反馈要求的 warn+忽略一致);\n * 2. 按 `上下文 + 群 + 引用` 去重后 `console.warn` 一次(避免每帧刷屏)。\n *\n * 需要判断「有没有解析到」但不想告警时,直接用 core 的 `resolveElement`。\n */\nconst warned = new Set<string>()\n\n/** 清空去重缓存(测试用;宿主一般不需要调用)。 */\nexport function clearElementRefWarnCache(): void {\n warned.clear()\n}\n\nexport function resolveElementWarn(\n group: Group | null | undefined,\n ref: string | null | undefined,\n context: string,\n): GroupElement | null {\n const el = resolveElement(group, ref)\n if (el) return el\n // 群本身缺席(尚未载入 / 已卸载)或引用为空属正常态,不是错误,不告警\n if (!group || ref == null || ref === '') return null\n const key = `${context}|${group.symbol}|${ref}`\n if (!warned.has(key)) {\n warned.add(key)\n console.warn(\n `[groupviz] ${context}: 元素引用 ${JSON.stringify(ref)} 在群 ${group?.symbol ?? '?'} 中解析不到` +\n `(已试 id / label / value / 循环记号四种写法),该项已忽略。`\n )\n }\n return null\n}\n\n/**\n * 批量解析元素引用(`subsets[].elementIds` / 陪集 H 这类数组入参)。\n * 保留顺序、去重、丢掉未命中项,并逐项走一次去重告警。\n */\nexport function resolveElementIdsWarn(\n group: Group | null | undefined,\n refs: readonly string[] | null | undefined,\n context: string,\n): string[] {\n if (!refs) return []\n const out: string[] = []\n const seen = new Set<string>()\n for (const ref of refs) {\n const el = resolveElementWarn(group, ref, context)\n if (!el || seen.has(el.id)) continue\n seen.add(el.id)\n out.push(el.id)\n }\n return out\n}\n","import type { Group, ViewMode, CayleyAction, Layout3D } from '../core/types'\r\nimport { COLOR_PALETTE, getDefaultLayout3D, getAvailableShapes3D, getDefaultShape2D, getAvailableShapesForView, isQuotientGroup, type CayleyShape2D } from '../core/types'\r\nimport type { CayleyActionParam } from '../core/types/viewConfig'\r\nimport { resolveElementWarn } from '../utils/elementRef'\r\n\r\nexport function getInitialCayleyActions(group: Group): CayleyAction[] {\r\n return group.generators.map((gen, i) => {\r\n const targetEl = gen.apply(group.identity)\r\n return {\r\n elementId: targetEl?.id || group.elements[0]?.id || group.identity.id,\r\n enabled: true,\r\n color: COLOR_PALETTE[i % COLOR_PALETTE.length]\r\n }\r\n })\r\n}\r\n\r\n/**\r\n * 归一化凯莱视图作用边参数:解析并过滤群中不存在的元素引用,补全 enabled(默认 true)与\r\n * color(默认 COLOR_PALETTE 按序)。actions 未提供时返回群生成元集合。\r\n * ViewWindow 参数面板与 CayleyView 渲染共用,保证两边对「当前边集合」的判定一致。\r\n *\r\n * `elementId` **接受元素引用**(`id` / `label` / `value` 串,见 `core.resolveElement`):\r\n * 传人类记号 `(234)` 不再被静默丢弃;确实解析不到时告警一次再忽略(不再无声无息)。\r\n */\r\nexport function normalizeCayleyActions(group: Group, actions?: CayleyActionParam[]): CayleyAction[] {\r\n if (!actions) return getInitialCayleyActions(group)\r\n const out: CayleyAction[] = []\r\n const seen = new Set<string>()\r\n for (const a of actions) {\r\n const el = resolveElementWarn(group, a.elementId, 'CayleyView.actions[].elementId')\r\n if (!el || seen.has(el.id)) continue\r\n seen.add(el.id)\r\n out.push({\r\n elementId: el.id,\r\n enabled: a.enabled !== false,\r\n color: a.color ?? COLOR_PALETTE[out.length % COLOR_PALETTE.length],\r\n })\r\n }\r\n return out\r\n}\r\n\r\nexport interface CayleyShapeConfig {\r\n defaultShape3D: Layout3D\r\n availableShapes3D: Layout3D[]\r\n defaultShape2D: CayleyShape2D\r\n availableShapes2D: CayleyShape2D[]\r\n}\r\n\r\nexport function getCayleyShapeConfig(group: Group): CayleyShapeConfig {\r\n if (isQuotientGroup(group)) {\r\n return {\r\n defaultShape3D: 'cone' as Layout3D,\r\n availableShapes3D: [],\r\n defaultShape2D: 'circular',\r\n availableShapes2D: ['circular'] as CayleyShape2D[],\r\n }\r\n }\r\n const defaultShape = getDefaultLayout3D(group)\r\n const shapes3D = getAvailableShapes3D(group)\r\n const shapes2D = getAvailableShapesForView(group, 'cayley') as CayleyShape2D[]\r\n const default2D = getDefaultShape2D(group)\r\n\r\n return {\r\n defaultShape3D: defaultShape,\r\n availableShapes3D: shapes3D,\r\n defaultShape2D: shapes2D.includes(default2D) ? default2D : (shapes2D[0] || 'circular'),\r\n availableShapes2D: shapes2D,\r\n }\r\n}\r\n\r\nexport function getSpecialCayleyActions(group: Group, shape: Layout3D): CayleyAction[] | null {\r\n const sym = group.symbol\r\n\r\n if (sym === 'S_{4}') {\r\n if (shape === 'rhombicuboctahedron') {\r\n return [\r\n { elementId: '4,1,2,3', enabled: true, color: COLOR_PALETTE[0] },\r\n { elementId: '3,1,2,4', enabled: true, color: COLOR_PALETTE[1] },\r\n ]\r\n } else if (shape === 'truncatedOctahedron2') {\r\n return [\r\n { elementId: '2,3,4,1', enabled: true, color: COLOR_PALETTE[0] },\r\n { elementId: '2,1,3,4', enabled: true, color: COLOR_PALETTE[1] },\r\n ]\r\n } else if (shape === 'truncatedCube') {\r\n return [\r\n { elementId: '1,4,2,3', enabled: true, color: COLOR_PALETTE[0] },\r\n { elementId: '2,1,3,4', enabled: true, color: COLOR_PALETTE[1] },\r\n ]\r\n } else if (shape === 'truncatedOctahedron3') {\r\n return [\r\n { elementId: '2,1,3,4', enabled: true, color: COLOR_PALETTE[0] },\r\n { elementId: '1,3,2,4', enabled: true, color: COLOR_PALETTE[1] },\r\n { elementId: '1,2,4,3', enabled: true, color: COLOR_PALETTE[2] },\r\n ]\r\n }\r\n }\r\n\r\n if (sym === 'A_{5}') {\r\n if (shape === 'truncatedIcosahedron') {\r\n return [\r\n { elementId: '2,3,4,5,1', enabled: true, color: COLOR_PALETTE[0] },\r\n { elementId: '2,1,4,3,5', enabled: true, color: COLOR_PALETTE[1] },\r\n ]\r\n } else if (shape === 'truncatedDodecahedron') {\r\n return [\r\n { elementId: '2,3,1,4,5', enabled: true, color: COLOR_PALETTE[0] },\r\n { elementId: '1,5,4,3,2', enabled: true, color: COLOR_PALETTE[1] },\r\n ]\r\n }\r\n }\r\n\r\n return null\r\n}\r\n\r\nexport function toggleCayleyActionReducer(prev: CayleyAction[], elementId: string): CayleyAction[] {\r\n const idx = prev.findIndex(a => a.elementId === elementId)\r\n if (idx === -1) {\r\n const colorIdx = prev.length\r\n return [...prev, { elementId, enabled: true, color: COLOR_PALETTE[colorIdx % COLOR_PALETTE.length] }]\r\n }\r\n return prev.map((a, i) => i === idx ? { ...a, enabled: !a.enabled } : a)\r\n}\r\n\r\nexport function addAllCayleyActionsHelper(\r\n group: Group,\r\n currentView: ViewMode,\r\n cayleyShape3D: Layout3D,\r\n existingActions: CayleyAction[]\r\n): CayleyAction[] {\r\n const isQuotientGroup = group.symbol.includes('/N')\r\n const canonical3D = (() => {\r\n const sym = group.symbol\r\n if (currentView !== '3d') return new Set<string>()\r\n if (sym === 'S_{4}' || sym === 'S4' || sym === 'S₄') {\r\n if (cayleyShape3D === 'rhombicuboctahedron') return new Set(['4,1,2,3', '3,1,2,4'])\r\n if (cayleyShape3D === 'truncatedOctahedron2') return new Set(['2,3,4,1', '2,1,3,4'])\r\n if (cayleyShape3D === 'truncatedCube') return new Set(['1,4,2,3', '2,1,3,4'])\r\n if (cayleyShape3D === 'truncatedOctahedron3') return new Set(['2,1,3,4', '1,3,2,4', '1,2,4,3'])\r\n }\r\n if (sym === 'A_{5}' || sym === 'A5' || sym === 'A₅') {\r\n if (cayleyShape3D === 'truncatedIcosahedron') return new Set(['2,3,4,5,1', '2,1,4,3,5'])\r\n if (cayleyShape3D === 'truncatedDodecahedron') return new Set(['2,3,1,4,5', '1,5,4,3,2'])\r\n }\r\n return new Set<string>()\r\n })()\r\n\r\n if (isQuotientGroup) {\r\n // For quotient groups, only expose generator actions so the Cayley graph\r\n // shows the quotient structure (edges between cosets), not internal\r\n // subgroup edges rendered inside compound nodes.\r\n return group.generators.map((gen, i) => {\r\n const targetEl = gen.apply(group.identity)\r\n const elementId = targetEl?.id || group.elements[0].id\r\n const existing = existingActions.find(a => a.elementId === elementId)\r\n return {\r\n elementId,\r\n enabled: existing?.enabled ?? true,\r\n color: existing?.color ?? COLOR_PALETTE[i % COLOR_PALETTE.length]\r\n }\r\n })\r\n }\r\n\r\n return group.elements.map((el, i) => {\r\n const existing = existingActions.find(a => a.elementId === el.id)\r\n const defaultEnabled = currentView === '3d'\r\n ? canonical3D.has(el.id)\r\n : group.generators.some(g => g.apply(group.identity).id === el.id)\r\n return {\r\n elementId: el.id,\r\n enabled: existing?.enabled ?? defaultEnabled,\r\n color: existing?.color ?? COLOR_PALETTE[i % COLOR_PALETTE.length]\r\n }\r\n })\r\n}\r\n","import { useCallback, useMemo, useState } from 'react'\nimport { SceneThemeRoot, type SceneTheme } from './SceneThemeRoot'\nimport { computeCayleyActionEdges, cayleyCircleLayout } from '../../core/algebra/forceLayout'\nimport { getSemidirectProductMeta, semidirectFactorMap, semidirectFixedPoints } from '../../core/algebra/semidirectDecompositions'\nimport { computeShape2DPositions } from '../../core/algebra/shapeLayouts'\nimport { texify, renderTex } from '../../utils/texify'\nimport { getDefaultShape2D } from '../../core/types'\nimport type { CanvasTransform, CayleyEdgeData, CayleyShape2D, Group, GroupElement, MultiplyType, NodePosition } from '../../core/types'\nimport type { CayleyActionParam } from '../../core/types/viewConfig'\n// 纯函数模块(无 react 依赖),FGVE 打包期随视图层迁入 core\nimport { normalizeCayleyActions } from '../../context/cayleyActions'\n\nexport interface CayleyViewProps {\n group: Group | null\n selectedElements: Set<string>\n canvasTransform: CanvasTransform\n viewBoxSize: { width: number; height: number }\n /** 缺省 getDefaultShape2D(group) */\n shape2D?: CayleyShape2D\n /** 缺省 'right'(右乘 a·c) */\n multiplyType?: MultiplyType\n /** 缺省 = 群生成元集合;条目缺省 enabled=true、color=COLOR_PALETTE 按序 */\n actions?: CayleyActionParam[]\n /** 缺省 28(与主视图非复合节点一致) */\n nodeRadius?: number\n /** 缺省 true;>60 阶沿用主视图自适应规则(选中后仅选中节点显示标签)。嵌入小窗(ViewWindow)传 false 彻底不显示节点标签、读元素靠悬停就地气泡 */\n showLabels?: boolean\n /** 缺省 false;true 时禁用节点拖拽(供 ViewWindow 锁定状态使用,点击选中仍保留) */\n locked?: boolean\n onSelect?: (elId: string, additive: boolean) => void\n /**\n * 悬停回调:第一个参数是元素,第二个是节点在 viewport 内的屏幕锚点\n * (viewBox 坐标经 canvasTransform 映射,供上层渲染\"就地气泡\"tooltip)。\n */\n onHover?: (el: GroupElement | null, anchor?: { x: number; y: number } | null) => void\n /** 当前悬停元素 id;用于在该节点外圈绘制高亮环(让\"悬停→信息\"在视觉上立得住) */\n hoveredElementId?: string | null\n noGroupText?: string\n /** 节点标签自适应阈值:`group.order > 该值` 时仅选中节点显示常驻标签;缺省 60(主画布规则) */\n largeGroupThreshold?: number\n /** 视图主题作用域(`'dark' | 'light'`)。缺省不注入、跟随外层主题;显式传值时在本子树内\n * 应用 `theme.css` 对应变量块(需宿主已 `import '@groupviz/react/theme.css'`) */\n theme?: SceneTheme\n}\n\nexport function CayleyView(props: CayleyViewProps) {\n return (\n <SceneThemeRoot theme={props.theme}>\n <CayleyViewBody {...props} />\n </SceneThemeRoot>\n )\n}\n\n/**\n * 归一化见 context/cayleyActions.ts 的 normalizeCayleyActions(渲染层与参数面板共用)。\n */\n\n// 每实例唯一前缀:同一文档内多个窗口 + 主画布的 <defs> marker/filter id 不冲突\nlet _cayleyViewInst = 0\n\nfunction renderEdgePath(\n edge: CayleyEdgeData,\n nodePositionsCache: Map<string, NodePosition>,\n nodeRadius: number,\n enabledActionIndexMap: Map<string, number>,\n isHighlighted: boolean,\n markerPrefix: string,\n) {\n const fromPos = nodePositionsCache.get(edge.fromId)\n const toPos = nodePositionsCache.get(edge.toId)\n if (!fromPos || !toPos) return null\n\n const dx = toPos.x - fromPos.x\n const dy = toPos.y - fromPos.y\n const dist = Math.sqrt(dx * dx + dy * dy)\n if (dist < 1) return null\n\n const baseColor = edge.color\n const color = isHighlighted ? baseColor : `${baseColor}99`\n\n if (edge.isSelfLoop) {\n const scx = fromPos.x\n const scy = fromPos.y - nodeRadius - 20\n return (\n <g key={`${edge.fromId}-${edge.actionElementId}`}>\n <ellipse cx={scx} cy={scy} rx={14} ry={12} fill=\"none\" stroke={color} strokeWidth={isHighlighted ? 3.5 : 2.5} />\n <polygon points={`${scx - 5},${scy - 2} ${scx + 5},${scy - 2} ${scx},${scy - 14}`} fill={baseColor} />\n </g>\n )\n }\n\n const midX = (fromPos.x + toPos.x) / 2\n const midY = (fromPos.y + toPos.y) / 2\n const nx = -dy / dist\n const ny = dx / dist\n\n const curvature = Math.min(dist * 0.08, 18)\n const ctrlX = midX + nx * curvature\n const ctrlY = midY + ny * curvature\n\n const startX = fromPos.x + (dx / dist) * nodeRadius\n const startY = fromPos.y + (dy / dist) * nodeRadius\n const endX = toPos.x - (dx / dist) * nodeRadius\n const endY = toPos.y - (dy / dist) * nodeRadius\n\n const actionIdx = enabledActionIndexMap.get(edge.actionElementId)\n const markerId = actionIdx !== undefined ? `${markerPrefix}-arrow-${actionIdx}` : undefined\n\n return (\n <path\n key={`${edge.fromId}-${edge.toId}-${edge.actionElementId}`}\n d={`M ${startX} ${startY} Q ${ctrlX} ${ctrlY} ${endX} ${endY}`}\n stroke={color}\n strokeWidth={isHighlighted ? 3.5 : 2.5}\n fill=\"none\"\n markerEnd={edge.isBidirectional || !markerId ? undefined : `url(#${markerId})`}\n opacity={0.9}\n />\n )\n}\n\nfunction CayleyViewBody({\n group,\n selectedElements,\n canvasTransform,\n viewBoxSize,\n shape2D: shapeProp,\n multiplyType: multiplyProp,\n actions: actionsProp,\n nodeRadius: nodeRadiusProp,\n showLabels: showLabelsProp,\n locked = false,\n onSelect,\n onHover,\n hoveredElementId,\n noGroupText,\n largeGroupThreshold = 60,\n}: CayleyViewProps) {\n // 惰性初始化的每实例唯一前缀(useState 初始化器每实例只执行一次)\n const [markerPrefix] = useState(() => `cv${++_cayleyViewInst}`)\n\n const n = group?.order ?? 0\n const shape: CayleyShape2D = group ? (shapeProp ?? getDefaultShape2D(group)) : 'circular'\n const multiplyType: MultiplyType = multiplyProp ?? 'right'\n const nodeRadius = nodeRadiusProp ?? 28\n const isLargeGraph = n > largeGroupThreshold\n\n const effectiveActions = useMemo(\n () => (group ? normalizeCayleyActions(group, actionsProp) : []),\n [group, actionsProp],\n )\n\n // 拖拽覆盖位置为窗口本地会话态;群/形状变化时重置(key 校验在渲染期完成,\n // 避免 key 变化后的一帧读到旧群的坐标)\n const posKey = group ? `${group.symbol}|${group.order}|${shape}` : ''\n const [dragState, setDragState] = useState<{ key: string; map: Map<string, NodePosition> }>({\n key: posKey,\n map: new Map(),\n })\n if (dragState.key !== posKey) {\n setDragState({ key: posKey, map: new Map() })\n }\n const dragPositions = useMemo(\n () => (dragState.key === posKey ? dragState.map : new Map<string, NodePosition>()),\n [dragState, posKey],\n )\n\n const setDragPositionsEntry = useCallback(\n (elId: string, pos: NodePosition) => {\n setDragState(prev => {\n if (prev.key !== posKey) return prev\n const map = new Map(prev.map)\n map.set(elId, pos)\n return { key: prev.key, map }\n })\n },\n [posKey],\n )\n\n const cx = viewBoxSize.width / 2\n const cy = viewBoxSize.height / 2\n const graphRadius = Math.min(viewBoxSize.width * 0.3, 180 + n * 10)\n\n const gridPositions = useMemo(() => {\n if (!group) return null\n return computeShape2DPositions(group, shape, viewBoxSize.width, viewBoxSize.height)\n }, [group, shape, viewBoxSize.width, viewBoxSize.height])\n\n const circLayout = useMemo(() => {\n if (!group || n === 0) return new Map<string, NodePosition>()\n return cayleyCircleLayout(group, cx, cy, graphRadius)\n }, [group, cx, cy, graphRadius, n])\n\n // rewiring 形状:半直积 φ-不动点青色高亮(与主视图同源纯计算)\n const sdMeta = useMemo(() => (group ? getSemidirectProductMeta(group) : null), [group])\n const sdFixedMap = useMemo(() => {\n const m = new Map<string, boolean>()\n if (!group || !sdMeta) return m\n const factorMap = semidirectFactorMap(group, sdMeta)\n if (!factorMap) return m\n return semidirectFixedPoints(group, sdMeta, factorMap)\n }, [group, sdMeta])\n\n const enabledActions = useMemo(() => effectiveActions.filter(a => a.enabled), [effectiveActions])\n const enabledActionIndexMap = useMemo(() => {\n const m = new Map<string, number>()\n enabledActions.forEach((a, idx) => m.set(a.elementId, idx))\n return m\n }, [enabledActions])\n\n const edges = useMemo(\n () => (group ? computeCayleyActionEdges(group, effectiveActions, multiplyType) : []),\n [group, effectiveActions, multiplyType],\n )\n\n const getNodePos = useCallback(\n (elId: string): NodePosition => {\n let defPos: NodePosition\n if (gridPositions) {\n const gp = gridPositions.get(elId)\n if (!gp) return { x: cx, y: cy }\n defPos = gp\n } else {\n const pos = circLayout.get(elId)\n if (!pos) return { x: cx, y: cy }\n defPos = pos\n }\n const saved = dragPositions.get(elId)\n if (saved && (Math.abs(saved.x - defPos.x) > 1 || Math.abs(saved.y - defPos.y) > 1)) {\n return saved\n }\n return defPos\n },\n [gridPositions, circLayout, dragPositions, cx, cy],\n )\n\n const nodePositionsCache = useMemo(() => {\n const cache = new Map<string, NodePosition>()\n if (!group) return cache\n group.elements.forEach(el => cache.set(el.id, getNodePos(el.id)))\n return cache\n }, [group, getNodePos])\n\n // KaTeX 标签 HTML 开销大:每群只渲染一次\n const labelHtmlCache = useMemo(() => {\n const m = new Map<string, string>()\n if (!group) return m\n group.elements.forEach(el => m.set(el.id, renderTex(texify(el.label))))\n return m\n }, [group])\n\n const selectedCount = useMemo(() => selectedElements.size, [selectedElements])\n\n const edgeElements = useMemo(() => {\n if (!group) return null\n return edges.map(edge =>\n renderEdgePath(edge, nodePositionsCache, nodeRadius, enabledActionIndexMap, false, markerPrefix),\n )\n }, [edges, nodePositionsCache, enabledActionIndexMap, nodeRadius, group, markerPrefix])\n\n // 选中相关边全色加粗重绘于基础边之上\n const highlightedEdges = useMemo(() => {\n if (!group || selectedElements.size === 0) return null\n return edges\n .filter(edge => selectedElements.has(edge.fromId) || selectedElements.has(edge.toId))\n .map(edge =>\n renderEdgePath(edge, nodePositionsCache, nodeRadius, enabledActionIndexMap, true, markerPrefix),\n )\n }, [edges, selectedElements, nodePositionsCache, enabledActionIndexMap, nodeRadius, group, markerPrefix])\n\n const nodeElements = useMemo(() => {\n if (!group) return null\n return group.elements.map(el => {\n const pos = nodePositionsCache.get(el.id) || { x: cx, y: cy }\n const sx = pos.x * canvasTransform.scale + canvasTransform.x\n const sy = pos.y * canvasTransform.scale + canvasTransform.y\n const cullMargin = nodeRadius * canvasTransform.scale * 1.5\n const onScreen =\n !isLargeGraph ||\n (sx + cullMargin > 0 &&\n sx - cullMargin < viewBoxSize.width &&\n sy + cullMargin > 0 &&\n sy - cullMargin < viewBoxSize.height)\n if (!onScreen) return null\n const isSdFixed = shape === 'rewiring' && !!sdMeta && sdFixedMap.get(el.id) === true\n\n let fillColor = 'var(--node-fill)'\n let strokeColor = 'var(--node-stroke)'\n let strokeWidth = 2.5\n if (isSdFixed) {\n fillColor = 'var(--accent-teal)22'\n strokeColor = 'var(--accent-teal)'\n strokeWidth = 3\n }\n\n return (\n <g\n key={el.id}\n transform={`translate(${pos.x}, ${pos.y})`}\n onClick={e => {\n e.stopPropagation()\n onSelect?.(el.id, e.ctrlKey || e.metaKey)\n }}\n onMouseDown={e => {\n if (locked) return\n if (e.button !== 0) return\n e.stopPropagation()\n const svg = e.currentTarget.closest('svg')\n if (!svg) return\n const svgRect = svg.getBoundingClientRect()\n if (svgRect.width === 0 || svgRect.height === 0) return\n const scaleX = viewBoxSize.width / svgRect.width\n const scaleY = viewBoxSize.height / svgRect.height\n const startX = (e.clientX - svgRect.left) * scaleX\n const startY = (e.clientY - svgRect.top) * scaleY\n const startPos = getNodePos(el.id)\n\n let pendingPos: NodePosition | null = null\n const rafId = { current: 0 }\n const commit = () => {\n if (pendingPos) setDragPositionsEntry(el.id, pendingPos)\n }\n const handleMove = (moveEvent: MouseEvent) => {\n const currentX = (moveEvent.clientX - svgRect.left) * scaleX\n const currentY = (moveEvent.clientY - svgRect.top) * scaleY\n pendingPos = {\n x: startPos.x + (currentX - startX) / canvasTransform.scale,\n y: startPos.y + (currentY - startY) / canvasTransform.scale,\n }\n // rAF 节流:每帧至多一次位置写入\n if (rafId.current === 0) {\n rafId.current = requestAnimationFrame(() => {\n rafId.current = 0\n commit()\n })\n }\n }\n const handleUp = () => {\n window.removeEventListener('mousemove', handleMove)\n window.removeEventListener('mouseup', handleUp)\n if (rafId.current !== 0) {\n cancelAnimationFrame(rafId.current)\n rafId.current = 0\n }\n commit()\n }\n window.addEventListener('mousemove', handleMove)\n window.addEventListener('mouseup', handleUp)\n }}\n onMouseEnter={() => onHover?.(el, { x: sx, y: sy })}\n onMouseLeave={() => onHover?.(null, null)}\n style={{ cursor: 'grab' }}\n >\n <circle\n r={nodeRadius}\n fill={fillColor}\n stroke={strokeColor}\n strokeWidth={strokeWidth}\n filter={isLargeGraph ? undefined : `url(#${markerPrefix}-node-shadow)`}\n />\n {/* 悬停高亮环:让\"我悬停的就是这个节点\"一眼可见,配合就地气泡形成\"节点环+元素名\"双重反馈 */}\n {el.id === hoveredElementId && (\n <circle\n r={nodeRadius + 5}\n fill=\"none\"\n stroke=\"#4ecdc4\"\n strokeWidth={3.5}\n opacity={0.95}\n style={{ filter: 'drop-shadow(0 0 4px rgba(78,205,196,0.7))' }}\n />\n )}\n {showLabelsProp !== false && (!isLargeGraph || selectedCount === 0) && (\n <foreignObject\n x={-nodeRadius}\n y={-16}\n width={nodeRadius * 2}\n height={32}\n style={{ pointerEvents: 'none', userSelect: 'none' }}\n >\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '100%',\n height: '100%',\n color: isSdFixed ? 'var(--accent-teal)' : 'var(--node-text)',\n fontSize: isLargeGraph ? '10px' : '15px',\n fontWeight: isSdFixed ? 700 : 400,\n }}\n dangerouslySetInnerHTML={{ __html: labelHtmlCache.get(el.id) ?? '' }}\n />\n </foreignObject>\n )}\n </g>\n )\n })\n }, [\n group, nodePositionsCache, selectedCount, sdMeta, sdFixedMap, nodeRadius, isLargeGraph,\n canvasTransform, viewBoxSize, cx, cy, labelHtmlCache, shape, getNodePos, onSelect, onHover,\n markerPrefix, showLabelsProp, setDragPositionsEntry, locked, hoveredElementId,\n ])\n\n // 选中金圈 overlay(大群时附带选中节点标签),绘制于节点之上\n const selectionOverlay = useMemo(() => {\n if (!group || selectedElements.size === 0) return null\n return [...selectedElements].map(id => {\n const pos = nodePositionsCache.get(id) || { x: cx, y: cy }\n const sx = pos.x * canvasTransform.scale + canvasTransform.x\n const sy = pos.y * canvasTransform.scale + canvasTransform.y\n const cullMargin = nodeRadius * canvasTransform.scale * 1.5\n if (\n isLargeGraph &&\n !(sx + cullMargin > 0 && sx - cullMargin < viewBoxSize.width && sy + cullMargin > 0 && sy - cullMargin < viewBoxSize.height)\n ) {\n return null\n }\n return (\n <g key={`selected-${id}`} transform={`translate(${pos.x}, ${pos.y})`}>\n <circle r={nodeRadius + 3} fill=\"none\" stroke=\"#ffd93d\" strokeWidth={3} opacity={0.95} />\n {isLargeGraph && (\n <foreignObject x={-nodeRadius} y={-16} width={nodeRadius * 2} height={32} style={{ pointerEvents: 'none', userSelect: 'none' }}>\n <div\n style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', width: '100%', height: '100%', color: 'var(--node-text)', fontSize: '10px' }}\n dangerouslySetInnerHTML={{ __html: labelHtmlCache.get(id) ?? '' }}\n />\n </foreignObject>\n )}\n </g>\n )\n })\n }, [group, selectedElements, nodePositionsCache, nodeRadius, canvasTransform, viewBoxSize, isLargeGraph, cx, cy, labelHtmlCache])\n\n if (!group) {\n return (\n <div className=\"view-empty\">\n <p>{noGroupText ?? ''}</p>\n </div>\n )\n }\n\n return (\n <svg viewBox={`0 0 ${viewBoxSize.width} ${viewBoxSize.height}`} className=\"view-svg\" style={{ userSelect: 'none' }}>\n <defs>\n <filter id={`${markerPrefix}-node-shadow`} x=\"-30%\" y=\"-30%\" width=\"160%\" height=\"160%\">\n <feDropShadow dx=\"0\" dy=\"2\" stdDeviation=\"3\" floodColor=\"#000000\" floodOpacity=\"0.25\" />\n </filter>\n {enabledActions.map((action, idx) => (\n <marker\n key={idx}\n id={`${markerPrefix}-arrow-${idx}`}\n markerWidth={10}\n markerHeight={10}\n refX={9}\n refY={3}\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path d=\"M0,0 L0,6 L9,3 z\" fill={action.color} />\n </marker>\n ))}\n </defs>\n\n <g transform={`translate(${canvasTransform.x}, ${canvasTransform.y}) scale(${canvasTransform.scale})`}>\n {edgeElements}\n {highlightedEdges}\n\n {nodeElements}\n {selectionOverlay}\n </g>\n </svg>\n )\n}\n","export type Lang = 'zh' | 'en'\n\ntype TranslationMap = Record<string, string>\n\nconst zh: TranslationMap = {\n /* App */\n 'app.title': 'GroupViz - 群论可视化',\n 'app.header': 'GroupViz - 群论可视化',\n 'ui.openToolbar': '打开工具栏',\n 'ui.openInfo': '打开信息面板',\n 'ui.computing': '计算中',\n 'theme.viewWindowDark': '视图窗口切换为浅色',\n 'theme.viewWindowLight': '视图窗口切换为深色',\n\n /* Welcome Page */\n 'welcome.subtitle': '群论可视化平台',\n 'welcome.version': 'v2.1.3',\n 'welcome.tagline': '探索抽象代数的对称之美 — 交互式群论可视化与学习工具',\n 'welcome.enter': '进入应用',\n 'welcome.section.done': '已实现',\n 'welcome.section.soon': '即将推出',\n 'welcome.item.subgroups': '子群与陪集',\n 'welcome.item.cayley': 'Cayley 图',\n 'welcome.item.table': '乘法表',\n 'welcome.item.build': '群构建系统',\n 'welcome.item.homomorphism': '同态映射',\n 'welcome.item.presentation': '群展示',\n 'welcome.soon.education': '教育模式',\n 'welcome.soon.freegroup': '自由群',\n 'welcome.soon.dlc': 'DLC(空间群/点群)',\n 'welcome.feature.subgroups': '子群与陪集',\n 'welcome.feature.cayley': 'Cayley图',\n 'welcome.feature.multigroup': '多群支持',\n 'welcome.feature.table': '乘法表',\n 'welcome.feature.3d': '3D可视化',\n 'welcome.feature.symmetry': '对称性视图',\n\n /* Left Panel — Accordion Titles */\n 'panel.createGroup': '创建群',\n 'panel.viewMode': '视图模式',\n 'panel.cayleySettings': '凯莱图设置',\n 'panel.operations': '操作与子集',\n 'panel.basicGroup': '基本群',\n 'panel.importGroup': '记号导入群',\n\n /* Left Panel — Group Types */\n 'group.cyclic': '循环群',\n 'group.cyclic.full': '循环群 Z_n',\n 'group.symmetric': '对称群',\n 'group.symmetric.full': '对称群 S_n',\n 'group.dihedral': '二面体群',\n 'group.dihedral.full': '二面体群 D_n',\n 'group.alternating': '交错群',\n 'group.alternating.full': '交错群 A_n',\n 'group.special': '特殊群',\n 'group.klein': 'Klein四元群',\n 'group.quaternion': '四元数群',\n 'group.gl2p2': 'GL(2,2) ≅ S₃,6 阶',\n 'group.gl2p3': 'GL(2,3),48 阶,|SL(2,3)| = 24',\n 'group.direct.z4z2': '直积群',\n 'group.direct.z2cubed': '初等阿贝尔群',\n 'group.direct.z3z3': '直积群',\n 'group.direct.z6z2': '直积群',\n 'group.type': '类型',\n 'group.order': '阶',\n 'panel.createByType': '按群类型创建',\n 'panel.createByOrder': '按阶创建',\n 'panel.order.semidirectHint': '符号中 \":\" 表示半直积(如 Z₃:C₄ = Dic₃)',\n\n /* Left Panel — View Modes */\n 'view.set': '集合视图',\n 'view.set.desc': '元素列表',\n 'view.cayley': '凯莱图',\n 'view.cayley.desc': '2D图',\n 'view.cycle': '循环图',\n 'view.cycle.desc': '循环结构',\n 'view.table': '乘法表',\n 'view.table.desc': 'Cayley表',\n 'view.3d': '3D凯莱图',\n 'view.3d.desc': '三维图',\n 'view.symmetry': '对称性视图',\n 'view.symmetry.desc': '多面体',\n 'view.sublattice': '子群格',\n 'view.sublattice.desc': '子群层次',\n 'view.homomorphism': '同态映射',\n 'view.homomorphism.desc': '群同态',\n 'view.cosetstrip': '陪集条带',\n 'view.cosetstrip.desc': '陪集分解',\n 'view.action': '轨道视图',\n 'view.action.desc': '群作用',\n 'view.sylow': 'Sylow',\n 'view.sylow.desc': 'p-元素与 Sylow p-子群',\n 'view.tree': '树视图',\n 'view.prestable': '展示乘法表',\n 'view.heatmap': '热力图',\n 'view.heatmap.desc': '乘法结果染色',\n\n /* Free Group Tree / Presentation Table views */\n 'prestable.noPresentation': '当前群没有可用的群展示(⟨… | …⟩)。请先在左侧「群展示」面板创建,或选择较小的群。',\n\n /* Left Panel — Buttons & Labels */\n 'panel.create': '创建 {label}',\n 'panel.multiView': '多视图模式',\n 'panel.floatView': '+ {label}',\n 'panel.showMaximalCycles': '仅显示极大循环',\n 'panel.showHeatmap': '热力图模式',\n 'panel.showAction': '显示元素操作',\n 'panel.speed': '速度',\n 'panel.solidShape': '几何体',\n 'panel.solidCube': '正方体',\n 'panel.solidOcta': '正八面体',\n 'panel.solidIcosa': '正二十面体',\n 'panel.solidDodeca': '正十二面体',\n 'panel.multiplyType': '乘法类型',\n 'panel.multiplyRight': '右乘 a·c',\n 'panel.multiplyLeft': '左乘 c·a',\n 'panel.shape': '图形状',\n 'panel.shape.circular': '圆形',\n 'panel.shape.cone': '圆锥',\n 'panel.shape.grid': '网格',\n 'panel.shape.rewiring': '重布线',\n 'panel.shape.concentric': '共轭类同心环',\n 'panel.shape.dualRing': '双环(旋转/反射)',\n 'panel.shape.cylinder': '交错同心圆',\n 'panel.shape.torus': '甜甜圈(环上挂副本)',\n 'panel.shape.ringGrid': '环网格(环×网格)',\n 'panel.shape.cosetStrip': '陪集条带',\n 'panel.shape.archimedean': '阿基米德螺旋',\n 'panel.shape.spiral': '螺旋',\n 'panel.shape.coil': '线圈',\n 'panel.shape.projection3D': '3D平面投影',\n 'panel.shape.pythagoreanSquare': '勾股正方形',\n 'panel.forceLayout': '力导向布局',\n 'panel.elementActions': '群元素作用 ({n}/{m})',\n 'panel.selectAll': '全选',\n 'panel.clear': '清除',\n 'panel.resetPositions': '重置位置',\n 'panel.decomposeSD': '半直积分解',\n 'panel.decomposeSDDisabled': '请先选择群',\n 'panel.subsetManagement': '子集管理',\n 'panel.saveAsSubset': '存为子集 ({n})',\n 'panel.clearAllSubsets': '清除所有子集',\n 'panel.showCosets': '显示陪集',\n 'panel.generateSubgroup': '生成子群 ⟨E⟩',\n 'panel.normalizer': '正规化子 N_G(E)',\n 'panel.centralizer': '中心化子 C_G(E)',\n 'panel.hideCosets': '隐藏陪集',\n 'panel.showAllCosets': '显示全部陪集',\n 'panel.showSelected': '显示选中陪集',\n 'panel.cosetType': '陪集类型',\n 'panel.indices': '指数: {index}',\n 'panel.cosetCount': '共 {count} 个陪集',\n 'panel.inverse': '求逆元',\n 'panel.clearCanvas': '清空画布',\n 'panel.exportPng': '导出 PNG',\n 'panel.exportSvg': '导出 SVG',\n 'panel.exportGif': '导出 GIF',\n 'panel.gifOption': 'GIF 旋转时长',\n 'panel.gif3s': '约 3 秒',\n 'panel.gif5Cycles': '5 个旋转周期',\n 'panel.exportView': '导出视图',\n 'panel.exporting': '导出中...',\n 'panel.selectElementFirst': '请先在画布上选中一个元素',\n 'panel.series': '子群列',\n\n /* Left Panel — Badges */\n 'badge.normal': '正规',\n 'badge.subgroup': '子群',\n 'badge.center': '中心',\n\n /* Right Panel */\n 'right.elementProps': '元素属性',\n 'right.currentElement': '当前元素',\n 'right.inverse': '逆元',\n 'right.id': 'ID',\n 'right.selectHint': '在画布上选择元素查看属性',\n 'right.groupInfo': '群信息',\n 'right.groupName': '群名',\n 'right.symbol': '符号',\n 'right.order': '阶',\n 'right.generators': '生成元',\n 'right.abelian': '阿贝尔',\n 'right.isomorphic': '同构于',\n 'right.isomorphicClick': '点击加载该同构群',\n 'right.yes': '是',\n 'right.no': '否',\n 'right.properties': '群性质',\n 'right.propertyTrue': '是',\n 'right.propertyFalse': '否',\n 'right.propertyUnavailable': '该群不支持性质分析',\n 'right.solvable': '可解',\n 'right.nilpotent': '幂零',\n 'right.perfect': '完美',\n 'right.derivedSeries': '导列',\n 'right.structure': '结构',\n 'right.structure.direct': '直积',\n 'right.structure.semidirect': '半直积',\n 'right.structure.indecomposable': '不可分解',\n 'right.structure.unknown': '未知',\n 'right.center': '中心 Z(G)',\n 'right.noGroup': '请先选择一个群',\n 'right.simpleGroup': '单群 Simple Group',\n 'right.subgroups': '子群 ({n})',\n 'right.noSubgroups': '无子群',\n 'right.loadingBackend': '正在从后端计算群结构...',\n 'right.conjugacyClasses': '共轭类 ({n})',\n 'right.noClasses': '无共轭类',\n 'right.elementList': '元素列表 ({n})',\n 'right.homomorphism': '群同态',\n 'right.homo.kernel': '核 Ker',\n 'right.homo.image': '像 Im',\n 'right.homo.quotient': '商群 G/Ker',\n 'right.homo.noActive': '暂无激活的同态映射',\n 'right.automorphismMapping': '自同构映射',\n 'right.automorphismFixed': '个不动点',\n\n /* Subgroup Lattice */\n 'lattice.trivial': '平凡群',\n 'lattice.subgroup': '子群',\n 'lattice.sylow': 'Sylow {p}-子群',\n 'lattice.labelDetail': '标签细节',\n 'lattice.label.auto': '自动',\n 'lattice.label.full': '完整名片',\n 'lattice.label.compact': '胶囊',\n 'lattice.label.dots': '圆点',\n 'lattice.mergeConjugates': '合并共轭子群',\n 'lattice.mergeHint': '同一共轭轨道的子群合成一个节点,角标 ×n = |G : N_G(H)|',\n 'lattice.nodeSize': '名片大小',\n 'lattice.showSeriesPanel': '子群列面板',\n 'lattice.orbitMembers': '{n} 个共轭子群',\n 'lattice.captionHint': '悬停或点击子群节点查看结构、指数与正规化子',\n 'lattice.mergeTooLarge': '子群数超过合并上限,已回退为未合并的子群格',\n 'lattice.backendOnly': '子群格需后端计算(超过 60 阶的群),请在主工作台中查看',\n\n /* Subgroup Series */\n 'series.off': '关闭',\n 'series.derived': '导列',\n 'series.upperCentral': '上中心列',\n 'series.lowerCentral': '下中心列',\n 'series.composition': '合成列',\n 'series.chain': '合成列链',\n 'series.alternativeChains': '共 {n} 条合成列',\n 'series.factors': '合成因子',\n 'series.jordanHolder': 'Jordan–Hölder:因子多重集唯一',\n 'series.solvable': '可解',\n 'series.nilpotent': '幂零',\n 'series.tooLarge': '群阶超过 240,跳过本地系列计算',\n 'series.loading': '后端(GAP)计算系列中…',\n 'series.truncated': '合成列超过 20 条,仅展示前 20 条',\n\n /* Cayley 3D Legend */\n 'cayley3d.multiplyRight': '右乘',\n 'cayley3d.multiplyLeft': '左乘',\n 'cayley3d.autoRotate': '自动旋转',\n 'cayley3d.resetView': '复位视图',\n\n /* Symmetry View */\n 'symmetry.reset': '复位中...',\n 'symmetry.rotating': '旋转中...',\n 'symmetry.clickHint': '点击元素查看其在几何体上的对称作用',\n 'symmetry.selectHint': '在画布上选中元素以查看其在几何体上的作用',\n 'symmetry.demoOff': '元素操作演示已关闭',\n 'symmetry.unsupported': '此群类型暂不支持对称性视图',\n 'symmetry.supported': '支持的群:循环群 C_n · 二面体群 D_n · A_4 · S_4 · A_5 · V_4',\n 'symmetry.toCube': '→ 正方体',\n 'symmetry.toOctahedron': '→ 正八面体',\n 'symmetry.toIcosahedron': '→ 正二十面体',\n 'symmetry.toDodecahedron': '→ 正十二面体',\n\n /* Symmetry Geometry Descriptions (形状名,群符号已在场景标题行单独显示) */\n 'symmetry.geo.cyclicText': '{n}阶旋转对称',\n 'symmetry.geo.dihedralText': '正{n}边形',\n 'symmetry.geo.tetrahedron': '正四面体',\n 'symmetry.geo.cube': '正方体',\n 'symmetry.geo.octahedron': '正八面体',\n 'symmetry.geo.icosahedron': '正二十面体',\n 'symmetry.geo.dodecahedron': '正十二面体',\n 'symmetry.geo.rectangle': '长方形',\n\n /* Canvas Common */\n 'canvas.noGroup': '请先选择一个群',\n 'canvas.noGroupCreate': '请先创建或选择一个群',\n 'canvas.orderTooLarge': '群阶数太大 (|G| = {n})',\n 'canvas.show': '显示',\n 'canvas.hintBox': '提示信息',\n 'canvas.history': '操作历史',\n 'canvas.cosetStripNoSubgroup': '请选择一个子群以查看陪集',\n 'canvas.cosetStripNoCosets': '在右侧面板点击一个子群以查看陪集',\n 'canvas.cosetStripCayley': '子群凯莱图 ⟨H⟩',\n 'canvas.tableSampled': '大群仅显示采样行列',\n\n /* TableView */\n 'table.footer1': '列 × 行 = 结果',\n 'table.footer2': '颜色对应结果元素',\n 'table.strategy.subgroup': '子群展示',\n 'table.strategy.random': '随机展示',\n 'table.strategy.full': '全量展示',\n 'table.subgroupCaption': '子群 {label}(|H| = {order})',\n 'table.randomCaption': '随机采样 {n} 个元素',\n 'table.heatmapAggCaption': '完整乘法表 |G| = {n},热力图缩略 {res}×{res}(众数色块)',\n 'table.fullConfirmTitle': '全量展示确认',\n 'table.fullConfirmMsg': '该群阶数 |G| = {n},全量展示将进入全屏模式并可能占用较多内存。确定继续吗?',\n 'table.confirmOk': '确定',\n 'table.confirmCancel': '取消',\n 'table.fullTitle': '{symbol} — 完整乘法表(|G| = {n})',\n 'table.fullExit': '退出全屏',\n 'table.fullExport': '导出 SVG',\n 'table.fullZoomIn': '放大',\n 'table.fullZoomOut': '缩小',\n 'table.fullZoomReset': '重置缩放',\n 'table.zoomSlider': '缩放滑块',\n 'table.fullPlaceholderMsg': '全量乘法表 |G| = {n} 较大,已切换至全屏模式',\n 'table.fullEnter': '进入全屏',\n\n /* Hint Messages */\n 'cayley.action.enabled': '已启用',\n 'cayley.action.disabled': '已禁用',\n 'cayley.action.byElement': '按元素',\n 'hint.cayleyActionNonGenerator': '本应用的凯莱边由任意元素作用定义(不限于生成元)',\n 'hint.groupSelected': '已选择群 {name}(阶 = {order})',\n 'hint.groupCleared': '已清空当前群',\n 'hint.cayley': '凯莱图 — 拖拽节点可移动 | {count} 个边作用元素 | {type}',\n 'hint.cayley3d': '3D凯莱图 — 拖拽旋转,滚轮缩放 | {count} 个边 | 形状: {shape}',\n 'hint.symmetry': '对称性视图 — 展示群的几何对称对象 | 拖拽旋转,滚轮缩放',\n 'hint.sublattice': '子群格 — 点击子群节点选中对应元素 | 拖拽平移,滚轮缩放',\n 'hint.cycle': '循环图 — 每个多边形是一个循环子群 ⟨g⟩ ≅ Z<sub>n</sub>',\n 'hint.tree': '树视图 — 展示 ⟨S|R⟩ 的退化树(商群凯莱图的 BFS 生成树):实线=生成树边(按生成元着色);粘合边不绘制,顶部栏显示粘合边计数 | 滚轮缩放、拖拽平移、双击复位、点击节点显示词',\n 'hint.prestable': '展示乘法表 — 行 × 列 = 结果,点击格子选中元素',\n 'hint.switchedTo': '已切换到 {viewLabel}',\n 'hint.elementSelected': '已选择: {label}',\n 'hint.layoutDone': '布局优化完成',\n 'hint.layoutComputing': '正在计算布局...',\n 'hint.cayleyMultiply': 'Cayley图乘法类型: {label}',\n 'hint.cayleyCleared': 'Cayley图已清除所有边',\n 'hint.cayleyShape': '3D凯莱图形状: {shape}',\n 'hint.subsetSaved': '已存储子集: {label}({n} 个元素)',\n 'hint.symmetryAction': '显示元素操作: {label}',\n 'hint.multiViewOn': '视图多开已开启 — 点击视图按钮打开悬浮窗',\n 'hint.multiViewOff': '视图多开已关闭 — 所有悬浮视图已关闭',\n 'hint.cosetShow': '陪集模式 — 选中元素的陪集高亮 | 子群: {label} (阶={order})',\n 'hint.cosetHide': '陪集模式已关闭',\n 'hint.cosetType': '陪集类型: {label}',\n 'hint.cosetAll': '显示全部陪集 — 验证拉格朗日定理: |G| = |H| × [G:H]',\n 'hint.cosetSelect': '选中元素以显示对应陪集',\n 'hint.layoutFailed': '布局优化失败,请重试',\n 'hint.quotientCreated': '已创建商群 {symbol}(阶 = {order})',\n 'hint.quotientCreatedIso': '已创建商群 {symbol}(阶 = {order})— 同构于 {isoSymbol}',\n 'hint.automorphismComputed': '已计算自同构群 Aut({symbol})(阶 = {order})',\n 'hint.automorphismComputedIso': '已计算自同构群 Aut({symbol})(阶 = {order})— 同构于 {isoSymbol}',\n\n /* Operation History */\n 'op.loadGroup': '加载群 {name} (阶={order})',\n 'op.switchView': '切换视图: {view}',\n 'op.layout': '布局优化: {view}',\n 'op.checkSubset': '检验子集: {label}',\n 'op.inverseRequest': '请选择一个元素求逆元',\n 'op.inverseDone': '求逆元: ({label})^{-1} = {result}',\n 'op.clearCanvas': '清空画布',\n 'op.generateSubgroup': '生成子群 (待实现)',\n 'op.setCayleyMultiply': '设置Cayley乘法: {label}',\n 'op.clearCayley': '清除Cayley图边',\n 'op.setShape': '设置3D形状: {shape}',\n 'op.saveSubset': '存为子集: {label} ({n} 个元素)',\n 'op.removeSubset': '删除子集',\n 'op.clearSubsets': '清除所有子集',\n 'op.multiViewOn': '开启视图多开',\n 'op.multiViewOff': '关闭视图多开',\n 'op.openFloatView': '打开悬浮视图: {viewLabel}',\n 'op.cosetShow': '显示陪集: {label}',\n 'op.cosetHide': '隐藏陪集',\n 'op.cosetType': '切换陪集类型: {label}',\n 'op.cosetAll': '显示全部陪集',\n 'op.cosetSelect': '按选中元素显示陪集',\n 'op.createQuotient': '创建商群 {parent}(阶 = {order})',\n 'op.removeQuotient': '删除商群',\n 'op.computedAutomorphism': '计算自同构群 Aut({symbol})(阶 = {order})',\n 'op.removeAutomorphism': '删除自同构群',\n\n /* Subset Results */\n 'subset.plain': '普通子集',\n 'subset.subgroup': '子群',\n 'subset.normalSubgroup': '正规子群',\n\n /* Coset */\n 'coset.left': '左陪集',\n 'coset.right': '右陪集',\n\n /* Language Toggle */\n 'lang.zh': '简体中文',\n 'lang.en': 'English',\n\n /* Direct Product */\n 'dp.title': '直积',\n 'dp.mode': '创建方式',\n 'dp.mode.cayley': '凯莱图',\n 'dp.mode.table': '乘法表',\n 'dp.mode.direct': '直接创建',\n 'dp.sourceGroup': 'G',\n 'dp.targetGroup': 'H',\n 'dp.selectGroup': '选择群...',\n 'dp.importGroup': '导入群',\n 'dp.createDirectProduct': '创建直积 G×H',\n 'dp.storeGroup': '储存直积群',\n 'dp.groupList': '直积群列表',\n 'dp.noGroups': '暂无直积群',\n 'dp.enterMode': '进入直积视图',\n 'dp.exitMode': '退出直积视图',\n 'dp.workspace': '直积工作区',\n 'dp.dragHint': '将一个群拖放到另一个群的节点上以创建直积',\n 'dp.tableDragHint': '将 H 的元素拖放到 G 来执行直积',\n 'dp.creating': '创建直积群...',\n 'dp.created': '已创建直积群: {symbol} (阶={order})',\n 'dp.selectBoth': '请先导入 G 和 H',\n 'dp.animation': '直积动画演示中...',\n 'dp.orderTooLarge': '直积群阶数过大 ({n})',\n 'dp.directHint': '选择两个群类型来创建直积群',\n 'dp.paramN': '参数 n',\n 'dp.paramM': '参数 m',\n 'dp.create': '创建 {a} × {b}',\n 'dp.storeHint': '已储存直积群: {symbol}',\n 'dp.removeHint': '已移除直积群: {symbol}',\n 'dp.exportGif': '导出 GIF',\n 'dp.exporting': '导出中...',\n 'dp.exportCayleyHint': '导出动图: 外环 = {tgt} (H), 内部嵌套 = {src} (G) → 直积群',\n\n /* Semidirect Product */\n 'sd.title': '半直积',\n 'sd.enterMode': '进入半直积模式',\n 'sd.exitMode': '退出半直积模式',\n 'sd.normalSubgroup': '正规子群 N',\n 'sd.actingGroup': '作用群 H',\n 'sd.importAsN': '导入当前群为 N',\n 'sd.importAsH': '导入当前群为 H',\n 'sd.computeAut': '计算 Aut(N)',\n 'sd.autComputed': 'Aut(N) 已计算,共 {n} 个自同构',\n 'sd.autTooLarge': 'Aut(N) 太大,无法计算',\n 'sd.phiMapping': 'φ: H → Aut(N) 生成元映射',\n 'sd.expandPhi': '扩张 φ 到全体',\n 'sd.phiValid': 'φ 是同态',\n 'sd.phiInvalid': 'φ 不满足同态条件',\n 'sd.create': '创建半直积 N ⋊_φ H',\n 'sd.storeGroup': '储存半直积群',\n 'sd.groupList': '半直积群列表',\n 'sd.noGroups': '暂无半直积群',\n 'sd.selectGroup': '选择群...',\n 'sd.selectBoth': '请先选择 N 和 H',\n 'sd.selectNFirst': '请先选择正规子群 N',\n 'sd.selectBothInPanel': '请在左侧面板选择 N 和 H',\n 'sd.mapAllGens': '请为所有生成元设置映射',\n 'sd.extendFailed': 'φ 扩张失败',\n 'sd.orderTooLarge': '半直积群阶数过大 ({n})',\n 'sd.createFailed': '半直积群创建失败',\n 'sd.storeHint': '已储存半直积群: {symbol}',\n 'sd.removeHint': '已移除半直积群: {symbol}',\n 'sd.created': '已创建半直积群: {symbol} (阶={order})',\n 'sd.decomposeHint': '已导入半直积分解: {symbol},N/H 与 φ 已就绪',\n 'sd.decomposeTitle': '半直积分解',\n 'sd.decomposeCount': '找到 {n} 个半直积分解,已自动载入第 1 个',\n 'sd.decomposeSES': '分裂短正合列',\n 'sd.decomposeVerified': '已验证(重建群同构)',\n 'sd.decomposeUnverified': '未验证(重建群结构不符)',\n 'sd.decomposeSelect': '点击载入该分解',\n 'sd.noDecomposition': '群 {symbol} 没有半直积分解(无正规子群 N 与互补子群 H 满足 N∩H={e})',\n 'sd.dragHint': '拖拽中心 + 以构建半直积',\n 'sd.clickCreate': '配置好 φ 后点击下方按钮创建',\n 'sd.finish': '完成',\n 'sd.phase1': '第一步:从作用群 H 的凯莱图开始(骨架)',\n 'sd.phase2': '第二步:结点膨胀,嵌入按 φ(h) 重布线的副本',\n 'sd.phase3': '第三步:用 H 的箭头连接各副本的对应结点',\n 'sd.phase4': '第四步:半直积群完成',\n 'sd.autoPlay': '自动播放',\n 'sd.phaseTitle': '半直积动画',\n 'sd.dropToCreate': '松开以创建 N ⋊_φ H',\n 'pres.title': '群展示',\n 'pres.placeholder': '输入群展示…(例:⟨a, b | a², b³, (ab)³⟩ 或 ⟨a | a^4⟩)',\n 'pres.presets': '预设展示',\n 'pres.create': '创建群',\n 'pres.clear': '清除',\n 'pres.preview': '预览',\n 'pres.groups': '已创建的展示群',\n 'pres.noGroups': '暂无展示群',\n 'pres.created': '已创建群:{symbol}(阶={order})',\n 'pres.createdIso': '已创建群:{symbol}(阶={order},同构于 {iso})',\n 'pres.error.parse': '语法错误:{msg}',\n 'pres.error.parseText': '展示无效:请检查生成元与关系词',\n 'pres.error.infinite': '该展示定义的是无限群',\n 'pres.error.overflow': '群过大或陪集枚举超限',\n 'pres.error.unconnected': '生成元作用不连通(生成元未生成整个群)',\n 'pres.error.empty': '请输入群展示',\n 'pres.storeHint': '已储存展示群:{symbol}',\n 'pres.removeHint': '已移除展示群:{symbol}',\n 'pres.loadHint': '已加载展示群:{symbol}(阶={order})',\n 'pres.views': '展示视图',\n 'pres.create.tabDirect': '直接创建',\n 'pres.create.tabVisual': '可视化创建',\n 'pres.clearGroup': '清空当前群(回到模板树)',\n 'pres.visual.template': '生成元模板',\n 'importGroup.placeholder': '输入群记号,如 PSL(2,7)、C_3×D_4 或 SmallGroup(16,13)',\n 'importGroup.samples': '示例',\n 'importGroup.order': '阶',\n 'importGroup.orderUnknown': '阶未知',\n 'importGroup.pathLocal': '本地直接创建',\n 'importGroup.pathBackend': '后端 GAP 导入',\n 'importGroup.import': '导入群',\n 'importGroup.loading': '导入中…',\n 'importGroup.error.empty': '请输入群记号',\n 'importGroup.error.semidirect': '半直积记号需要自同态 φ,请改用 SmallGroup(n,i) 记号',\n 'importGroup.error.unknown': '无法识别的群记号',\n 'importGroup.error.noRoute': '该记号既不能本地创建也没有可用的 GAP 路径',\n 'importGroup.error.backend': '后端未运行或 GAP 不可用,请先启动后端服务',\n 'importGroup.error.fetch': '导入失败:{msg}',\n 'pres.visual.relation': '输入一条关系(f = e 或 f1 = f2)',\n 'pres.visual.relationPlaceholder': '例 a^3=e 或 ab=ba',\n 'pres.visual.add': '确定',\n 'pres.visual.list': '已添加关系',\n 'pres.visual.finish': '结束并创建群 → 查看退化树',\n 'pres.visual.invalid': '关系格式需为 f=e 或 f1=f2(词由生成元组成,支持 ^n 与 ⁻¹)',\n 'pres.visual.infinite': '当前关系集为无限群,无法创建',\n 'pres.visual.order': '|G| = {n}',\n 'right.presentation': '群展示',\n\n /* Homomorphism */\n 'homo.title': '群同态',\n 'homo.source': '定义域 G',\n 'homo.target': '陪域 H',\n 'homo.savedList': '已保存同态 ({n})',\n 'homo.activate': '激活',\n 'homo.autoMap': '自动映射',\n 'homo.trivial': '平凡映射',\n 'homo.projection': '自然投影',\n 'homo.dpProjection': '直积投影 ({factor})',\n 'homo.generatorHint': '在画布上拖拽元素来定义生成元映射',\n 'homo.fullPreview': '完整预览 ({m}/{n})',\n 'homo.verify': '验证同态',\n 'homo.clear': '清除',\n 'homo.create': '保存同态',\n 'homo.openView': '打开同态视图',\n 'homo.viewSection': '同态视图',\n 'homo.valid': '同态成立',\n 'homo.invalid': '不满足同态条件',\n 'homo.kernel': '核 Ker',\n 'homo.image': '像 Im',\n 'homo.injective': '单射',\n 'homo.notInjective': '非单射',\n 'homo.surjective': '满射',\n 'homo.notSurjective': '非满射',\n 'homo.isomorphism': '同构',\n 'homo.firstIso': '第一同构定理',\n 'homo.theoremMode': '定理模式 →',\n 'homo.firstIso.needValid': '需要一个有效的同态映射',\n 'homo.firstIso.needValidHint': '请先验证同态映射',\n 'homo.firstIso.phase0': 'f: G \\\\to H',\n 'homo.firstIso.phase1': 'K = \\\\ker f \\\\subsetneq G',\n 'homo.firstIso.phase2': '\\\\pi: G \\\\to G/K',\n 'homo.firstIso.phase3': 'G/K \\\\cong \\\\operatorname{Im} f',\n 'homo.firstIso.phase0Desc': '同态 f 将 G 中的运算保持地映到 H',\n 'homo.firstIso.phase1Desc': '核 K 是所有映到单位元的元素,且 K 是正规子群',\n 'homo.firstIso.phase2Desc': '自然投影 π 把 G 压成商群 G/K,陪集按纤维着色',\n 'homo.firstIso.phase3Desc': '第一同构定理:G/K ≅ Im f,由 f 诱导的商群同构',\n 'homo.selectSourceFirst': '请先选择定义域群',\n 'homo.interactiveHint': '拖拽元素来定义映射',\n 'homo.created': '已创建同态: {source} → {target}',\n 'homo.verified': '同态验证通过: {source} → {target}',\n 'homo.saved': '同态已保存',\n 'homo.trivialApplied': '已应用平凡映射',\n 'homo.projectionApplied': '已应用自然投影',\n 'homo.projectionFailed': '投影映射失败: 没有正规子群',\n 'homo.inclusionApplied': '已应用包含映射',\n 'homo.inclusionFailed': '包含映射失败',\n 'homo.dpProjectionApplied': '已应用直积投影 ({factor})',\n 'homo.dpProjectionFailed': '直积投影失败',\n\n /* Quotient */\n 'quotient.title': '商群',\n 'quotient.boundHint': '选择一个正规子群来构建商群 G/N',\n 'quotient.create': '创建商群',\n 'quotient.load': '加载',\n 'quotient.noQuotient': '暂无商群',\n\n /* Automorphism */\n 'automorphism.title': '自同构群',\n 'automorphism.boundHint': '计算当前群的自同构群 Aut(G)',\n 'automorphism.compute': '计算 Aut(G)',\n 'automorphism.load': '加载',\n 'automorphism.noAutomorphism': '暂无自同构群',\n\n /* Group Action */\n 'action.title': '群作用',\n 'action.kind.conjugation': '共轭作用',\n 'action.kind.custom': '自定义作用',\n 'action.kind.sylow': 'Sylow {p}-子群共轭作用',\n 'action.kind.regular': '左平移作用(正则表示)',\n 'action.kind.coset': '陪集作用',\n 'action.create.conjugation': '共轭作用',\n 'action.create.custom': '自定义作用',\n 'action.create.regular': '左平移(Cayley)',\n 'action.create.coset': '陪集作用',\n 'action.create.sylow': 'Sylow p-作用',\n 'action.setSize': '集合大小 |X|',\n 'action.startEdit': '开始编辑',\n 'action.editHint': '点击元素选择起点,箭头跟随鼠标移动,点击目标元素部署(选中生成元后直接绑定);点击起点自身 = 固定点(自环);点击已部署箭头删除;点击空白取消',\n 'action.genSelectHint': '拖动生成元到虚线箭头上,或点击生成元选中后点击虚线完成绑定',\n 'action.dropHint': '松开以绑定',\n 'action.cycleCandidates': '候选循环:',\n 'action.cycleUnit': '循环',\n 'action.editingSource': '选择 {x} 的去向',\n 'action.finish': '完成并验证',\n 'action.clear': '清除',\n 'action.exit': '退出编辑',\n 'action.valid': '同态成立,作用合法',\n 'action.invalid': '不满足同态条件,作用不合法',\n 'action.draftRestored': '已恢复上次保存的自定义作用草稿',\n 'action.saved': '自定义群作用已保存到列表',\n 'action.activated': '已恢复群作用',\n 'action.savedList': '已保存的群作用',\n 'action.activate': '激活',\n 'action.created': '已创建{kind}',\n 'action.violation': 'Φ({g}·{a}) ≠ Φ({g})∘Φ({a})(在 {x} 处)',\n 'action.orbitCount': '轨道数: {n}',\n 'action.fixedPoints': '稳定元: {n}',\n 'action.sumCheck': 'Σ|Orb| = |X|: {sum} = {n}',\n 'action.ost': '|Orb(x)|·|Stab(x)| = {orbit}·{stab} = {product} = |G|',\n 'action.stabilizer': 'Stab({x})',\n 'action.orbitStab': '|Orb({x})| = {orbit},|Stab({x})| = {stab}',\n 'action.noAction': '在左侧面板创建群作用',\n 'action.error.range': '箭头 {from}→{to} 超出集合范围',\n 'action.error.unbound': '存在未绑定的箭头',\n 'action.error.duplicate-source': '生成元 {gen} 重复指定了源 {from}',\n 'action.error.conflict-target': '生成元 {gen} 的目标 {to} 被多个源指向',\n 'action.error.missing-target': '目标 {to} 需要去向:{gen} 未定义它的像',\n 'action.error.unknown-generator': '未知生成元: {gen}',\n 'action.error.homomorphism': '不满足同态:Φ({g}·{gen}) ≠ Φ({g})∘Φ({gen})(在 {x} 处),请修正箭头',\n 'action.viewBlurb': '每个圆圈 = 一个轨道(共轭作用时即共轭类);弧线 = 生成元的作用,颜色对应生成元',\n 'action.showing': '正在显示元素 ',\n 'action.conjSuffix': ' 的共轭作用:x ↦ g·x·g⁻¹',\n 'action.arrowSuffix': ' 的全部作用箭头',\n 'action.orbitGroup': '轨道 · {size} 元素',\n 'action.viewTitle.conjugation': '共轭作用:G 作用于自身,g·x = g·x·g⁻¹(轨道 = 共轭类)',\n 'action.viewTitle.custom': '自定义作用:G 作用于集合 X',\n 'action.viewTitle.sylow': 'Sylow {p}-子群:G 共轭作用于 Syl_p(G)(轨道 = 全部 Sylow p-子群,|Syl_p(G)| = n_p)',\n 'action.viewTitle.regular': '左平移作用(正则表示):G 作用于自身,g·x = g·x;轨道唯一且自由 ⇒ Cayley 定理:G ≅ Sym(G) 的子群',\n 'action.viewTitle.coset': '陪集作用:G 作用于左陪集 G/H,g·(xH) = (gx)H;传递作用,Stab(xH) = xHx⁻¹(共轭于 H)',\n 'action.coset.selectSubgroup': '选择子群 H(陪集作用用)…',\n 'action.coset.noSubgroups': '群过大(>60),未枚举子群',\n 'action.math.regular': '正则表示:G ≅ Sym(G) 嵌入',\n 'action.math.regularNote': 'Stab(x) = {e}(自由)',\n 'action.math.cosetStab': 'Stab(xH) = xHx⁻¹',\n 'action.math.cosetStabNote': '≅ H',\n 'action.math.cosetTransitive': '传递作用(唯一轨道)',\n 'action.math.fixedCenter': '固定点 = 中心 Z(G)',\n 'action.math.burnside': 'Burnside:|X/G| = (1/|G|)·Σ|Fix(g)|',\n 'action.edgeBlurb': '弧线 = 生成元的作用:x → g·x,颜色对应生成元(图例)',\n 'action.hoverElEdges': '金色弧线 = {el} 的全部作用:对每个 x 画出 x → g·x',\n 'action.hoverGenEdges': '高亮弧线 = 生成元 {gen} 的作用',\n 'action.selHint': '选中元素 x:轨道与稳定化子信息见右侧面板',\n 'action.stabilizerFor': '元素 {el} 的稳定子 G_x',\n 'action.closeStab': '关闭',\n 'right.actionInfo': '群作用信息',\n\n /* Sylow View */\n 'sylowView.selectP': '素数 p',\n 'sylowView.pElements': 'p-元素',\n 'sylowView.pSubgroups': 'p-子群',\n 'sylowView.sylowSubgroups': 'Sylow p-子群',\n 'sylowView.otherPSubgroups': '其他 p-子群',\n 'sylowView.none': '无 p-子群(p 不整除 |G|)',\n 'sylowView.legendSelected': '选中子群元素',\n 'sylowView.legendP': 'p-元素(阶为 p 的幂)',\n 'sylowView.legendOther': '其他元素',\n 'sylowView.legendEdges': '边 = 生成元作用(颜色对应)',\n 'sylowView.edgeAction': '边作用',\n 'sylowView.edgeActionDefault': '群生成元',\n 'sylowView.edgeHint': '点击子群,边切换为该子群生成元作用', 'sylowView.twoSelectHint': 'Ctrl/⌘ 或 ⊕ 点击第二个子群 → 共轭视图(Sylow 第二定理)', 'sylowView.addSecond': '⊕ 加入为第二个子群(复选)',\n 'sylowView.conjLabel': '共轭',\n 'sylowView.noConjugator': '未找到共轭元',\n 'sylowView.legendP2': 'P(上半)',\n 'sylowView.legendQ2': 'Q(下半)',\n 'sylowView.legendI2': 'P∩Q(中间)',\n 'sylowView.legendConj': '箭头 = 共轭 x ↦ gxg⁻¹',\n 'sylowView.collapseList': '收起子群列表',\n 'sylowView.expandList': '展开子群列表',\n\n /* Theme Toggle */\n 'theme.dark': '深色模式',\n 'theme.light': '浅色模式',\n 'theme.switchToLight': '切换浅色模式',\n 'theme.switchToDark': '切换深色模式',\n}\n\nconst en: TranslationMap = {\n /* App */\n 'app.title': 'GroupViz - Group Theory Visualization',\n 'app.header': 'GroupViz - Group Theory Visualization',\n 'ui.openToolbar': 'Open Toolbar',\n 'ui.openInfo': 'Open Info Panel',\n 'ui.computing': 'Computing',\n 'theme.viewWindowDark': 'View windows: switch to light',\n 'theme.viewWindowLight': 'View windows: switch to dark',\n\n /* Welcome Page */\n 'welcome.subtitle': 'Group Theory Visualization Platform',\n 'welcome.version': 'v2.1.3',\n 'welcome.tagline': 'Explore the beauty of symmetry in abstract algebra — Interactive group theory visualization & learning tool',\n 'welcome.enter': 'Enter',\n 'welcome.section.done': 'Implemented',\n 'welcome.section.soon': 'Coming Soon',\n 'welcome.item.subgroups': 'Subgroups & Cosets',\n 'welcome.item.cayley': 'Cayley Graph',\n 'welcome.item.table': 'Multiplication Table',\n 'welcome.item.build': 'Group Construction',\n 'welcome.item.homomorphism': 'Homomorphisms',\n 'welcome.item.presentation': 'Group Presentations',\n 'welcome.soon.education': 'Education Mode',\n 'welcome.soon.freegroup': 'Free Groups',\n 'welcome.soon.dlc': 'DLC (Space/Point Groups)',\n 'welcome.feature.subgroups': 'Subgroups & Cosets',\n 'welcome.feature.cayley': 'Cayley Graph',\n 'welcome.feature.multigroup': 'Multi-Group Support',\n 'welcome.feature.table': 'Multiplication Table',\n 'welcome.feature.3d': '3D Visualization',\n 'welcome.feature.symmetry': 'Symmetry View',\n\n /* Left Panel — Accordion Titles */\n 'panel.createGroup': 'Create Group',\n 'panel.viewMode': 'View Mode',\n 'panel.cayleySettings': 'Cayley Settings',\n 'panel.operations': 'Operations & Subsets',\n 'panel.basicGroup': 'Basic Groups',\n 'panel.importGroup': 'Import by Notation',\n\n /* Left Panel — Group Types */\n 'group.cyclic': 'Cyclic',\n 'group.cyclic.full': 'Cyclic Group Z_n',\n 'group.symmetric': 'Symmetric',\n 'group.symmetric.full': 'Symmetric Group S_n',\n 'group.dihedral': 'Dihedral',\n 'group.dihedral.full': 'Dihedral Group D_n',\n 'group.alternating': 'Alternating',\n 'group.alternating.full': 'Alternating Group A_n',\n 'group.special': 'Special',\n 'group.klein': 'Klein Four-Group',\n 'group.quaternion': 'Quaternion Group',\n 'group.gl2p2': 'GL(2,2) ≅ S₃, order 6',\n 'group.gl2p3': 'GL(2,3), order 48, |SL(2,3)| = 24',\n 'group.direct.z4z2': 'Direct Product',\n 'group.direct.z2cubed': 'Elementary Abelian Group',\n 'group.direct.z3z3': 'Direct Product',\n 'group.direct.z6z2': 'Direct Product',\n 'group.type': 'Type',\n 'group.order': 'Order',\n 'panel.createByType': 'By Group Type',\n 'panel.createByOrder': 'By Order',\n 'panel.order.semidirectHint': '\" : \" in a symbol denotes a semidirect product (e.g. Z₃:C₄ = Dic₃)',\n\n /* Left Panel — View Modes */\n 'view.set': 'Set View',\n 'view.set.desc': 'Element List',\n 'view.cayley': 'Cayley Graph',\n 'view.cayley.desc': '2D Graph',\n 'view.cycle': 'Cycle Graph',\n 'view.cycle.desc': 'Cycle Structure',\n 'view.table': 'Multiplication Table',\n 'view.table.desc': 'Cayley Table',\n 'view.3d': '3D Cayley Graph',\n 'view.3d.desc': '3D Graph',\n 'view.symmetry': 'Symmetry View',\n 'view.symmetry.desc': 'Polyhedra',\n 'view.sublattice': 'Subgroup Lattice',\n 'view.sublattice.desc': 'Subgroup Hierarchy',\n 'view.homomorphism': 'Homomorphism',\n 'view.homomorphism.desc': 'Group Homomorphisms',\n 'view.cosetstrip': 'Coset Strip',\n 'view.cosetstrip.desc': 'Coset Decomposition',\n 'view.action': 'Orbit View',\n 'view.action.desc': 'Group Action',\n 'view.sylow': 'Sylow',\n 'view.sylow.desc': 'p-elements & Sylow p-subgroups',\n 'view.tree': 'Group Tree',\n 'view.prestable': 'Presentation Table',\n 'view.heatmap': 'Heatmap',\n 'view.heatmap.desc': 'Multiplication color map',\n\n /* Free Group Tree / Presentation Table views */\n 'prestable.noPresentation': 'No group presentation ⟨… | …⟩ is available for the current group. Create one in the left \"Group Presentation\" panel, or pick a smaller group.',\n\n /* Left Panel — Buttons & Labels */\n 'panel.create': 'Create {label}',\n 'panel.multiView': 'Multi-View Mode',\n 'panel.floatView': '+ {label}',\n 'panel.showMaximalCycles': 'Show Maximal Cycles Only',\n 'panel.showHeatmap': 'Heatmap mode',\n 'panel.showAction': 'Show Element Action',\n 'panel.speed': 'Speed',\n 'panel.solidShape': 'Solid shape',\n 'panel.solidCube': 'Cube',\n 'panel.solidOcta': 'Octahedron',\n 'panel.solidIcosa': 'Icosahedron',\n 'panel.solidDodeca': 'Dodecahedron',\n 'panel.multiplyType': 'Multiply Type',\n 'panel.multiplyRight': 'Right a·c',\n 'panel.multiplyLeft': 'Left c·a',\n 'panel.shape': 'Shape',\n 'panel.shape.circular': 'Circular',\n 'panel.shape.cone': 'Cone',\n 'panel.shape.grid': 'Grid',\n 'panel.shape.rewiring': 'Rewiring',\n 'panel.shape.concentric': 'Concentric (Conjugacy)',\n 'panel.shape.dualRing': 'Dual Ring (Rotation/Reflection)',\n 'panel.shape.cylinder': 'Interleaved Concentric Circles',\n 'panel.shape.torus': 'Torus (Copies on Ring)',\n 'panel.shape.ringGrid': 'Ring Grid (Ring × Grid)',\n 'panel.shape.cosetStrip': 'Coset Strip',\n 'panel.shape.archimedean': 'Archimedean Spiral',\n 'panel.shape.spiral': 'Spiral',\n 'panel.shape.coil': 'Coil',\n 'panel.shape.projection3D': '3D Planar Projection',\n 'panel.shape.pythagoreanSquare': 'Pythagorean Square',\n 'panel.forceLayout': 'Force-Directed Layout',\n 'panel.elementActions': 'Group Actions ({n}/{m})',\n 'panel.selectAll': 'Select All',\n 'panel.clear': 'Clear',\n 'panel.resetPositions': 'Reset Positions',\n 'panel.decomposeSD': 'Semidirect Decomposition',\n 'panel.decomposeSDDisabled': 'Please select a group first',\n 'panel.subsetManagement': 'Subset Management',\n 'panel.saveAsSubset': 'Save as Subset ({n})',\n 'panel.clearAllSubsets': 'Clear All Subsets',\n 'panel.showCosets': 'Show Cosets',\n 'panel.generateSubgroup': 'Generate Subgroup ⟨E⟩',\n 'panel.normalizer': 'Normalizer N_G(E)',\n 'panel.centralizer': 'Centralizer C_G(E)',\n 'panel.hideCosets': 'Hide Cosets',\n 'panel.showAllCosets': 'Show All Cosets',\n 'panel.showSelected': 'Show Selected',\n 'panel.cosetType': 'Coset Type',\n 'panel.indices': 'Index: {index}',\n 'panel.cosetCount': '{count} cosets total',\n 'panel.inverse': 'Inverse',\n 'panel.clearCanvas': 'Clear Canvas',\n 'panel.exportPng': 'Export PNG',\n 'panel.exportSvg': 'Export SVG',\n 'panel.exportGif': 'Export GIF',\n 'panel.gifOption': 'GIF rotation length',\n 'panel.gif3s': '~3 seconds',\n 'panel.gif5Cycles': '5 rotation cycles',\n 'panel.exportView': 'Export View',\n 'panel.exporting': 'Exporting...',\n 'panel.selectElementFirst': 'Please select an element on the canvas first',\n 'panel.series': 'Subgroup Series',\n\n /* Left Panel — Badges */\n 'badge.normal': 'Normal',\n 'badge.subgroup': 'Subgroup',\n 'badge.center': 'Center',\n\n /* Right Panel */\n 'right.elementProps': 'Element Properties',\n 'right.currentElement': 'Current Element',\n 'right.inverse': 'Inverse',\n 'right.id': 'ID',\n 'right.selectHint': 'Select an element on the canvas to view properties',\n 'right.groupInfo': 'Group Info',\n 'right.groupName': 'Name',\n 'right.symbol': 'Symbol',\n 'right.order': 'Order',\n 'right.generators': 'Generators',\n 'right.abelian': 'Abelian',\n 'right.isomorphic': 'Isomorphic to',\n 'right.isomorphicClick': 'Click to load the isomorphic group',\n 'right.yes': 'Yes',\n 'right.no': 'No',\n 'right.properties': 'Group Properties',\n 'right.propertyTrue': 'Yes',\n 'right.propertyFalse': 'No',\n 'right.propertyUnavailable': 'Property analysis not supported for this group',\n 'right.solvable': 'Solvable',\n 'right.nilpotent': 'Nilpotent',\n 'right.perfect': 'Perfect',\n 'right.derivedSeries': 'Derived Series',\n 'right.structure': 'Structure',\n 'right.structure.direct': 'Direct product',\n 'right.structure.semidirect': 'Semidirect product',\n 'right.structure.indecomposable': 'Indecomposable',\n 'right.structure.unknown': 'Unknown',\n 'right.center': 'Center Z(G)',\n 'right.noGroup': 'Please select a group first',\n 'right.simpleGroup': 'Simple Group',\n 'right.subgroups': 'Subgroups ({n})',\n 'right.noSubgroups': 'No subgroups',\n 'right.loadingBackend': 'Computing via backend...',\n 'right.conjugacyClasses': 'Conjugacy Classes ({n})',\n 'right.noClasses': 'No classes',\n 'right.elementList': 'Element List ({n})',\n 'right.homomorphism': 'Homomorphism',\n 'right.homo.kernel': 'Kernel Ker',\n 'right.homo.image': 'Image Im',\n 'right.homo.quotient': 'Quotient G/Ker',\n 'right.homo.noActive': 'No active homomorphism',\n 'right.automorphismMapping': 'Automorphism Mapping',\n 'right.automorphismFixed': 'fixed points',\n\n /* Subgroup Lattice */\n 'lattice.trivial': 'Trivial',\n 'lattice.subgroup': 'Subgroup',\n 'lattice.sylow': 'Sylow {p}',\n 'lattice.labelDetail': 'Label detail',\n 'lattice.label.auto': 'Auto',\n 'lattice.label.full': 'Full cards',\n 'lattice.label.compact': 'Pills',\n 'lattice.label.dots': 'Dots',\n 'lattice.mergeConjugates': 'Merge conjugate subgroups',\n 'lattice.mergeHint': 'One node per conjugacy orbit; the ×n badge is |G : N_G(H)|',\n 'lattice.nodeSize': 'Card size',\n 'lattice.showSeriesPanel': 'Series panel',\n 'lattice.orbitMembers': '{n} conjugate subgroups',\n 'lattice.captionHint': 'Hover or click a node for structure, index and normalizer',\n 'lattice.mergeTooLarge': 'Too many subgroups to merge; showing the unmerged lattice',\n 'lattice.backendOnly': 'Subgroup lattices beyond order 60 need the backend; open this group in the main workspace',\n\n /* Subgroup Series */\n 'series.off': 'Off',\n 'series.derived': 'Derived',\n 'series.upperCentral': 'Upper Central',\n 'series.lowerCentral': 'Lower Central',\n 'series.composition': 'Composition',\n 'series.chain': 'Chain',\n 'series.alternativeChains': '{n} composition chains',\n 'series.factors': 'Composition factors',\n 'series.jordanHolder': 'Jordan–Hölder: unique factor multiset',\n 'series.solvable': 'Solvable',\n 'series.nilpotent': 'Nilpotent',\n 'series.tooLarge': 'Order exceeds 240; local series computation skipped',\n 'series.loading': 'Computing series via backend (GAP)…',\n 'series.truncated': 'More than 20 chains; showing first 20',\n\n /* Cayley 3D Legend */\n 'cayley3d.multiplyRight': 'Right Multiply',\n 'cayley3d.multiplyLeft': 'Left Multiply',\n 'cayley3d.autoRotate': 'Auto Rotate',\n 'cayley3d.resetView': 'Reset View',\n 'cayley.action.enabled': 'Enabled',\n 'cayley.action.disabled': 'Disabled',\n 'cayley.action.byElement': 'by element',\n 'hint.cayleyActionNonGenerator': 'Cayley edges in this app are defined by arbitrary element actions (not limited to generators)',\n\n /* Symmetry View */\n 'symmetry.reset': 'Resetting...',\n 'symmetry.rotating': 'Rotating...',\n 'symmetry.clickHint': 'Click an element to see its symmetry action on the polyhedron',\n 'symmetry.selectHint': 'Select an element on canvas to see its effect on the geometry',\n 'symmetry.demoOff': 'Element action demo turned off',\n 'symmetry.unsupported': 'This group type does not support symmetry view yet',\n 'symmetry.supported': 'Supported groups: Cyclic C_n · Dihedral D_n · A_4 · S_4 · A_5 · V_4',\n 'symmetry.toCube': '→ Cube',\n 'symmetry.toOctahedron': '→ Octahedron',\n 'symmetry.toIcosahedron': '→ Icosahedron',\n 'symmetry.toDodecahedron': '→ Dodecahedron',\n\n /* Symmetry Geometry Descriptions (shape names; group symbol is shown in the scene title line) */\n 'symmetry.geo.cyclicText': '{n}-fold rotational symmetry',\n 'symmetry.geo.dihedralText': 'Regular {n}-gon',\n 'symmetry.geo.tetrahedron': 'Regular Tetrahedron',\n 'symmetry.geo.cube': 'Cube',\n 'symmetry.geo.octahedron': 'Regular Octahedron',\n 'symmetry.geo.icosahedron': 'Regular Icosahedron',\n 'symmetry.geo.dodecahedron': 'Regular Dodecahedron',\n 'symmetry.geo.rectangle': 'Rectangle',\n\n /* Canvas Common */\n 'canvas.noGroup': 'Please select a group first',\n 'canvas.noGroupCreate': 'Please create or select a group first',\n 'canvas.orderTooLarge': 'Group order is too large (|G| = {n})',\n 'canvas.show': 'Show',\n 'canvas.hintBox': 'Hints',\n 'canvas.history': 'History',\n 'canvas.cosetStripNoSubgroup': 'Select a subgroup to view cosets',\n 'canvas.cosetStripNoCosets': 'Click a subgroup in the right panel to view cosets',\n 'canvas.cosetStripCayley': 'Subgroup Cayley graph ⟨H⟩',\n 'canvas.tableSampled': 'Showing sampled rows and columns for large groups.',\n\n /* TableView */\n 'table.footer1': 'Column × Row = Result',\n 'table.footer2': 'Color corresponds to the result element',\n 'table.strategy.subgroup': 'Subgroup',\n 'table.strategy.random': 'Random',\n 'table.strategy.full': 'Full',\n 'table.subgroupCaption': 'Subgroup {label} (|H| = {order})',\n 'table.randomCaption': 'Random sample of {n} elements',\n 'table.heatmapAggCaption': 'Full table |G| = {n}, heatmap thumbnail {res}×{res} (mode blocks)',\n 'table.fullConfirmTitle': 'Confirm full table',\n 'table.fullConfirmMsg': 'This group has order |G| = {n}. Showing the full table enters fullscreen mode and may use noticeable memory. Continue?',\n 'table.confirmOk': 'OK',\n 'table.confirmCancel': 'Cancel',\n 'table.fullTitle': '{symbol} — Full multiplication table (|G| = {n})',\n 'table.fullExit': 'Exit fullscreen',\n 'table.fullExport': 'Export SVG',\n 'table.fullZoomIn': 'Zoom in',\n 'table.fullZoomOut': 'Zoom out',\n 'table.fullZoomReset': 'Reset zoom',\n 'table.zoomSlider': 'Zoom slider',\n 'table.fullPlaceholderMsg': 'The full table |G| = {n} is large; fullscreen mode has been applied',\n 'table.fullEnter': 'Enter fullscreen',\n\n /* Hint Messages */\n 'hint.groupSelected': 'Selected {name} (order = {order})',\n 'hint.groupCleared': 'Current group cleared',\n 'hint.cayley': 'Cayley Graph — Drag nodes to move | {count} active actions | {type}',\n 'hint.cayley3d': '3D Cayley Graph — Drag to rotate, scroll to zoom | {count} edges | Shape: {shape}',\n 'hint.symmetry': 'Symmetry View — Displays geometric symmetry objects | Drag to rotate, scroll to zoom',\n 'hint.sublattice': 'Subgroup Lattice — Click node to select elements | Drag to pan, scroll to zoom',\n 'hint.cycle': 'Cycle Graph — Each polygon is a cyclic subgroup ⟨g⟩ ≅ Z<sub>n</sub>',\n 'hint.tree': 'Group Tree view — the \"degenerated tree\" of ⟨S|R⟩ (BFS spanning tree of the quotient Cayley graph): solid edges = spanning tree (colored by generator); glued edges are not drawn, their count shown in the top bar | Scroll to zoom, drag to pan, double-click to reset, click a node to show its word',\n 'hint.prestable': 'Presentation Table — row × col = result, click a cell to select the element',\n 'hint.switchedTo': 'Switched to {viewLabel}',\n 'hint.elementSelected': 'Selected: {label}',\n 'hint.layoutDone': 'Layout optimization complete',\n 'hint.layoutComputing': 'Computing layout...',\n 'hint.cayleyMultiply': 'Cayley multiply type: {label}',\n 'hint.cayleyCleared': 'Cayley graph edges cleared',\n 'hint.cayleyShape': '3D Cayley shape: {shape}',\n 'hint.subsetSaved': 'Subset saved: {label} ({n} elements)',\n 'hint.symmetryAction': 'Show element action: {label}',\n 'hint.multiViewOn': 'Multi-view enabled — Click view buttons to open floating windows',\n 'hint.multiViewOff': 'Multi-view disabled — All floating windows closed',\n 'hint.cosetShow': 'Coset mode — cosets of selected elements highlighted | Subgroup: {label} (order={order})',\n 'hint.cosetHide': 'Coset mode disabled',\n 'hint.cosetType': 'Coset type: {label}',\n 'hint.cosetAll': 'All cosets shown — Verifying Lagrange: |G| = |H| × [G:H]',\n 'hint.cosetSelect': 'Select elements to highlight their cosets',\n 'hint.layoutFailed': 'Layout optimization failed, please retry',\n 'hint.quotientCreated': 'Quotient group {symbol} created (order = {order})',\n 'hint.quotientCreatedIso': 'Quotient group {symbol} created (order = {order}) — isomorphic to {isoSymbol}',\n 'hint.automorphismComputed': 'Automorphism group Aut({symbol}) computed (order = {order})',\n 'hint.automorphismComputedIso': 'Automorphism group Aut({symbol}) computed (order = {order}) — isomorphic to {isoSymbol}',\n\n /* Operation History */\n 'op.loadGroup': 'Load {name} (|G|={order})',\n 'op.switchView': 'Switch view: {view}',\n 'op.layout': 'Layout: {view}',\n 'op.checkSubset': 'Check subset: {label}',\n 'op.inverseRequest': 'Select an element to compute inverse',\n 'op.inverseDone': 'Inverse: ({label})^{-1} = {result}',\n 'op.clearCanvas': 'Clear Canvas',\n 'op.generateSubgroup': 'Generate subgroup (TBD)',\n 'op.setCayleyMultiply': 'Set Cayley multiply: {label}',\n 'op.clearCayley': 'Clear Cayley edges',\n 'op.setShape': 'Set 3D shape: {shape}',\n 'op.saveSubset': 'Save subset: {label} ({n} items)',\n 'op.removeSubset': 'Remove subset',\n 'op.clearSubsets': 'Clear all subsets',\n 'op.multiViewOn': 'Enable multi-view',\n 'op.multiViewOff': 'Disable multi-view',\n 'op.openFloatView': 'Open floating view: {viewLabel}',\n 'op.cosetShow': 'Show cosets: {label}',\n 'op.cosetHide': 'Hide cosets',\n 'op.cosetType': 'Switch coset type: {label}',\n 'op.cosetAll': 'Show all cosets',\n 'op.cosetSelect': 'Show cosets by selection',\n 'op.createQuotient': 'Create quotient group {parent} (order = {order})',\n 'op.removeQuotient': 'Remove quotient group',\n 'op.computedAutomorphism': 'Computed automorphism group Aut({symbol}) (order = {order})',\n 'op.removeAutomorphism': 'Remove automorphism group',\n\n /* Subset Results */\n 'subset.plain': 'Plain Subset',\n 'subset.subgroup': 'Subgroup',\n 'subset.normalSubgroup': 'Normal Subgroup',\n\n /* Coset */\n 'coset.left': 'Left Coset',\n 'coset.right': 'Right Coset',\n\n /* Language Toggle */\n 'lang.zh': '简体中文',\n 'lang.en': 'English',\n\n /* Direct Product */\n 'dp.title': 'Direct Product',\n 'dp.mode': 'Creation Mode',\n 'dp.mode.cayley': 'Cayley Graph',\n 'dp.mode.table': 'Mult. Table',\n 'dp.mode.direct': 'Direct Create',\n 'dp.sourceGroup': 'G',\n 'dp.targetGroup': 'H',\n 'dp.selectGroup': 'Select Group...',\n 'dp.importGroup': 'Import',\n 'dp.createDirectProduct': 'Create G×H',\n 'dp.storeGroup': 'Store Group',\n 'dp.groupList': 'Direct Product Groups',\n 'dp.noGroups': 'No direct product groups',\n 'dp.enterMode': 'Enter Direct Product View',\n 'dp.exitMode': 'Exit Direct Product View',\n 'dp.workspace': 'Direct Product Workspace',\n 'dp.dragHint': 'Drag one group onto a node of the other group to create a direct product',\n 'dp.tableDragHint': 'Drag H elements onto G to perform direct product',\n 'dp.creating': 'Creating direct product...',\n 'dp.created': 'Created direct product: {symbol} (order={order})',\n 'dp.selectBoth': 'Please import G and H first',\n 'dp.animation': 'Direct product animation...',\n 'dp.orderTooLarge': 'Direct product order too large ({n})',\n 'dp.directHint': 'Select two group types to create a direct product group',\n 'dp.paramN': 'Parameter n',\n 'dp.paramM': 'Parameter m',\n 'dp.create': 'Create {a} × {b}',\n 'dp.storeHint': 'Stored direct product: {symbol}',\n 'dp.removeHint': 'Removed direct product: {symbol}',\n 'dp.exportGif': 'Export GIF',\n 'dp.exporting': 'Exporting...',\n 'dp.exportCayleyHint': 'Exporting GIF: outer ring = {tgt} (H), inner cluster = {src} (G) → direct product',\n\n /* Semidirect Product */\n 'sd.title': 'Semidirect',\n 'sd.enterMode': 'Enter Semidirect Mode',\n 'sd.exitMode': 'Exit Semidirect Mode',\n 'sd.normalSubgroup': 'Normal Subgroup N',\n 'sd.actingGroup': 'Acting Group H',\n 'sd.importAsN': 'Import current as N',\n 'sd.importAsH': 'Import current as H',\n 'sd.computeAut': 'Compute Aut(N)',\n 'sd.autComputed': 'Aut(N) computed: {n} automorphisms',\n 'sd.autTooLarge': 'Aut(N) is too large to compute',\n 'sd.phiMapping': 'φ: H → Aut(N) Gen Mapping',\n 'sd.expandPhi': 'Expand φ',\n 'sd.phiValid': 'φ is a homomorphism',\n 'sd.phiInvalid': 'φ is NOT a homomorphism',\n 'sd.create': 'Create N ⋊_φ H',\n 'sd.storeGroup': 'Store Group',\n 'sd.groupList': 'Semidirect Groups',\n 'sd.noGroups': 'No semidirect groups',\n 'sd.selectGroup': 'Select group...',\n 'sd.selectBoth': 'Select N and H first',\n 'sd.selectNFirst': 'Select normal subgroup N first',\n 'sd.selectBothInPanel': 'Select N and H in the left panel',\n 'sd.mapAllGens': 'Map all generators first',\n 'sd.extendFailed': 'φ extension failed',\n 'sd.orderTooLarge': 'Semidirect product order too large ({n})',\n 'sd.createFailed': 'Semidirect product creation failed',\n 'sd.storeHint': 'Stored semidirect group: {symbol}',\n 'sd.removeHint': 'Removed semidirect group: {symbol}',\n 'sd.created': 'Created semidirect group: {symbol} (order={order})',\n 'sd.decomposeHint': 'Semidirect decomposition imported: {symbol}, N/H and φ are ready',\n 'sd.decomposeTitle': 'Semidirect Decompositions',\n 'sd.decomposeCount': 'Found {n} semidirect decompositions, first one loaded',\n 'sd.decomposeSES': 'Split short exact sequence',\n 'sd.decomposeVerified': 'Verified (rebuilt group is isomorphic)',\n 'sd.decomposeUnverified': 'Unverified (rebuilt group structure mismatch)',\n 'sd.decomposeSelect': 'Click to load this decomposition',\n 'sd.noDecomposition': 'Group {symbol} has no semidirect decomposition (no normal N and complement H with N∩H={e})',\n 'sd.dragHint': 'Drag + handle to build semidirect',\n 'sd.dropToCreate': 'Drop to create N ⋊_φ H',\n 'pres.title': 'Group Presentation',\n 'pres.placeholder': 'Enter a group presentation… (e.g. ⟨a, b | a², b³, (ab)³⟩ or ⟨a | a^4⟩)',\n 'pres.presets': 'Presets',\n 'pres.create': 'Create Group',\n 'pres.clear': 'Clear',\n 'pres.preview': 'Preview',\n 'pres.groups': 'Created Presentation Groups',\n 'pres.noGroups': 'No presentation groups yet',\n 'pres.created': 'Group created: {symbol} (order {order})',\n 'pres.createdIso': 'Group created: {symbol} (order {order}, isomorphic to {iso})',\n 'pres.error.parse': 'Parse error: {msg}',\n 'pres.error.parseText': 'Invalid presentation: check generators and relators',\n 'pres.error.infinite': 'This presentation defines an infinite group',\n 'pres.error.overflow': 'Group too large or coset enumeration limit exceeded',\n 'pres.error.unconnected': 'Generator action is not connected (generators do not generate the whole group)',\n 'pres.error.empty': 'Please enter a group presentation',\n 'importGroup.placeholder': 'Type a group notation, e.g. PSL(2,7), C_3×D_4 or SmallGroup(16,13)',\n 'importGroup.samples': 'Samples',\n 'importGroup.order': 'Order',\n 'importGroup.orderUnknown': 'Order unknown',\n 'importGroup.pathLocal': 'Built locally',\n 'importGroup.pathBackend': 'Imported via backend GAP',\n 'importGroup.import': 'Import Group',\n 'importGroup.loading': 'Importing…',\n 'importGroup.error.empty': 'Type a group notation',\n 'importGroup.error.semidirect': 'Semidirect notation needs the automorphism φ — use SmallGroup(n,i) instead',\n 'importGroup.error.unknown': 'Unrecognized group notation',\n 'importGroup.error.noRoute': 'This notation can neither be built locally nor mapped to a GAP expression',\n 'importGroup.error.backend': 'Backend is not running or GAP is unavailable — start the backend first',\n 'importGroup.error.fetch': 'Import failed: {msg}',\n 'pres.storeHint': 'Presentation group stored: {symbol}',\n 'pres.removeHint': 'Presentation group removed: {symbol}',\n 'pres.loadHint': 'Presentation group loaded: {symbol} (order {order})',\n 'pres.views': 'Views',\n 'pres.create.tabDirect': 'Direct Create',\n 'pres.create.tabVisual': 'Visual Create',\n 'pres.clearGroup': 'Clear current group (back to template tree)',\n 'pres.visual.template': 'Generator template',\n 'pres.visual.relation': 'Enter one relation (f = e or f1 = f2)',\n 'pres.visual.relationPlaceholder': 'e.g. a^3=e or ab=ba',\n 'pres.visual.add': 'Add',\n 'pres.visual.list': 'Added relations',\n 'pres.visual.finish': 'Finish & Create Group → Tree View',\n 'pres.visual.invalid': 'Relation must be f=e or f1=f2 (words of generators, supporting ^n and ⁻¹)',\n 'pres.visual.infinite': 'Current relations give an infinite group',\n 'pres.visual.order': '|G| = {n}',\n 'right.presentation': 'Presentation',\n 'sd.clickCreate': 'Configure φ then click button below',\n 'sd.finish': 'Finish',\n 'sd.phase1': 'Step 1: Start with the Cayley graph of H (skeleton)',\n 'sd.phase2': 'Step 2: Inflate each node into the rewired copy under φ(h)',\n 'sd.phase3': 'Step 3: Connect corresponding nodes across copies with H-arrows',\n 'sd.phase4': 'Step 4: The semidirect product is complete',\n 'sd.autoPlay': 'Auto play',\n 'sd.phaseTitle': 'Semidirect Animation',\n\n /* Homomorphism */\n 'homo.title': 'Homomorphism',\n 'homo.source': 'Domain G',\n 'homo.target': 'Codomain H',\n 'homo.savedList': 'Saved Homomorphisms ({n})',\n 'homo.activate': 'Activate',\n 'homo.autoMap': 'Auto Map',\n 'homo.trivial': 'Trivial Map',\n 'homo.projection': 'Natural Projection',\n 'homo.dpProjection': 'DP Projection ({factor})',\n 'homo.generatorHint': 'Drag elements on canvas to define generator mapping',\n 'homo.fullPreview': 'Full Preview ({m}/{n})',\n 'homo.verify': 'Verify',\n 'homo.clear': 'Clear',\n 'homo.create': 'Create',\n 'homo.openView': 'Open Homomorphism View',\n 'homo.viewSection': 'Homomorphism View',\n 'homo.valid': 'Valid',\n 'homo.invalid': 'Not a Homomorphism',\n 'homo.kernel': 'Kernel Ker',\n 'homo.image': 'Image Im',\n 'homo.injective': 'Injective',\n 'homo.notInjective': 'Not Injective',\n 'homo.surjective': 'Surjective',\n 'homo.notSurjective': 'Not Surjective',\n 'homo.isomorphism': 'Isomorphism',\n 'homo.firstIso': 'First Iso Theorem',\n 'homo.theoremMode': 'Theorem Mode →',\n 'homo.firstIso.needValid': 'Need a valid homomorphism',\n 'homo.firstIso.needValidHint': 'Please verify a homomorphism first',\n 'homo.firstIso.phase0': 'f: G \\\\to H',\n 'homo.firstIso.phase1': 'K = \\\\ker f \\\\subsetneq G',\n 'homo.firstIso.phase2': '\\\\pi: G \\\\to G/K',\n 'homo.firstIso.phase3': 'G/K \\\\cong \\\\operatorname{Im} f',\n 'homo.firstIso.phase0Desc': 'The homomorphism f maps G to H preserving the operation',\n 'homo.firstIso.phase1Desc': 'The kernel K consists of elements mapping to the identity, and K is a normal subgroup',\n 'homo.firstIso.phase2Desc': 'The natural projection π collapses G onto the quotient G/K, cosets colored by fiber',\n 'homo.firstIso.phase3Desc': 'First Isomorphism Theorem: G/K ≅ Im f, induced by f',\n 'homo.selectSourceFirst': 'Select source group first',\n 'homo.interactiveHint': 'Drag elements to map them',\n 'homo.created': 'Homomorphism created: {source} → {target}',\n 'homo.verified': 'Homomorphism verified: {source} → {target}',\n 'homo.saved': 'Homomorphism saved',\n 'homo.trivialApplied': 'Trivial mapping applied',\n 'homo.projectionApplied': 'Natural projection applied',\n 'homo.projectionFailed': 'Projection failed: no normal subgroup',\n 'homo.inclusionApplied': 'Inclusion mapping applied',\n 'homo.inclusionFailed': 'Inclusion mapping failed',\n 'homo.dpProjectionApplied': 'DP projection applied ({factor})',\n 'homo.dpProjectionFailed': 'DP projection failed',\n\n /* Quotient */\n 'quotient.title': 'Quotient Groups',\n 'quotient.boundHint': 'Select a normal subgroup to build G/N',\n 'quotient.create': 'Create Quotient',\n 'quotient.load': 'Load',\n 'quotient.noQuotient': 'No quotient groups',\n\n /* Automorphism */\n 'automorphism.title': 'Automorphism Group',\n 'automorphism.boundHint': 'Compute the automorphism group Aut(G)',\n 'automorphism.compute': 'Compute Aut(G)',\n 'automorphism.load': 'Load',\n 'automorphism.noAutomorphism': 'No automorphism groups',\n\n /* Group Action */\n 'action.title': 'Group Action',\n 'action.kind.conjugation': 'Conjugation Action',\n 'action.kind.custom': 'Custom Action',\n 'action.kind.sylow': 'Sylow {p}-subgroup conjugation action',\n 'action.kind.regular': 'Left translation (regular representation)',\n 'action.kind.coset': 'Coset action',\n 'action.create.conjugation': 'Conjugation',\n 'action.create.custom': 'Custom',\n 'action.create.regular': 'Left translation (Cayley)',\n 'action.create.coset': 'Coset action',\n 'action.create.sylow': 'Sylow p-action',\n 'action.setSize': 'Set size |X|',\n 'action.startEdit': 'Start Editing',\n 'action.editHint': 'Click an element to pick the start; the arrow follows the cursor; click a target element to deploy (auto-binds the selected generator); click the start element itself for a fixed point (self-loop); click a deployed arrow to delete it; click empty space to cancel',\n 'action.genSelectHint': 'Drag a generator onto a dashed arrow, or select one then click the arrow to bind',\n 'action.dropHint': 'Release to bind',\n 'action.cycleCandidates': 'Cycle candidates:',\n 'action.cycleUnit': 'cycle',\n 'action.editingSource': 'Choose destination of {x}',\n 'action.finish': 'Finish & Verify',\n 'action.clear': 'Clear',\n 'action.exit': 'Exit editing',\n 'action.valid': 'Homomorphism holds — action is valid',\n 'action.invalid': 'Not a homomorphism — action is invalid',\n 'action.draftRestored': 'Restored your last saved custom action draft',\n 'action.saved': 'Custom action saved to the list',\n 'action.activated': 'Action restored',\n 'action.savedList': 'Saved actions',\n 'action.activate': 'Activate',\n 'action.created': '{kind} created',\n 'action.violation': 'Φ({g}·{a}) ≠ Φ({g})∘Φ({a}) at {x}',\n 'action.orbitCount': 'Orbits: {n}',\n 'action.fixedPoints': 'Fixed points: {n}',\n 'action.sumCheck': 'Σ|Orb| = |X|: {sum} = {n}',\n 'action.ost': '|Orb(x)|·|Stab(x)| = {orbit}·{stab} = {product} = |G|',\n 'action.stabilizer': 'Stab({x})',\n 'action.orbitStab': '|Orb({x})| = {orbit}, |Stab({x})| = {stab}',\n 'action.noAction': 'Create a group action from the left panel',\n 'action.error.range': 'Arrow {from}→{to} is out of range',\n 'action.error.unbound': 'There are unbound arrows',\n 'action.error.duplicate-source': 'Generator {gen} defines source {from} twice',\n 'action.error.conflict-target': 'Target {to} of {gen} is pointed to by multiple sources',\n 'action.error.missing-target': 'Target {to} needs a destination: {gen} has no image defined for it',\n 'action.error.homomorphism': 'Not a homomorphism: Φ({g}·{gen}) ≠ Φ({g})∘Φ({gen}) at {x}; fix the arrows',\n 'action.error.unknown-generator': 'Unknown generator: {gen}',\n 'action.viewBlurb': 'Each circle is an orbit (a conjugacy class for conjugation); arcs are generator actions, colored by generator',\n 'action.showing': 'Showing element ',\n 'action.conjSuffix': \"'s conjugation action: x ↦ g·x·g⁻¹'\",\n 'action.arrowSuffix': \"'s full action arrows'\",\n 'action.orbitGroup': 'Orbit · {size} elements',\n 'action.viewTitle.conjugation': 'Conjugation action: G acts on itself, g·x = g·x·g⁻¹ (orbits = conjugacy classes)',\n 'action.viewTitle.custom': 'Custom action: G acts on the set X',\n 'action.viewTitle.sylow': 'Sylow {p}-subgroups: G acts on Syl_p(G) by conjugation (orbit = all Sylow p-subgroups, |Syl_p(G)| = n_p)',\n 'action.viewTitle.regular': 'Left translation (regular representation): G acts on itself by g·x = g·x; single orbit, free action ⇒ Cayley theorem: G ≅ subgroup of Sym(G)',\n 'action.viewTitle.coset': 'Coset action: G acts on left cosets G/H by g·(xH) = (gx)H; transitive, Stab(xH) = xHx⁻¹ (conjugate of H)',\n 'action.coset.selectSubgroup': 'Select subgroup H (for coset action)…',\n 'action.coset.noSubgroups': 'Group too large (>60), subgroups not enumerated',\n 'action.math.regular': 'Regular representation: G ≅ Sym(G) embedding',\n 'action.math.regularNote': 'Stab(x) = {e} (free)',\n 'action.math.cosetStab': 'Stab(xH) = xHx⁻¹',\n 'action.math.cosetStabNote': '≅ H',\n 'action.math.cosetTransitive': 'Transitive (single orbit)',\n 'action.math.fixedCenter': 'Fixed points = center Z(G)',\n 'action.math.burnside': 'Burnside: |X/G| = (1/|G|)·Σ|Fix(g)|',\n 'action.edgeBlurb': 'Arcs = generator actions: x → g·x, colors match the legend',\n 'action.hoverElEdges': 'Gold arcs = all actions of {el}: x → g·x for every x',\n 'action.hoverGenEdges': 'Highlighted arcs = action of generator {gen}',\n 'action.selHint': 'Selected x: orbit & stabilizer details in the right panel',\n 'action.stabilizerFor': 'Stabilizer G_x of element {el}',\n 'action.closeStab': 'Close',\n 'right.actionInfo': 'Group Action Info',\n\n /* Sylow View */\n 'sylowView.selectP': 'Prime p',\n 'sylowView.pElements': 'p-elements',\n 'sylowView.pSubgroups': 'p-subgroups',\n 'sylowView.sylowSubgroups': 'Sylow p-subgroups',\n 'sylowView.otherPSubgroups': 'Other p-subgroups',\n 'sylowView.none': 'No p-subgroups (p ∤ |G|)',\n 'sylowView.legendSelected': 'selected subgroup elements',\n 'sylowView.legendP': 'p-elements (order a power of p)',\n 'sylowView.legendOther': 'other elements',\n 'sylowView.legendEdges': 'edges = generator action (color-coded)',\n 'sylowView.edgeAction': 'Edge action',\n 'sylowView.edgeActionDefault': 'group generators',\n 'sylowView.edgeHint': 'Click a subgroup to switch edges to its generators',\n 'sylowView.twoSelectHint': 'Ctrl/⌘ or ⊕ click a second subgroup → conjugation (Sylow II)', 'sylowView.addSecond': '⊕ add as second subgroup (multi-select)',\n 'sylowView.conjLabel': 'Conjugation',\n 'sylowView.noConjugator': 'no conjugating element',\n 'sylowView.legendP2': 'P (top)',\n 'sylowView.legendQ2': 'Q (bottom)',\n 'sylowView.legendI2': 'P∩Q (middle)',\n 'sylowView.legendConj': 'arrows = conjugation x ↦ gxg⁻¹',\n 'sylowView.collapseList': 'Collapse subgroup list',\n 'sylowView.expandList': 'Expand subgroup list',\n\n /* Theme Toggle */\n 'theme.dark': 'Dark Mode',\n 'theme.light': 'Light Mode',\n 'theme.switchToLight': 'Switch to Light Mode',\n 'theme.switchToDark': 'Switch to Dark Mode',\n}\n\nexport const translations: Record<Lang, TranslationMap> = { zh, en }\n\nexport function getDefaultLang(): Lang {\n if (typeof window === 'undefined') return 'zh'\n const stored = localStorage.getItem('groupviz-lang')\n if (stored === 'en' || stored === 'zh') return stored\n const nav = navigator.language || ''\n if (nav.startsWith('zh')) return 'zh'\n return 'zh'\n}\n","import { createContext, useState, useCallback, type ReactNode } from 'react'\nimport { translations, getDefaultLang, type Lang } from './translations'\n\nexport interface I18nContextValue {\n lang: Lang\n setLang: (lang: Lang) => void\n t: (key: string, params?: Record<string, string | number>) => string\n}\n\n/**\n * 缺省 `t`(无 `<I18nProvider>` 包裹时)——**查真实词典**,而不是回落成 key。\n *\n * 旧实现是 `t: (key) => key`,于是外部嵌入漏包 Provider 时整屏文案都变成\n * `canvas.cosetStripNoCosets` 这样的 key(反馈里的高频踩坑点)。现在缺省就按\n * 「中文优先、英文兜底」渲染,漏包 Provider 只是拿不到 `setLang` 的切换能力。\n */\nfunction defaultTranslate(key: string, params?: Record<string, string | number>): string {\n let text = translations['zh'][key] ?? translations['en'][key] ?? key\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n text = text.replace(new RegExp(`\\\\{${k}\\\\}`, 'g'), String(v))\n }\n }\n return text\n}\n\n// eslint-disable-next-line react-refresh/only-export-components\nexport const I18nContext = createContext<I18nContextValue>({\n lang: 'zh',\n setLang: () => { },\n t: defaultTranslate,\n})\n\nexport interface I18nProviderProps {\n children: ReactNode\n /** 初始语言;缺省按 `getDefaultLang()`(读 localStorage / 浏览器语言) */\n lang?: Lang\n /** 是否把语言选择写入 `localStorage('groupviz-lang')`;缺省 `true`。\n * 嵌入宿主不希望与主应用抢同一 key 时可传 `false`。 */\n persist?: boolean\n}\n\nexport function I18nProvider({ children, lang: langProp, persist = true }: I18nProviderProps) {\n const [lang, setLangState] = useState<Lang>(() => langProp ?? getDefaultLang())\n\n const setLang = useCallback((newLang: Lang) => {\n setLangState(newLang)\n if (persist) localStorage.setItem('groupviz-lang', newLang)\n }, [persist])\n\n const t = useCallback((key: string, params?: Record<string, string | number>) => {\n const dict = translations[lang]\n let text = dict[key]\n if (text === undefined) {\n text = translations['en'][key]\n }\n if (text === undefined) {\n console.warn(`Missing translation key: \"${key}\" for lang \"${lang}\"`)\n return key\n }\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n text = text.replace(new RegExp(`\\\\{${k}\\\\}`, 'g'), String(v))\n }\n }\n return text\n }, [lang])\n\n return (\n <I18nContext.Provider value={{ lang, setLang, t }}>\n {children}\n </I18nContext.Provider>\n )\n}\n","import { useContext } from 'react'\nimport { I18nContext } from './I18nContext'\n\nexport function useTranslation() {\n return useContext(I18nContext)\n}\n","import { useId, useMemo } from 'react'\nimport { SceneThemeRoot, type SceneTheme } from './SceneThemeRoot'\nimport { useTranslation } from '../../i18n/useTranslation'\nimport { cosetStripLayout, cayleyCircleLayout } from '../../core/algebra/forceLayout'\nimport { computeCayleyActionEdges } from '../../core/algebra/cayleyEdges'\nimport { findMinimalGenerators } from '../../core/algebra/sylow'\nimport { buildCosetViewData } from '../../core/algebra/cosetView'\nimport { resolveElementIdsWarn } from '../../utils/elementRef'\n\n// 「H 不是子群」告警去重(同一群 + 同一集合只提示一次)\nconst _notSubgroupWarned = new Set<string>()\nfunction warnNotSubgroup(group: Group, ids: string[]) {\n const key = `${group.symbol}|${[...ids].sort().join(',')}`\n if (_notSubgroupWarned.has(key)) return\n _notSubgroupWarned.add(key)\n console.warn(\n `[groupviz] CosetStripScene.subgroup: 元素集合 [${key.split('|')[1]}] 在群 ${group.symbol} 中` +\n `不构成子群(不含单位元或乘法不封闭),陪集视图显示空态。`\n )\n}\nimport { renderTex, texify } from '../../utils/texify'\nimport type { CosetStripInfo } from '../../core/algebra/forceLayout'\nimport { COLOR_PALETTE } from '../../core/types'\nimport type { Group, GroupElement } from '../../core/types'\n\n// ─── Coset Strip props-化内核 ──────────────────────────────────────────\n// 受控 ViewWindow (FGVE) 与主画布(经 context 壳)共用。除 group / viewBoxSize 外\n// 全部可选:主画布壳由全局 Provider 组装装饰数据(陪集/子集高亮、选中、变换),\n// 窗口引擎自包含时只传 group + 由 H 派生的陪集数据,其余缺省即安全空值。\n// FGVE 打包期随视图层入包:仅依赖 i18n context(文案 key 由 @groupviz/react 自带\n// I18nProvider/语言包供给),不读 useGroup/useHover/useTheme——context 组装壳\n// 在 CosetStripView.tsx(主应用宿主专用,不入包)。\n\nexport interface CosetStripSceneProps {\n group: Group | null\n selectedElements?: Set<string>\n canvasTransform?: { x: number; y: number; scale: number }\n viewBoxSize: { width: number; height: number }\n /** 元素 → 陪集下标(与 SetView 同约定)。缺省空 Map 显示空态文案 */\n cosetElementMap?: Map<string, number> | null\n /** 每条陪集的条带颜色 */\n cosetColors?: string[]\n /** 被高亮的陪集下标集合(点击选中元素 → 其所在陪集) */\n cosetHighlightSet?: Set<number>\n /** 已保存子集(元素集合 + 颜色),命中元素描边用子集色 */\n subsets?: Array<{ elementIds: string[]; color: string }>\n /** 节点常驻标签;缺省 true(主画布行为);嵌入窗口默认关,读元素靠 hover */\n showLabels?: boolean\n /** H 条带上方的 H-Cayley 小圈;缺省 true(主画布行为),嵌入窗口默认关省空间 */\n showSubgroupCayley?: boolean\n /** 点击节点:缺省无操作(主画布壳接全局选中,窗口引擎自己维护会话态) */\n onSelect?: (elId: string, additive: boolean) => void\n /** 悬停节点:主画布走全局 Hover,窗口经 anchor 就地气泡 */\n onHover?: (el: GroupElement | null, anchor?: { x: number; y: number } | null) => void\n noGroupText?: string\n /** 有群但无陪集数据时的文案(缺省 i18n canvas.cosetStripNoCosets,主应用语境);\n * 窗口引擎可传自定义提示(如本地枚举上限) */\n noCosetsText?: string\n /** **便捷入口**:给定子群 H(元素引用数组,`id` 或 `label` 皆可),内部经\n * `@groupviz/core` 的 `buildCosetViewData` 自动派生 `cosetElementMap` /\n * `cosetColors` / `cosetHighlightSet`。与显式传三件套二选一——显式传入者优先。 */\n subgroup?: string[] | null\n /** 便捷入口配套:左 / 右陪集族;缺省 `'left'` */\n cosetType?: 'left' | 'right'\n /** 便捷入口配套:是否高亮全部陪集;缺省 `false`(仅高亮含选中元素的陪集) */\n highlightAllCosets?: boolean\n /** 视图主题作用域(`'dark' | 'light'`)。缺省不注入、跟随外层主题;显式传值时在本子树内\n * 应用 `theme.css` 对应变量块(需宿主已 `import '@groupviz/react/theme.css'`) */\n theme?: SceneTheme\n}\n\nexport function CosetStripScene(props: CosetStripSceneProps) {\n return (\n <SceneThemeRoot theme={props.theme}>\n <CosetStripSceneBody {...props} />\n </SceneThemeRoot>\n )\n}\n\nfunction CosetStripSceneBody({\n group,\n selectedElements,\n canvasTransform,\n viewBoxSize,\n cosetElementMap: cosetElementMapProp,\n cosetColors: cosetColorsProp,\n cosetHighlightSet: cosetHighlightSetProp,\n subsets,\n showLabels = true,\n showSubgroupCayley = true,\n onSelect,\n onHover,\n noGroupText,\n noCosetsText,\n subgroup,\n cosetType = 'left',\n highlightAllCosets = false,\n}: CosetStripSceneProps) {\n const { t } = useTranslation()\n // 多实例(主画布 + 多窗口)并存时避免 marker/filter id 冲突\n const uid = useId()\n const shadowId = `${uid}-cs-node-shadow`\n const arrowId = (i: number) => `${uid}-cs-cayley-arrow-${i}`\n\n // 便捷入口:显式三件套优先;未传时由 H 元素引用经 core.buildCosetViewData 一键派生\n const derived = useMemo(() => {\n if (cosetElementMapProp || !group || !subgroup || subgroup.length === 0) return null\n const ids = resolveElementIdsWarn(group, subgroup, 'CosetStripScene.subgroup')\n if (ids.length === 0) return null\n const data = buildCosetViewData(group, ids, {\n side: cosetType,\n highlightAll: highlightAllCosets,\n selected: selectedElements ?? [],\n })\n if (!data) warnNotSubgroup(group, ids)\n return data\n }, [cosetElementMapProp, group, subgroup, cosetType, highlightAllCosets, selectedElements])\n\n const cosetElementMap = cosetElementMapProp ?? derived?.cosetElementMap\n const cosetColors = cosetColorsProp ?? derived?.cosetColors\n const cosetHighlightSet = cosetHighlightSetProp ?? derived?.cosetHighlightSet\n\n const subsetDetailMap = useMemo(() => {\n const m = new Map<string, { color: string }>()\n ;(subsets ?? []).forEach(s => s.elementIds.forEach(id => { if (!m.has(id)) m.set(id, s) }))\n return m\n }, [subsets])\n\n const subgroupInfo = useMemo(() => {\n if (!group || !cosetElementMap || cosetElementMap.size === 0) return null\n // The subgroup is the coset containing the identity (eH = H); coset index 0\n // may correspond to any coset depending on group element ordering.\n const hCi = cosetElementMap.get(group.identity.id)\n if (hCi === undefined) return null\n let hSize = 0\n for (const ci of cosetElementMap.values()) { if (ci === hCi) hSize++ }\n if (hSize < 2 || hSize > 12) return null\n const r = Math.max(40, Math.min(96, hSize * 16))\n return { hSize, r, topPad: 2 * r + 64 }\n }, [group, cosetElementMap])\n\n const cosetStripData = useMemo(() => {\n if (!group) return null\n if (!cosetElementMap || cosetElementMap.size === 0) return null\n return cosetStripLayout(\n group,\n viewBoxSize.width,\n viewBoxSize.height,\n undefined,\n cosetElementMap,\n new Set(cosetElementMap.values()).size,\n cosetColors,\n subgroupInfo && showSubgroupCayley ? subgroupInfo.topPad : undefined,\n )\n }, [group, viewBoxSize.width, viewBoxSize.height, cosetElementMap, cosetColors, subgroupInfo, showSubgroupCayley])\n\n const subgroupCayley = useMemo(() => {\n if (!group || !cosetElementMap || cosetElementMap.size === 0) return null\n if (!showSubgroupCayley) return null\n // Same coset-of-identity logic as subgroupInfo: the subgroup H is the coset eH.\n const hCi = cosetElementMap.get(group.identity.id)\n if (hCi === undefined) return null\n const hIds: string[] = []\n for (const [id, ci] of cosetElementMap) { if (ci === hCi) hIds.push(id) }\n if (hIds.length < 2 || hIds.length > 12) return null\n const hIdSet = new Set(hIds)\n const hElements = group.elements.filter(el => hIdSet.has(el.id))\n const hGenerators = findMinimalGenerators(hElements, group)\n if (hGenerators.length === 0) return null\n const genIndex = new Map<string, number>()\n const actions = hGenerators.map((g, i) => {\n genIndex.set(g.id, i)\n return { elementId: g.id, enabled: true, color: COLOR_PALETTE[i % COLOR_PALETTE.length] }\n })\n const edges = computeCayleyActionEdges(group, actions, 'right')\n .filter(e => !e.isSelfLoop && hIdSet.has(e.fromId) && hIdSet.has(e.toId))\n return { hIdSet, hElements, hGenerators, genIndex, edges }\n }, [group, cosetElementMap, showSubgroupCayley])\n\n const nodeRadius = useMemo(() => {\n if (!group) return 28\n const maxLen = Math.max(...group.elements.map(el => el.label.length))\n if (maxLen > 15) return 20\n if (maxLen > 8) return 24\n return 28\n }, [group])\n const NO_GROUP = !group\n\n const handleHover = (el: GroupElement | null, anchor?: { x: number; y: number } | null) => {\n if (onHover) onHover(el, anchor)\n }\n\n return (\n <svg viewBox={`0 0 ${viewBoxSize.width} ${viewBoxSize.height}`} className=\"view-svg\" style={{ userSelect: 'none' }}>\n <defs>\n <filter id={shadowId} x=\"-30%\" y=\"-30%\" width=\"160%\" height=\"160%\">\n <feDropShadow dx=\"0\" dy=\"2\" stdDeviation=\"3\" floodColor=\"#000000\" floodOpacity=\"0.25\" />\n </filter>\n {subgroupCayley && subgroupCayley.hGenerators.map((g, i) => (\n <marker key={g.id} id={arrowId(i)} markerWidth={13} markerHeight={13} refX={10} refY={6.5} orient=\"auto\">\n <path d=\"M0,0 L13,6.5 L0,13 Z\" fill={COLOR_PALETTE[i % COLOR_PALETTE.length]} />\n </marker>\n ))}\n </defs>\n\n <g transform={`translate(${canvasTransform?.x ?? 0}, ${canvasTransform?.y ?? 0}) scale(${canvasTransform?.scale ?? 1})`}>\n {cosetStripData && cosetStripData.strips.length > 0 && cosetStripData.strips.map((strip: CosetStripInfo, si: number) => (\n <g key={`coset-bg-${si}`} data-coset-strip={si}>\n <rect\n x={strip.x}\n y={strip.y}\n width={strip.w}\n height={strip.h}\n rx={8}\n fill={strip.color + (strip.isSubgroup ? '18' : '10')}\n stroke={strip.color + (strip.isSubgroup ? '55' : '28')}\n strokeWidth={strip.isSubgroup ? 2 : 1}\n strokeDasharray={strip.isSubgroup ? undefined : '4 6'}\n />\n <text\n x={strip.x + strip.w / 2}\n y={strip.y - 10}\n textAnchor=\"middle\"\n fill={strip.color}\n fontSize={13}\n fontWeight={strip.isSubgroup ? 700 : 400}\n opacity={0.85}\n style={{ fontFamily: 'KaTeX_Main, monospace', fontStyle: 'italic' }}\n >{strip.label}</text>\n </g>\n ))}\n\n {subgroupCayley && cosetStripData && cosetStripData.strips[0] && subgroupInfo && group && (() => {\n const strip = cosetStripData.strips[0]\n const cx = strip.x + strip.w / 2\n const cy = strip.y - subgroupInfo.r - 24\n const hGroup = { ...group, order: subgroupInfo.hSize, elements: subgroupCayley.hElements }\n const positions = cayleyCircleLayout(hGroup, cx, cy, subgroupInfo.r)\n const maxLabelLen = Math.max(...subgroupCayley.hElements.map(el => {\n const l = el.label\n if (l.startsWith('\\\\begin{smallmatrix}')) return 4\n return l.length\n }))\n const labelFs = maxLabelLen <= 4 ? 15 : maxLabelLen <= 6 ? 13 : maxLabelLen <= 8 ? 11 : 9.5\n const hNodeR = Math.max(12, Math.min((maxLabelLen * labelFs * 0.62 + 10) / 2, subgroupInfo.r * 0.35))\n return (\n <g key=\"subgroup-cayley\">\n <text\n x={cx}\n y={cy - subgroupInfo.r - 12}\n textAnchor=\"middle\"\n fill=\"var(--text-muted)\"\n fontSize={13}\n fontFamily=\"KaTeX_Main, monospace\"\n >{t('canvas.cosetStripCayley')}</text>\n {subgroupCayley.edges.map(edge => {\n const fp = positions.get(edge.fromId)\n const tp = positions.get(edge.toId)\n if (!fp || !tp) return null\n const gi = subgroupCayley.genIndex.get(edge.actionElementId) ?? 0\n return (\n <line\n key={`${edge.fromId}-${edge.toId}-${edge.actionElementId}`}\n x1={fp.x}\n y1={fp.y}\n x2={tp.x}\n y2={tp.y}\n stroke={edge.color}\n strokeWidth={2.2}\n opacity={0.9}\n markerEnd={edge.isBidirectional ? undefined : `url(#${arrowId(gi)})`}\n />\n )\n })}\n {subgroupCayley.hElements.map(el => {\n const p = positions.get(el.id)\n if (!p) return null\n return (\n <g key={`h-cayley-${el.id}`} transform={`translate(${p.x}, ${p.y})`}>\n <circle\n r={hNodeR}\n fill=\"var(--node-fill)\"\n stroke={el.id === group.identity.id ? '#ffd93d' : 'var(--node-stroke)'}\n strokeWidth={1.8}\n />\n <foreignObject\n x={-hNodeR}\n y={-hNodeR}\n width={hNodeR * 2}\n height={hNodeR * 2}\n style={{ pointerEvents: 'none', userSelect: 'none' }}\n >\n <div\n style={{\n display: 'flex', alignItems: 'center', justifyContent: 'center',\n width: '100%', height: '100%', color: 'var(--node-text)', fontSize: `${labelFs}px`\n }}\n dangerouslySetInnerHTML={{ __html: renderTex(texify(el.label)) }}\n />\n </foreignObject>\n </g>\n )\n })}\n </g>\n )\n })()}\n\n {cosetStripData && cosetStripData.strips.length > 0 && group && (\n (() => {\n const shSize = cosetStripData.strips[0]?.elementIds.length || 0\n const n = group.order\n const index = cosetStripData.strips.length\n return (\n <text\n x={viewBoxSize.width / 2}\n y={viewBoxSize.height - 14}\n textAnchor=\"middle\"\n fill=\"#999\"\n fontSize={12}\n opacity={0.7}\n style={{ fontFamily: 'KaTeX_Main, monospace' }}\n >{`|G|=${n} = ${shSize}\\u00b7${index} |H|\\u00b7[G:H]`}</text>\n )\n })()\n )}\n\n {cosetStripData && group && group.elements.map((el) => {\n const pos = cosetStripData.positions.get(el.id)\n if (!pos) return null\n const isSelected = selectedElements?.has(el.id) ?? false\n const parentSubset = subsetDetailMap.get(el.id)\n const cosetIdx = cosetElementMap?.get(el.id)\n const isInHighlightedCoset = cosetIdx !== undefined && (cosetHighlightSet?.has(cosetIdx) ?? false)\n\n let fillColor = 'var(--node-fill)'\n let strokeColor = 'var(--node-stroke)'\n let strokeWidth = 2.5\n\n if (isSelected) {\n fillColor = 'var(--node-fill-selected)'\n strokeColor = '#ffd93d'\n strokeWidth = 3\n } else if (isInHighlightedCoset && cosetIdx !== undefined && cosetColors) {\n fillColor = cosetColors[cosetIdx] + '33'\n strokeColor = cosetColors[cosetIdx]\n strokeWidth = 3\n } else if (parentSubset) {\n fillColor = parentSubset.color + '33'\n strokeColor = parentSubset.color\n strokeWidth = 2.5\n }\n\n return (\n <g\n key={el.id}\n data-coset-node={el.id}\n transform={`translate(${pos.x}, ${pos.y})`}\n onClick={(e) => {\n e.stopPropagation()\n if (onSelect) onSelect(el.id, e.ctrlKey || e.metaKey)\n }}\n onMouseEnter={() => {\n // anchor 用世界→视口换算(与 CycleView 同约定):窗口 hover 气泡据此定位\n const s = canvasTransform?.scale ?? 1\n handleHover(el, {\n x: pos.x * s + (canvasTransform?.x ?? 0),\n y: pos.y * s + (canvasTransform?.y ?? 0),\n })\n }}\n onMouseLeave={() => handleHover(null)}\n style={{ cursor: 'pointer' }}\n >\n <circle\n r={nodeRadius}\n fill={fillColor}\n stroke={strokeColor}\n strokeWidth={strokeWidth}\n filter=\"url(#${shadowId})\"\n />\n {parentSubset && (\n <circle\n r={nodeRadius}\n fill={`${parentSubset.color}22`}\n stroke=\"none\"\n />\n )}\n {isInHighlightedCoset && cosetIdx !== undefined && cosetColors && (\n <circle\n r={nodeRadius}\n fill={`${cosetColors[cosetIdx]}22`}\n stroke=\"none\"\n />\n )}\n {showLabels && (\n <foreignObject\n x={-nodeRadius}\n y={-16}\n width={nodeRadius * 2}\n height={32}\n style={{ pointerEvents: 'none', userSelect: 'none' }}\n >\n <div\n style={{\n display: 'flex', alignItems: 'center', justifyContent: 'center',\n width: '100%', height: '100%', color: 'var(--node-text)',\n fontSize: el.label.length <= 4 ? '15px' : el.label.length <= 6 ? '13px' : '10px'\n }}\n dangerouslySetInnerHTML={{\n __html: renderTex(texify(el.label))\n }}\n />\n </foreignObject>\n )}\n </g>\n )\n })}\n\n {NO_GROUP && (\n <text x={viewBoxSize.width / 2} y={viewBoxSize.height / 2} textAnchor=\"middle\" fill=\"var(--text-muted)\" fontSize=\"18\">\n {noGroupText ?? t('canvas.cosetStripNoSubgroup')}\n </text>\n )}\n\n {group && (!cosetStripData || cosetStripData.strips.length === 0) && (\n <text x={viewBoxSize.width / 2} y={viewBoxSize.height / 2} textAnchor=\"middle\" fill=\"var(--text-muted)\" fontSize=\"18\">\n {noCosetsText ?? t('canvas.cosetStripNoCosets')}\n </text>\n )}\n </g>\n </svg>\n )\n}\n","/**\n * 通用 Blob 下载触发 —— 与导出链(gifenc/渲染收集)解耦的纯 DOM 工具。\n *\n * 独立成模块的动机(FGVE 阶段 3 入包):TableView 等纯内核 Scene 需要\n * \"导出当前 SVG\" 能力,但 utils/export.ts 整模块顶层依赖 gifenc(GIF 编码,\n * 无 sideEffects 声明时会被打包器保守内嵌)。把 triggerDownload 抽到零依赖\n * 模块后,react 包的程序图不再触及 export.ts,gifenc 不会进入包产物。\n */\nexport function triggerDownload(blob: Blob, filename: string) {\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = filename\n document.body.appendChild(a)\n a.click()\n document.body.removeChild(a)\n setTimeout(() => URL.revokeObjectURL(url), 1000)\n}\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type PointerEvent as RPointerEvent,\n} from 'react'\nimport { useTranslation } from '../../i18n/useTranslation'\nimport { SceneThemeRoot, type SceneTheme } from './SceneThemeRoot'\nimport { isTooLarge } from '../../core/viewBox'\nimport { findAllSubgroups } from '../../core/algebra/subgroups'\nimport { triggerDownload } from '../../utils/download'\nimport type { CanvasTransform, Group, GroupElement, Subset } from '../../core/types'\nimport type { CosetInfo } from '../../core/algebra/subgroups'\nimport type { TableStrategy } from '../../core/types/viewConfig'\n\nconst elementColors = [\n '#ff6b6b', '#4ecdc4', '#ffd93d', '#6bcb77', '#9b59b6',\n '#3498db', '#e67e22', '#1abc9c', '#e74c3c', '#2ecc71',\n '#f39c12', '#8e44ad', '#3071a9', '#d35400', '#c0392b'\n]\n\n// 完整表格(网格 + 行表头 + 列表头 + 页脚)的 viewBox 内容尺寸余量\nexport const TABLE_PAD_W = 44 // 行表头 ~38px + 右侧小余量\nexport const TABLE_PAD_H = 74 // 列表头 ~16px + 页脚 ~50px + 余量\n\n// 热力图大群聚合:超过该阶数的热力图 full 策略降采样为众数色块缩略图,\n// 既用颜色密度呈现乘法表宏观结构,又将渲染成本恒定在 HEATMAP_AGG_RES² 量级。\nconst HEATMAP_AGG_THRESHOLD = 60\nconst HEATMAP_AGG_RES = 80\n\nexport interface TableViewProps {\n group: Group | null\n selectedElements: Set<string>\n canvasTransform: CanvasTransform\n viewBoxSize: { width: number; height: number }\n /** 子集(含子群标记),用于子群/非子群着色;缺省空 */\n subsets?: Subset[]\n cosetElementMap?: Map<string, number>\n cosetColors?: string[]\n cosetData?: CosetInfo | null\n cosetType?: 'left' | 'right'\n showAllCosets?: boolean\n /** 大群告警已解除(对应主画布 forceShowLargeGroupViews.has('table'));缺省 false */\n forceShowLargeGroup?: boolean\n /** 解除大群告警回调;缺省使用本地状态 */\n onForceShowLargeGroup?: (allow: boolean) => void\n /** 大群(>16 阶)展示策略;缺省 'subgroup' */\n strategy?: TableStrategy\n /** 单元格尺寸;缺省 50 */\n cellSize?: number\n /** 热力图模式:只显示颜色,不显示元素和行/列表头;缺省 false */\n showHeatmap?: boolean\n /** 策略被内部 UI 切换时回传(供外部 viewParams 同步) */\n onStrategyChange?: (s: TableStrategy) => void\n /** 实际渲染的表格内容尺寸回传(行数×cellSize + 表头/页脚),用于 ViewWindow 设定最小窗口尺寸;\n * 大群告警/全屏占位时回传 null(无表格可显示) */\n onLayoutSize?: (size: { width: number; height: number } | null) => void\n onSelect?: (elId: string, additive: boolean) => void\n onHover?: (el: GroupElement | null) => void\n noGroupText?: string\n /** 文字乘法表「过大」阈值覆盖(群阶 > 该值时先出告警占位);缺省 100(core.sizeLimitFor('table')) */\n maxTableOrder?: number\n /** 热力图「过大」阈值覆盖;缺省 240(core.sizeLimitFor('heatmap'),聚合缩略图可承载更大群) */\n maxHeatmapOrder?: number\n /** 视图主题作用域(`'dark' | 'light'`)。缺省不注入、跟随外层主题;显式传值时在本子树内\n * 应用 `theme.css` 对应变量块(需宿主已 `import '@groupviz/react/theme.css'`) */\n theme?: SceneTheme\n}\n\nexport function TableView(props: TableViewProps) {\n return (\n <SceneThemeRoot theme={props.theme}>\n <TableViewBody {...props} />\n </SceneThemeRoot>\n )\n}\n\ninterface SubgroupPick {\n indices: number[]\n label: string\n order: number\n}\n\nconst EMPTY_IDX_MAP = new Map<string, number>()\nconst EMPTY_SUBSETS: Subset[] = []\n\nfunction pickRandomSample(group: Group, idToIdx: Map<string, number>): number[] {\n const n = group.order\n const set = new Set<number>([idToIdx.get(group.identity.id) ?? 0])\n const target = Math.max(set.size, Math.min(n, 6 + Math.floor(Math.random() * 7)))\n const pool: number[] = []\n for (let i = 0; i < n; i++) {\n if (!set.has(i)) pool.push(i)\n }\n while (set.size < target && pool.length > 0) {\n const r = Math.floor(Math.random() * pool.length)\n set.add(pool[r])\n pool.splice(r, 1)\n }\n return [...set].sort((a, b) => a - b)\n}\n\nfunction pickSubgroup(group: Group, idToIdx: Map<string, number>, subsets: Subset[]): SubgroupPick | null {\n const byKey = new Map<string, SubgroupPick>()\n const add = (indices: number[], label: string) => {\n const key = [...indices].sort((a, b) => a - b).join(',')\n if (!byKey.has(key)) {\n byKey.set(key, { indices: [...indices], label, order: indices.length })\n }\n }\n\n for (const s of subsets) {\n if (!s.isSubgroup || s.elementIds.length < 2 || s.elementIds.length > 16) continue\n const idxs: number[] = []\n let ok = true\n for (const elId of s.elementIds) {\n const idx = idToIdx.get(elId)\n if (idx === undefined) {\n ok = false\n break\n }\n idxs.push(idx)\n }\n if (ok) add(idxs, s.label)\n }\n\n const { elements, identity, multiply } = group\n for (const el of elements) {\n if (el.id === identity.id) continue\n let g = el\n let order = 1\n while (order < 17 && g.id !== identity.id) {\n g = multiply(g, el)\n order++\n }\n if (g.id === identity.id && order >= 2 && order <= 16) {\n const idxs: number[] = []\n g = el\n for (let k = 0; k < order; k++) {\n const idx = idToIdx.get(g.id)\n if (idx !== undefined) idxs.push(idx)\n g = multiply(g, el)\n }\n add(idxs, `⟨${el.label}⟩`)\n }\n }\n\n if (group.order <= 60) {\n for (const sg of findAllSubgroups(group)) {\n if (sg.order < 2 || sg.order > 16) continue\n const idxs: number[] = []\n let ok = true\n for (const el of sg.elements) {\n const idx = idToIdx.get(el.id)\n if (idx === undefined) {\n ok = false\n break\n }\n idxs.push(idx)\n }\n if (!ok) continue\n const genLabels = sg.generators.map(gr => gr.label).join(', ')\n add(idxs, sg.order === 1 ? '{e}' : `⟨${genLabels}⟩`)\n }\n }\n\n const cands = [...byKey.values()]\n const preferred = cands.filter(c => c.order >= 6 && c.order <= 12)\n const pool = preferred.length > 0 ? preferred : cands\n if (pool.length === 0) return null\n return pool[Math.floor(Math.random() * pool.length)]\n}\n\nfunction TableViewBody({\n group,\n selectedElements,\n viewBoxSize,\n canvasTransform,\n subsets: subsetsProp,\n cosetElementMap,\n cosetColors,\n cosetData: cosetDataProp,\n cosetType: cosetTypeProp,\n showAllCosets: showAllCosetsProp,\n forceShowLargeGroup,\n onForceShowLargeGroup,\n strategy: strategyProp,\n cellSize: cellSizeProp,\n showHeatmap = false,\n onStrategyChange,\n onLayoutSize,\n onSelect,\n onHover,\n noGroupText,\n maxTableOrder,\n maxHeatmapOrder,\n}: TableViewProps) {\n const { t } = useTranslation()\n const subsets = subsetsProp ?? EMPTY_SUBSETS\n const cem = cosetElementMap ?? EMPTY_IDX_MAP\n const cosetData = cosetDataProp ?? null\n const cosetType = cosetTypeProp ?? 'left'\n const showAllCosets = showAllCosetsProp ?? false\n\n const isLargeTable = group ? group.order > 16 : false\n\n const [strategy, setStrategy] = useState<TableStrategy>(() => strategyProp ?? 'subgroup')\n const [reroll, setReroll] = useState(0)\n const [confirmOpen, setConfirmOpen] = useState(false)\n const [fullscreenOpen, setFullscreenOpen] = useState(false)\n const [fsScale, setFsScale] = useState(1)\n const [fsDragging, setFsDragging] = useState(false)\n const [fsScroll, setFsScroll] = useState({ l: 0, t: 0 })\n const [fsViewport, setFsViewport] = useState({ w: 0, h: 0 })\n const fsBodyRef = useRef<HTMLDivElement>(null)\n const fsScrollRaf = useRef(0)\n const fsSvgRef = useRef<SVGSVGElement>(null)\n const fsDragRef = useRef<{ x: number; y: number; sl: number; st: number } | null>(null)\n\n // 大群告警:外部受控(主画布)优先,否则本地状态兜底(ViewWindow)\n const [localForceShow, setLocalForceShow] = useState(false)\n const forceShow = forceShowLargeGroup ?? localForceShow\n const requestForceShow = useCallback(() => {\n if (onForceShowLargeGroup) onForceShowLargeGroup(true)\n else setLocalForceShow(true)\n }, [onForceShowLargeGroup])\n\n // 外部 strategy 受控同步:渲染期比对 props 变化(参数面板驱动),避免 effect 内 setState\n const [prevStrategyProp, setPrevStrategyProp] = useState<TableStrategy | undefined>(strategyProp)\n if (strategyProp !== prevStrategyProp) {\n setPrevStrategyProp(strategyProp)\n if (strategyProp !== undefined) setStrategy(strategyProp)\n }\n\n const applyStrategy = useCallback((s: TableStrategy) => {\n setStrategy(s)\n onStrategyChange?.(s)\n }, [onStrategyChange])\n\n const idToIdx = useMemo(() => {\n if (!group) return new Map<string, number>()\n const m = new Map<string, number>()\n group.elements.forEach((el, i) => m.set(el.id, i))\n return m\n }, [group])\n\n const labelToIdx = useMemo(() => {\n if (!group) return new Map<string, number>()\n const m = new Map<string, number>()\n group.elements.forEach((el, i) => m.set(el.label, i))\n return m\n }, [group])\n\n const table = useMemo(() => {\n if (!group) return null\n const { elements, multiply } = group\n const n = elements.length\n const tableData: { label: string; id: string }[][] = []\n for (let i = 0; i < n; i++) {\n const row: { label: string; id: string }[] = []\n for (let j = 0; j < n; j++) {\n const result = multiply(elements[j], elements[i])\n row.push({ label: result.label, id: result.id })\n }\n tableData.push(row)\n }\n return tableData\n }, [group])\n\n const getElementColor = (label: string): string => {\n const idx = labelToIdx.get(label)\n if (idx === undefined) return '#ccc'\n return elementColors[idx % elementColors.length]\n }\n\n const selectedIndices = useMemo(() => {\n const set = new Set<number>()\n selectedElements.forEach(id => {\n const idx = idToIdx.get(id)\n if (idx !== undefined) set.add(idx)\n })\n return set\n }, [selectedElements, idToIdx])\n\n const subgroupIndexSets = useMemo(() => {\n if (!group) return [] as { color: string; indices: Set<number> }[]\n return subsets\n .filter(s => s.isSubgroup)\n .map(s => {\n const indices = new Set<number>()\n s.elementIds.forEach(elId => {\n const idx = idToIdx.get(elId)\n if (idx !== undefined) indices.add(idx)\n })\n return { color: s.color, indices }\n })\n }, [subsets, idToIdx, group])\n\n const nonSubgroupSubsetIndices = useMemo(() => {\n const set = new Set<number>()\n for (const subset of subsets) {\n if (subset.isSubgroup) continue\n for (const elId of subset.elementIds) {\n const idx = idToIdx.get(elId)\n if (idx !== undefined) set.add(idx)\n }\n }\n return set\n }, [subsets, idToIdx])\n\n const subsetElemMap = useMemo(() => {\n const map = new Map<number, { color: string; isSubgroup: boolean }>()\n for (const subset of subsets) {\n for (const elId of subset.elementIds) {\n const idx = idToIdx.get(elId)\n if (idx !== undefined) {\n if (!map.has(idx)) {\n map.set(idx, { color: subset.color, isSubgroup: subset.isSubgroup })\n }\n }\n }\n }\n return map\n }, [subsets, idToIdx])\n\n const subgroupCellColors = useMemo(() => {\n if (!group) return new Map<string, string>()\n const map = new Map<string, string>()\n for (const sg of subgroupIndexSets) {\n for (const ri of sg.indices) {\n for (const ci of sg.indices) {\n map.set(`${ri},${ci}`, sg.color)\n }\n }\n }\n return map\n }, [subgroupIndexSets, group])\n\n const cosetSubgroupIndices = useMemo(() => {\n const set = new Set<number>()\n if (!group || !cosetData) return set\n for (const el of cosetData.subgroup.elements) {\n const idx = idToIdx.get(el.id)\n if (idx !== undefined) set.add(idx)\n }\n return set\n }, [group, cosetData, idToIdx])\n\n const cosetActiveRowIds = useMemo(() => {\n if (!group || !cosetData) return new Set<string>()\n if (showAllCosets) {\n const reps = new Set<string>()\n const cosets = cosetType === 'left' ? cosetData.leftCosets : cosetData.rightCosets\n for (const coset of cosets) {\n if (coset.length > 0) reps.add(coset[0].id)\n }\n return reps\n }\n return new Set(selectedElements)\n }, [group, cosetData, showAllCosets, cosetType, selectedElements])\n\n const cosetActiveColIds = useMemo(() => {\n if (!group || !cosetData) return new Set<string>()\n if (showAllCosets) {\n const reps = new Set<string>()\n const cosets = cosetType === 'right' ? cosetData.rightCosets : cosetData.leftCosets\n for (const coset of cosets) {\n if (coset.length > 0) reps.add(coset[0].id)\n }\n return reps\n }\n return new Set(selectedElements)\n }, [group, cosetData, showAllCosets, cosetType, selectedElements])\n\n const elementsInAnySubgroup = useMemo(() => {\n const set = new Set<number>()\n for (const sg of subgroupIndexSets) {\n for (const i of sg.indices) set.add(i)\n }\n return set\n }, [subgroupIndexSets])\n\n const subgroupInfo = useMemo(() => {\n if (!group || !isLargeTable || strategy !== 'subgroup') return null\n return pickSubgroup(group, idToIdx, subsets)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [group, isLargeTable, strategy, subsets, idToIdx, reroll])\n\n const randomSample = useMemo(() => {\n if (!group || !isLargeTable) return [] as number[]\n return pickRandomSample(group, idToIdx)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [group, isLargeTable, idToIdx, reroll])\n\n const strategyIndices = useMemo(() => {\n if (!group) return [] as number[]\n if (!isLargeTable) return group.elements.map((_, i) => i)\n if (strategy === 'full') return group.elements.map((_, i) => i)\n if (strategy === 'random') return randomSample\n return subgroupInfo ? subgroupInfo.indices : randomSample\n }, [group, isLargeTable, strategy, subgroupInfo, randomSample])\n\n // 热力图 full 大群聚合:把 n×n 乘法表降采样到固定分辨率的众数色块网格。\n // 每个聚合色块覆盖原表一个矩形区域,颜色取该区域结果元素的众数。\n const heatmapAgg = useMemo(() => {\n if (!group || !table || !(showHeatmap && strategy === 'full' && group.order > HEATMAP_AGG_THRESHOLD)) return null\n const n = group.order\n const res = Math.min(HEATMAP_AGG_RES, n)\n const grid: number[][] = []\n for (let ai = 0; ai < res; ai++) {\n const r0 = Math.floor((ai * n) / res)\n const r1 = Math.floor(((ai + 1) * n) / res)\n const rowArr = new Array<number>(res)\n for (let aj = 0; aj < res; aj++) {\n const c0 = Math.floor((aj * n) / res)\n const c1 = Math.floor(((aj + 1) * n) / res)\n const counter = new Map<number, number>()\n for (let i = r0; i < r1; i++) {\n const row = table[i]\n for (let j = c0; j < c1; j++) {\n const v = idToIdx.get(row[j].id) ?? 0\n counter.set(v, (counter.get(v) ?? 0) + 1)\n }\n }\n let mode = idToIdx.get(table[r0][c0].id) ?? 0\n let best = -1\n for (const [v, c] of counter) {\n if (c > best) { best = c; mode = v }\n }\n rowArr[aj] = mode\n }\n grid.push(rowArr)\n }\n return grid\n }, [group, table, idToIdx, showHeatmap, strategy])\n\n // 向宿主上报实际渲染表格的内容尺寸(供 ViewWindow 设定最小窗口尺寸):\n // 大群告警 / 全屏占位时不渲染网格,回传 null(不强制窗口大小)\n const cellSize = cellSizeProp ?? 50\n // 热力图自适应 cell:显示「全表」(小群全表 或 大群 full 策略)时,cell 无需容纳文字,\n // 自适应缩小使整表在 viewBox 内可见,但不超过 cellSize 上限(不放大)。\n // 这样热力图窗口无论缩到多小都能看清整体色块模式(核心价值)。\n const isFullTable = group !== null && (!isLargeTable || strategy === 'full')\n const heatmapAutoFit = showHeatmap && isFullTable\n const heatmapRenderDim = heatmapAgg ? heatmapAgg.length : strategyIndices.length\n const fitCell = Math.max(4, Math.floor((Math.min(viewBoxSize.width, viewBoxSize.height) - 60) / Math.max(1, heatmapRenderDim)))\n const renderCell = heatmapAutoFit ? Math.min(cellSize, fitCell) : cellSize\n // 热力图(纯色块 + 聚合缩略图)可展示更大群,阈值放宽到 240;普通乘法表(文字)保持 100\n const tableBlocked = group ? isTooLarge(group.order, showHeatmap ? 'heatmap' : 'table', showHeatmap ? maxHeatmapOrder : maxTableOrder) && !forceShow : false\n // 热力图模式下的 full 策略不占位:纯色 cell 直接渲染整表,无需进入全屏\n const tablePlaceholder = !showHeatmap && isLargeTable && strategy === 'full' && !!group && group.order > 30 && !fullscreenOpen\n useEffect(() => {\n if (!group || !table) { onLayoutSize?.(null); return }\n if (tableBlocked || tablePlaceholder) { onLayoutSize?.(null); return }\n const k = heatmapAgg ? heatmapAgg.length : strategyIndices.length\n const padW = showHeatmap ? 0 : TABLE_PAD_W\n const padH = showHeatmap ? 40 : TABLE_PAD_H\n onLayoutSize?.({ width: k * renderCell + padW, height: k * renderCell + padH })\n }, [group, table, tableBlocked, tablePlaceholder, strategyIndices.length, heatmapAgg, renderCell, onLayoutSize, showHeatmap])\n\n const exitFullscreen = useCallback(() => {\n setFullscreenOpen(false)\n applyStrategy('subgroup')\n }, [applyStrategy])\n\n useEffect(() => {\n if (!fullscreenOpen) return\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') exitFullscreen()\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [fullscreenOpen, exitFullscreen])\n\n useEffect(() => {\n if (fullscreenOpen) {\n const body = fsBodyRef.current\n if (body) {\n body.scrollLeft = 0\n body.scrollTop = 0\n }\n }\n }, [fullscreenOpen])\n\n const openFullscreen = () => {\n setFsScale(1)\n setFullscreenOpen(true)\n }\n\n const handleStrategy = (s: TableStrategy) => {\n if (s === strategy) {\n setReroll(r => r + 1)\n return\n }\n if (s === 'full') {\n // 热力图模式的 full 策略:纯色 cell 直接渲染,不弹确认框、不进全屏\n if (!showHeatmap && group && group.order > 30) {\n setConfirmOpen(true)\n return\n }\n applyStrategy('full')\n return\n }\n applyStrategy(s)\n }\n\n const confirmFull = () => {\n setConfirmOpen(false)\n openFullscreen()\n }\n\n const adjustZoom = useCallback((factor: number, cx?: number, cy?: number) => {\n const body = fsBodyRef.current\n if (!body) return\n const rect = body.getBoundingClientRect()\n const mx = cx ?? rect.width / 2\n const my = cy ?? rect.height / 2\n const px = (body.scrollLeft + mx) / fsScale\n const py = (body.scrollTop + my) / fsScale\n const next = Math.min(6, Math.max(0.25, fsScale * factor))\n setFsScale(next)\n requestAnimationFrame(() => {\n body.scrollLeft = px * next - mx\n body.scrollTop = py * next - my\n })\n }, [fsScale])\n\n const onFsSlider = (v: number) => {\n adjustZoom(v / 100 / fsScale)\n }\n\n const onFwPointerDown = (e: RPointerEvent<HTMLDivElement>) => {\n const body = fsBodyRef.current\n if (!body) return\n fsDragRef.current = { x: e.clientX, y: e.clientY, sl: body.scrollLeft, st: body.scrollTop }\n setFsDragging(true)\n body.setPointerCapture(e.pointerId)\n }\n\n const onFwPointerMove = (e: RPointerEvent<HTMLDivElement>) => {\n const body = fsBodyRef.current\n const d = fsDragRef.current\n if (!body || !d) return\n body.scrollLeft = d.sl - (e.clientX - d.x)\n body.scrollTop = d.st - (e.clientY - d.y)\n }\n\n const onFwPointerUp = () => {\n fsDragRef.current = null\n setFsDragging(false)\n }\n\n const onFsScroll = useCallback(() => {\n const body = fsBodyRef.current\n if (!body || fsScrollRaf.current) return\n fsScrollRaf.current = requestAnimationFrame(() => {\n fsScrollRaf.current = 0\n setFsScroll({ l: body.scrollLeft, t: body.scrollTop })\n })\n }, [])\n\n useEffect(() => {\n return () => {\n if (fsScrollRaf.current) cancelAnimationFrame(fsScrollRaf.current)\n }\n }, [])\n\n useEffect(() => {\n if (!fullscreenOpen) return\n const body = fsBodyRef.current\n if (!body) return\n const update = () => setFsViewport({ w: body.clientWidth, h: body.clientHeight })\n update()\n const ro = new ResizeObserver(update)\n ro.observe(body)\n return () => ro.disconnect()\n }, [fullscreenOpen])\n\n const exportFullscreen = () => {\n const svg = fsSvgRef.current\n if (!svg || !group) return\n const clone = svg.cloneNode(true) as SVGSVGElement\n const vb = (svg.getAttribute('viewBox') || '0 0 800 600').trim().split(/\\s+/).map(Number)\n clone.setAttribute('width', String(vb[2] || 800))\n clone.setAttribute('height', String(vb[3] || 600))\n clone.removeAttribute('style')\n const blob = new Blob([new XMLSerializer().serializeToString(clone)], {\n type: 'image/svg+xml;charset=utf-8',\n })\n const sym = group.symbol.replace(/[^A-Za-z0-9]+/g, '_')\n triggerDownload(blob, `table_${sym}_${group.order}x${group.order}.svg`)\n }\n\n if (!group || !table) {\n return (\n <div className=\"view-empty\">\n <p>{noGroupText ?? t('canvas.noGroup')}</p>\n </div>\n )\n }\n\n if (isTooLarge(group.order, 'table', maxTableOrder) && !forceShow) {\n return (\n <div className=\"large-group-warning\">\n <p>{t('canvas.orderTooLarge', { n: group.order })}</p>\n <button className=\"panel-btn\" onClick={requestForceShow}>\n {t('canvas.show')}\n </button>\n </div>\n )\n }\n\n const { elements } = group\n\n const tableWidth = heatmapRenderDim * renderCell\n const tableHeight = heatmapRenderDim * renderCell\n const vw = viewBoxSize.width\n const vh = viewBoxSize.height\n const offsetX = vw / 2 - tableWidth / 2\n const offsetY = vh / 2 - tableHeight / 2\n\n const caption = isLargeTable\n ? strategy === 'subgroup' && subgroupInfo\n ? t('table.subgroupCaption', { label: subgroupInfo.label, order: subgroupInfo.order })\n : strategy === 'random'\n ? t('table.randomCaption', { n: strategyIndices.length })\n : strategy === 'full' && heatmapAgg\n ? t('table.heatmapAggCaption', { n: group.order, res: heatmapAgg.length })\n : ''\n : ''\n\n const showFullPlaceholder = !showHeatmap && isLargeTable && strategy === 'full' && group.order > 30 && !fullscreenOpen\n\n if (showFullPlaceholder) {\n return (\n <>\n <div className=\"table-strategy-bar\">\n {(['subgroup', 'random', 'full'] as TableStrategy[]).map(s => (\n <button\n key={s}\n className={`table-strategy-btn${strategy === s ? ' active' : ''}`}\n onClick={() => handleStrategy(s)}\n >\n {s === 'subgroup'\n ? t('table.strategy.subgroup')\n : s === 'random'\n ? t('table.strategy.random')\n : t('table.strategy.full')}\n </button>\n ))}\n </div>\n <div className=\"large-group-warning\">\n <p>{t('table.fullPlaceholderMsg', { n: group.order })}</p>\n <button className=\"panel-btn\" onClick={openFullscreen}>\n {t('table.fullEnter')}\n </button>\n </div>\n </>\n )\n }\n\n return (\n <>\n {isLargeTable && (\n <div className=\"table-strategy-bar\">\n {(['subgroup', 'random', 'full'] as TableStrategy[]).map(s => (\n <button\n key={s}\n className={`table-strategy-btn${strategy === s ? ' active' : ''}`}\n onClick={() => handleStrategy(s)}\n >\n {s === 'subgroup'\n ? t('table.strategy.subgroup')\n : s === 'random'\n ? t('table.strategy.random')\n : t('table.strategy.full')}\n </button>\n ))}\n {caption && <span className=\"table-strategy-caption\">{caption}</span>}\n </div>\n )}\n\n <svg viewBox={`0 0 ${vw} ${vh}`} className=\"view-svg\" style={{ userSelect: 'none' }}>\n <g transform={`translate(${canvasTransform.x}, ${canvasTransform.y}) scale(${canvasTransform.scale}) translate(${offsetX}, ${offsetY})`}>\n\n {/* Row headers — hidden in heatmap mode */}\n {!showHeatmap && strategyIndices.map((rowIdx, ri) => {\n const rowEl = elements[rowIdx]\n const isSelected = selectedIndices.has(rowIdx)\n const sInfo = subsetElemMap.get(rowIdx)\n const inSubgroup = elementsInAnySubgroup.has(rowIdx)\n const cosetMode = cosetData !== null\n const rowIsCosetAnchor = cosetActiveRowIds.has(rowEl.id)\n const rowCosetIdx = cem.get(rowEl.id)\n const rowCosetHl = rowIsCosetAnchor && rowCosetIdx !== undefined\n\n let headerFill = elementColors[rowIdx % elementColors.length]\n let bg: string | null = null\n if (!cosetMode && isSelected) bg = '#ffd93d33'\n else if (rowCosetHl) bg = (cosetColors ?? [])[rowCosetIdx] + '33'\n else if (!cosetMode && inSubgroup && sInfo) bg = sInfo.color + '33'\n if (!cosetMode && isSelected) headerFill = '#ffd93d'\n\n return (\n <g\n key={rowEl.id}\n transform={`translate(0, ${ri * cellSize})`}\n onClick={() => onSelect?.(rowEl.id, true)}\n style={{ cursor: 'pointer' }}\n >\n {bg && (\n <rect x={-38} y={2} width={33} height={cellSize - 4} fill={bg} rx={4} />\n )}\n <text\n x={-35}\n y={cellSize / 2 + 5}\n textAnchor=\"end\"\n fill={headerFill}\n fontSize={14}\n fontFamily=\"serif\"\n fontWeight={isSelected ? 'bold' : 'normal'}\n style={{ userSelect: 'none' }}\n >\n {rowEl.label}\n </text>\n </g>\n )\n })}\n\n {/* Column headers — hidden in heatmap mode */}\n {!showHeatmap && strategyIndices.map((colIdx, ci) => {\n const colEl = elements[colIdx]\n const isSelected = selectedIndices.has(colIdx)\n const sInfo = subsetElemMap.get(colIdx)\n const inSubgroup = elementsInAnySubgroup.has(colIdx)\n const cosetMode = cosetData !== null\n const colIsCosetAnchor = cosetActiveColIds.has(colEl.id)\n const colCosetIdx = cem.get(colEl.id)\n const colCosetHl = colIsCosetAnchor && colCosetIdx !== undefined\n\n let headerFill = elementColors[colIdx % elementColors.length]\n let bg: string | null = null\n if (!cosetMode && isSelected) bg = '#ffd93d33'\n else if (colCosetHl) bg = (cosetColors ?? [])[colCosetIdx] + '33'\n else if (!cosetMode && inSubgroup && sInfo) bg = sInfo.color + '33'\n if (!cosetMode && isSelected) headerFill = '#ffd93d'\n\n return (\n <g\n key={`head-${colEl.id}`}\n onClick={() => onSelect?.(colEl.id, true)}\n style={{ cursor: 'pointer' }}\n >\n {bg && (\n <rect x={ci * cellSize + 2} y={-16} width={cellSize - 4} height={18} fill={bg} rx={4} />\n )}\n <text\n x={ci * cellSize + cellSize / 2}\n y={-12}\n textAnchor=\"middle\"\n fill={headerFill}\n fontSize={14}\n fontFamily=\"serif\"\n fontWeight={isSelected ? 'bold' : 'normal'}\n style={{ userSelect: 'none' }}\n >\n {colEl.label}\n </text>\n </g>\n )\n })}\n\n {/* Heatmap aggregate thumbnail: downsampled mode-color blocks for large groups */}\n {heatmapAgg && heatmapAgg.map((aggRow, ai) =>\n aggRow.map((resultIdx, aj) => {\n const resultColor = elementColors[resultIdx % elementColors.length]\n const heatGap = renderCell <= 8 ? 0.5 : renderCell <= 20 ? 1 : 2\n const heatR = renderCell <= 8 ? 1 : renderCell <= 20 ? 2 : 3\n return (\n <g\n key={`agg-${ai}-${aj}`}\n transform={`translate(${aj * renderCell}, ${ai * renderCell})`}\n >\n <rect\n width={renderCell - heatGap}\n height={renderCell - heatGap}\n fill={resultColor}\n stroke=\"rgba(0,0,0,0.12)\"\n strokeWidth={renderCell <= 8 ? 0.2 : 0.5}\n rx={heatR}\n />\n </g>\n )\n })\n )}\n\n {/* Table cells */}\n {!heatmapAgg && strategyIndices.map((rowIdx, ri) =>\n strategyIndices.map((colIdx, ci) => {\n const rowEl = elements[rowIdx]\n const colEl = elements[colIdx]\n const result = table[rowIdx][colIdx]\n const resultColor = getElementColor(result.label)\n\n const isRowSel = selectedIndices.has(rowIdx)\n const isColSel = selectedIndices.has(colIdx)\n\n const sgKey = `${rowIdx},${colIdx}`\n const sgColor = subgroupCellColors.get(sgKey)\n\n const identityIdx = idToIdx.get(group.identity.id) ?? -1\n const nonSubRow = identityIdx >= 0 && rowIdx === identityIdx && nonSubgroupSubsetIndices.has(colIdx)\n const nonSubCol = identityIdx >= 0 && colIdx === identityIdx && nonSubgroupSubsetIndices.has(rowIdx)\n\n const colInSubgroup = cosetSubgroupIndices.has(colIdx)\n const rowInSubgroup = cosetSubgroupIndices.has(rowIdx)\n const cosetMode = cosetData !== null\n const rowIsCosetAnchor = cosetActiveRowIds.has(rowEl.id)\n const colIsCosetAnchor = cosetActiveColIds.has(colEl.id)\n\n const isLeftCosetCell = cosetType === 'left' && rowIsCosetAnchor && colInSubgroup\n const isRightCosetCell = cosetType === 'right' && colIsCosetAnchor && rowInSubgroup\n const isCosetCell = isLeftCosetCell || isRightCosetCell\n\n // Heatmap mode: solid fill, thin border\n if (showHeatmap) {\n // 大群热力图:cell 很小时用更小的间隙与圆角,保证色块紧凑、宏观结构清晰\n const heatGap = renderCell <= 8 ? 0.5 : renderCell <= 20 ? 1 : 2\n const heatR = renderCell <= 8 ? 1 : renderCell <= 20 ? 2 : 3\n let cellFill = resultColor\n let cellStroke = 'rgba(0,0,0,0.18)'\n let cellStrokeW = renderCell <= 8 ? 0.2 : 0.5\n\n if (isCosetCell) {\n const elId = cosetType === 'left' ? rowEl.id : colEl.id\n const cIdx = cem.get(elId)\n const cColor = cIdx !== undefined ? (cosetColors ?? [])[cIdx] : '#888'\n cellStroke = cColor\n cellStrokeW = 3\n } else if (sgColor) {\n cellStroke = sgColor\n cellStrokeW = 2.5\n } else if (!cosetMode && isRowSel && isColSel) {\n cellStroke = '#ffd93d'\n cellStrokeW = 2.5\n } else if (!cosetMode && (isRowSel || isColSel)) {\n cellStroke = '#ffd93d88'\n cellStrokeW = 1.5\n } else if (nonSubRow || nonSubCol) {\n cellFill = 'var(--table-cell-bg)'\n cellStroke = 'var(--table-cell-border)'\n cellStrokeW = 1.5\n }\n\n return (\n <g\n key={`${rowEl.id}-${colEl.id}`}\n transform={`translate(${ci * renderCell}, ${ri * renderCell})`}\n onClick={() => {\n const targetEl = elements.find(e => e.id === result.id)\n if (targetEl) onSelect?.(targetEl.id, true)\n }}\n onMouseEnter={() => {\n const targetEl = elements.find(e => e.id === result.id)\n if (targetEl) onHover?.(targetEl)\n }}\n onMouseLeave={() => onHover?.(null)}\n style={{ cursor: 'pointer' }}\n >\n <rect\n width={renderCell - heatGap}\n height={renderCell - heatGap}\n fill={cellFill}\n stroke={cellStroke}\n strokeWidth={cellStrokeW}\n rx={heatR}\n />\n </g>\n )\n }\n\n // Normal table mode: semi-transparent fill + text\n let cellFill = resultColor + '22'\n let cellStroke = resultColor\n let cellStrokeW = 0.5\n\n if (isCosetCell) {\n const elId = cosetType === 'left' ? rowEl.id : colEl.id\n const cIdx = cem.get(elId)\n const cColor = cIdx !== undefined ? (cosetColors ?? [])[cIdx] : '#888'\n cellFill = cColor + '40'\n cellStroke = cColor\n cellStrokeW = 2.5\n } else if (sgColor) {\n cellFill = sgColor + '28'\n cellStroke = sgColor\n cellStrokeW = 2\n } else if (!cosetMode && isRowSel && isColSel) {\n cellFill = '#ffd93d22'\n cellStroke = '#ffd93d'\n cellStrokeW = 2\n } else if (!cosetMode && (isRowSel || isColSel)) {\n cellFill = '#ffd93d15'\n cellStroke = '#ffd93d88'\n cellStrokeW = 1\n } else if (nonSubRow || nonSubCol) {\n cellFill = 'var(--table-cell-bg)'\n cellStroke = 'var(--table-cell-border)'\n cellStrokeW = 1.5\n }\n\n return (\n <g\n key={`${rowEl.id}-${colEl.id}`}\n transform={`translate(${ci * renderCell}, ${ri * renderCell})`}\n onClick={() => {\n const targetEl = elements.find(e => e.id === result.id)\n if (targetEl) onSelect?.(targetEl.id, true)\n }}\n onMouseEnter={() => {\n const targetEl = elements.find(e => e.id === result.id)\n if (targetEl) onHover?.(targetEl)\n }}\n onMouseLeave={() => onHover?.(null)}\n style={{ cursor: 'pointer' }}\n >\n <rect\n width={renderCell - 2}\n height={renderCell - 2}\n fill={cellFill}\n stroke={cellStroke}\n strokeWidth={cellStrokeW}\n rx={4}\n />\n <text\n x={renderCell / 2}\n y={renderCell / 2 + 5}\n textAnchor=\"middle\"\n fill={resultColor}\n fontSize={13}\n fontFamily=\"serif\"\n style={{ userSelect: 'none', pointerEvents: 'none' }}\n >\n {result.label}\n </text>\n </g>\n )\n })\n )}\n </g>\n\n <text x={vw / 2} y={tableHeight + offsetY + 35} textAnchor=\"middle\" fill=\"#666\" fontSize={11} style={{ userSelect: 'none' }}>\n {t('table.footer1')}\n </text>\n\n <text x={vw / 2} y={tableHeight + offsetY + 50} textAnchor=\"middle\" fill=\"#666\" fontSize={10} style={{ userSelect: 'none' }}>\n {t('table.footer2')}\n </text>\n </svg>\n\n {confirmOpen && (\n <div className=\"table-confirm-overlay\">\n <div className=\"table-confirm-modal\">\n <div className=\"table-confirm-title\">{t('table.fullConfirmTitle')}</div>\n <div className=\"table-confirm-msg\">\n {t('table.fullConfirmMsg', { n: group.order })}\n </div>\n <div className=\"table-confirm-actions\">\n <button className=\"panel-btn\" onClick={() => setConfirmOpen(false)}>\n {t('table.confirmCancel')}\n </button>\n <button className=\"panel-btn\" onClick={confirmFull}>\n {t('table.confirmOk')}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {fullscreenOpen && (\n <div className=\"table-fullscreen\">\n <div className=\"table-fullscreen-header\">\n <div className=\"table-fullscreen-title\">\n {t('table.fullTitle', { symbol: group.symbol, n: group.order })}\n </div>\n <div className=\"table-fullscreen-toolbar\">\n <button\n className=\"table-fs-btn\"\n title={t('table.fullZoomOut')}\n onClick={() => adjustZoom(1 / 1.25)}\n >\n −\n </button>\n <button\n className=\"table-fs-btn\"\n title={t('table.fullZoomIn')}\n onClick={() => adjustZoom(1.25)}\n >\n +\n </button>\n <button\n className=\"table-fs-btn\"\n title={t('table.fullZoomReset')}\n onClick={() => adjustZoom(1 / fsScale)}\n >\n ⟳\n </button>\n <input\n type=\"range\"\n className=\"table-fs-slider\"\n min={25}\n max={600}\n step={1}\n value={Math.round(fsScale * 100)}\n aria-label={t('table.zoomSlider')}\n onChange={(e) => onFsSlider(Number(e.target.value))}\n />\n <button className=\"panel-btn\" onClick={exportFullscreen}>\n {t('table.fullExport')}\n </button>\n <button className=\"panel-btn\" onClick={exitFullscreen}>\n {t('table.fullExit')}\n </button>\n </div>\n </div>\n <div\n className={`table-fullscreen-body${fsDragging ? ' dragging' : ''}`}\n ref={fsBodyRef}\n onScroll={onFsScroll}\n onPointerDown={onFwPointerDown}\n onPointerMove={onFwPointerMove}\n onPointerUp={onFwPointerUp}\n onPointerLeave={onFwPointerUp}\n >\n {(() => {\n const n = group.order\n const fsCell = 32\n const padL = 44\n const padT = 26\n const padB = 34\n const tw = n * fsCell + padL + 16\n const th = n * fsCell + padT + padB\n const fsIdentityIdx = idToIdx.get(group.identity.id) ?? -1\n const fvw = fsViewport.w || 960\n const fvh = fsViewport.h || 600\n const viewL = fsScroll.l / fsScale\n const viewT = fsScroll.t / fsScale\n const viewW = fvw / fsScale\n const viewH = fvh / fsScale\n const buf = 3\n const cStart = Math.max(0, Math.floor((viewL - padL) / fsCell) - buf)\n const cEnd = Math.min(n - 1, Math.ceil((viewL + viewW - padL) / fsCell) + buf)\n const rStart = Math.max(0, Math.floor((viewT - padT) / fsCell) - buf)\n const rEnd = Math.min(n - 1, Math.ceil((viewT + viewH - padT) / fsCell) + buf)\n const rowIdxList = Array.from({ length: rEnd - rStart + 1 }, (_, k) => rStart + k)\n const colIdxList = Array.from({ length: cEnd - cStart + 1 }, (_, k) => cStart + k)\n return (\n <svg\n ref={fsSvgRef}\n className=\"table-fullscreen-svg\"\n viewBox={`0 0 ${tw} ${th}`}\n style={{ width: tw * fsScale, height: th * fsScale }}\n >\n <g transform={`translate(${showHeatmap ? 8 : padL}, ${showHeatmap ? 8 : padT})`}>\n {!showHeatmap && rowIdxList.map((rowIdx) => {\n const rowEl = elements[rowIdx]\n return (\n <text\n key={`fr-${rowEl.id}`}\n x={-6}\n y={rowIdx * fsCell + fsCell / 2 + 4}\n textAnchor=\"end\"\n fill={elementColors[rowIdx % elementColors.length]}\n fontSize={11}\n fontFamily=\"serif\"\n >\n {rowEl.label}\n </text>\n )\n })}\n {!showHeatmap && colIdxList.map((colIdx) => {\n const colEl = elements[colIdx]\n return (\n <text\n key={`fc-${colEl.id}`}\n x={colIdx * fsCell + fsCell / 2}\n y={-6}\n textAnchor=\"middle\"\n fill={elementColors[colIdx % elementColors.length]}\n fontSize={11}\n fontFamily=\"serif\"\n >\n {colEl.label}\n </text>\n )\n })}\n {rowIdxList.map(rowIdx =>\n colIdxList.map(colIdx => {\n const rowEl = elements[rowIdx]\n const colEl = elements[colIdx]\n const result = table[rowIdx][colIdx]\n const resultColor = getElementColor(result.label)\n const sgKey = `${rowIdx},${colIdx}`\n const sgColor = subgroupCellColors.get(sgKey)\n const isRowSel = selectedIndices.has(rowIdx)\n const isColSel = selectedIndices.has(colIdx)\n const nonSubRow = fsIdentityIdx >= 0 && rowIdx === fsIdentityIdx && nonSubgroupSubsetIndices.has(colIdx)\n const nonSubCol = fsIdentityIdx >= 0 && colIdx === fsIdentityIdx && nonSubgroupSubsetIndices.has(rowIdx)\n const cosetMode = cosetData !== null\n const rowIsCosetAnchor = cosetActiveRowIds.has(rowEl.id)\n const colIsCosetAnchor = cosetActiveColIds.has(colEl.id)\n const colInSubgroup = cosetSubgroupIndices.has(colIdx)\n const rowInSubgroup = cosetSubgroupIndices.has(rowIdx)\n const isLeftCosetCell = cosetType === 'left' && rowIsCosetAnchor && colInSubgroup\n const isRightCosetCell = cosetType === 'right' && colIsCosetAnchor && rowInSubgroup\n const isCosetCell = isLeftCosetCell || isRightCosetCell\n\n if (showHeatmap) {\n let cellFill = resultColor\n let cellStroke = 'rgba(0,0,0,0.18)'\n let cellStrokeW = 0.5\n\n if (isCosetCell) {\n const elId = cosetType === 'left' ? rowEl.id : colEl.id\n const cIdx = cem.get(elId)\n const cColor = cIdx !== undefined ? (cosetColors ?? [])[cIdx] : '#888'\n cellStroke = cColor\n cellStrokeW = 3\n } else if (sgColor) {\n cellStroke = sgColor\n cellStrokeW = 2.5\n } else if (!cosetMode && isRowSel && isColSel) {\n cellStroke = '#ffd93d'\n cellStrokeW = 2.5\n } else if (!cosetMode && (isRowSel || isColSel)) {\n cellStroke = '#ffd93d88'\n cellStrokeW = 1.5\n } else if (nonSubRow || nonSubCol) {\n cellFill = 'var(--table-cell-bg)'\n cellStroke = 'var(--table-cell-border)'\n cellStrokeW = 1.5\n }\n\n return (\n <g key={`${rowEl.id}-${colEl.id}`} transform={`translate(${colIdx * fsCell}, ${rowIdx * fsCell})`}>\n <rect\n width={fsCell - 2}\n height={fsCell - 2}\n fill={cellFill}\n stroke={cellStroke}\n strokeWidth={cellStrokeW}\n rx={2}\n />\n </g>\n )\n }\n\n let cellFill = resultColor + '30'\n let cellStroke = resultColor\n let cellStrokeW = 0.5\n\n if (isCosetCell) {\n const elId = cosetType === 'left' ? rowEl.id : colEl.id\n const cIdx = cem.get(elId)\n const cColor = cIdx !== undefined ? (cosetColors ?? [])[cIdx] : '#888'\n cellFill = cColor + '40'\n cellStroke = cColor\n cellStrokeW = 2.5\n } else if (sgColor) {\n cellFill = sgColor + '28'\n cellStroke = sgColor\n cellStrokeW = 2\n } else if (!cosetMode && isRowSel && isColSel) {\n cellFill = '#ffd93d22'\n cellStroke = '#ffd93d'\n cellStrokeW = 2\n } else if (!cosetMode && (isRowSel || isColSel)) {\n cellFill = '#ffd93d15'\n cellStroke = '#ffd93d88'\n cellStrokeW = 1\n } else if (nonSubRow || nonSubCol) {\n cellFill = '#ffffff0d'\n cellStroke = '#8899aa'\n cellStrokeW = 1.5\n }\n\n return (\n <g key={`${rowEl.id}-${colEl.id}`} transform={`translate(${colIdx * fsCell}, ${rowIdx * fsCell})`}>\n <rect\n width={fsCell - 2}\n height={fsCell - 2}\n fill={cellFill}\n stroke={cellStroke}\n strokeWidth={cellStrokeW}\n rx={2}\n />\n <text\n x={fsCell / 2}\n y={fsCell / 2 + 4}\n textAnchor=\"middle\"\n fill={resultColor}\n fontSize={11}\n fontFamily=\"serif\"\n style={{ pointerEvents: 'none' }}\n >\n {result.label}\n </text>\n </g>\n )\n })\n )}\n </g>\n <text\n x={tw / 2}\n y={th - 10}\n textAnchor=\"middle\"\n fill=\"#888\"\n fontSize={12}\n >\n {t('table.footer1')}\n </text>\n </svg>\n )\n })()}\n </div>\n </div>\n )}\n </>\n )\n}\n","import { useMemo, useRef, useState } from 'react'\nimport { SceneThemeRoot, type SceneTheme } from './SceneThemeRoot'\nimport { useTranslation } from '../../i18n/useTranslation'\nimport { texify, renderTex } from '../../utils/texify'\nimport type { Group, GroupActionArrow, GroupActionComputation, GroupActionKind, GroupElement, CanvasTransform } from '../../core/types'\nimport { computeFixedPoints, computeCycleCandidates, type CustomArrowError } from '../../core/algebra/actions'\n\n// ─── Action props 化内核(批次六 FGVE) ─────────────────────────────────\n// 受控 ViewWindow(conjugation/regular/custom 三来源)与主画布(经 context 壳\n// ActionView)共用。group/computation 之外全部可选:主画布壳由全局 Provider 组装,\n// 窗口引擎自包含时自算 computation 并以本地/受控态驱动选中与编辑。\n\nconst NODE_R = 28\nconst CLUSTER_PAD = 26\nconst CLUSTER_GAP = 90\nconst CHIP_W = 100\nconst CHIP_H = 30\nconst CHIP_GAP = 10\nconst CHIP_ROW_H = CHIP_H + 10\nconst CHIP_PER_ROW = 8\nconst GRP_PAD = 8\nconst GRP_HDR = 18\nconst GRP_GAP = 14\nconst HOVER_COLOR = '#ffd93d'\nconst SNAP_R = 44\n\nfunction clusterRadius(size: number): number {\n // 相邻节点弦长 = 2r·sin(π/size) ≈ 220,两端各收缩 ~50(nodeR+headLen)后边仍 ~120 可见\n if (size <= 1) return 52\n return Math.max(52, Math.ceil(110 / Math.sin(Math.PI / size)))\n}\n\nfunction arrowHeadPoints(ex: number, ey: number, angle: number, size = 10): string {\n const a1 = angle - Math.PI / 6\n const a2 = angle + Math.PI / 6\n return `${ex},${ey} ${ex - Math.cos(a1) * size},${ey - Math.sin(a1) * size} ${ex - Math.cos(a2) * size},${ey - Math.sin(a2) * size}`\n}\n\ninterface EdgeProps {\n sx: number\n sy: number\n ex: number\n ey: number\n color: string\n width?: number\n dashed?: boolean\n dir?: 1 | -1\n opacity?: number\n headSize?: number\n nodeR?: number\n offset?: number\n tFrom?: { x: number; y: number }\n onClick?: () => void\n onDrop?: (e: React.DragEvent) => void\n highlight?: boolean\n}\n\nfunction DirectedEdge({ sx, sy, ex, ey, color, width = 2.2, dashed, dir: _dir = 1, opacity = 0.85, headSize = 12, nodeR = 0, offset = 0, tFrom, onClick, onDrop, highlight }: EdgeProps) {\n const dx = ex - sx\n const dy = ey - sy\n const dist = Math.sqrt(dx * dx + dy * dy) || 1\n const ux = dx / dist\n const uy = dy / dist\n const headLen = Math.min(headSize * 1.25, Math.max(12, dist * 0.25))\n const arrowSize = Math.min(headSize, headLen)\n const fx = tFrom ? tFrom.x : -uy\n const fy = tFrom ? tFrom.y : ux\n const ax = sx + ux * nodeR + fx * offset\n const ay = sy + uy * nodeR + fy * offset\n const bx = ex - ux * (nodeR + headLen) + fx * offset\n const by = ey - uy * (nodeR + headLen) + fy * offset\n const c1x = (ax + bx) / 2\n const c1y = (ay + by) / 2\n const angle = Math.atan2(by - c1y, bx - c1x)\n const d = `M${ax},${ay} Q${c1x},${c1y} ${bx},${by}`\n\n return (\n <g>\n <path\n d={d}\n fill=\"none\"\n stroke={color}\n strokeWidth={width}\n strokeDasharray={dashed ? '5 4' : undefined}\n strokeOpacity={opacity}\n strokeLinecap=\"round\"\n />\n <polygon\n points={arrowHeadPoints(bx, by, angle, arrowSize)}\n fill={color}\n stroke={color}\n strokeWidth={0.5}\n opacity={opacity}\n />\n {highlight && (\n <path\n d={d}\n fill=\"none\"\n stroke={HOVER_COLOR}\n strokeWidth={6.5}\n strokeDasharray={dashed ? '8 5' : undefined}\n strokeOpacity={0.95}\n strokeLinecap=\"round\"\n style={{ pointerEvents: 'none' }}\n />\n )}\n {(onClick || onDrop) && (\n <path\n d={d}\n fill=\"none\"\n stroke=\"transparent\"\n strokeWidth={16}\n style={{ cursor: onClick ? 'pointer' : 'default', pointerEvents: 'stroke' }}\n onClick={(e) => { e.stopPropagation(); onClick?.() }}\n onDragOver={(e) => { if (onDrop) { e.preventDefault(); e.dataTransfer.dropEffect = 'copy' } }}\n onDrop={(e) => { if (onDrop) { e.preventDefault(); e.stopPropagation(); onDrop(e) } }}\n />\n )}\n </g>\n )\n}\n\nfunction ClusterNode({\n x, y, label, isSelected, isFixed, nodeR = NODE_R, onClick, onPointerDown, showNumber, onHoverIn, onHoverOut, testId,\n}: {\n x: number\n y: number\n label: string\n isSelected: boolean\n isFixed: boolean\n nodeR?: number\n onClick?: () => void\n onPointerDown?: (e: React.PointerEvent) => void\n showNumber?: number\n /** 悬停进入(窗口接就地气泡 + 金色箭头联动;主画布壳不传) */\n onHoverIn?: () => void\n onHoverOut?: () => void\n /** 测试钩子(action-node 显示态环节点 / action-edit-node 编辑态数字节点) */\n testId?: string\n}) {\n const fill = isSelected ? 'var(--node-fill-selected)' : 'var(--node-fill)'\n const stroke = isSelected ? HOVER_COLOR : 'var(--node-stroke)'\n return (\n <g\n transform={`translate(${x}, ${y})`}\n onClick={(e) => { e.stopPropagation(); onClick?.() }}\n onPointerDown={onPointerDown}\n onMouseEnter={onHoverIn}\n onMouseLeave={onHoverOut}\n data-testid={testId}\n style={{ cursor: onClick || onPointerDown ? 'pointer' : 'default' }}\n >\n <circle r={nodeR} fill={fill} stroke={stroke} strokeWidth={isSelected ? 3 : 2} filter=\"url(#node-shadow)\" />\n {isFixed && (\n <text x={nodeR - 2} y={-(nodeR + 2)} textAnchor=\"middle\" fill={HOVER_COLOR} fontSize={13} fontWeight=\"bold\">★</text>\n )}\n {label !== '' ? (\n <foreignObject\n x={-nodeR}\n y={-12}\n width={nodeR * 2}\n height={24}\n style={{ pointerEvents: 'none', userSelect: 'none' }}\n >\n <div\n style={{\n display: 'flex', alignItems: 'center', justifyContent: 'center',\n width: '100%', height: '100%', color: 'var(--node-text)', fontSize: '13px',\n whiteSpace: 'nowrap',\n }}\n dangerouslySetInnerHTML={{ __html: label }}\n />\n </foreignObject>\n ) : showNumber !== undefined ? (\n <text y={4} textAnchor=\"middle\" fill=\"var(--node-text)\" fontSize={14} style={{ pointerEvents: 'none' }}>\n {showNumber}\n </text>\n ) : null}\n </g>\n )\n}\n\nfunction ElementChip({ label, color, symbol, isSelected, onClick, onHover, onPointerDown }: {\n label: string\n color?: string\n symbol?: string\n isSelected: boolean\n onClick: () => void\n onHover?: (on: boolean) => void\n onPointerDown?: (e: React.PointerEvent, symbol: string) => void\n}) {\n return (\n <g\n onClick={(e) => { e.stopPropagation(); onClick() }}\n onMouseEnter={() => onHover?.(true)}\n onMouseLeave={() => onHover?.(false)}\n onPointerDown={symbol && onPointerDown ? (e) => onPointerDown(e, symbol) : undefined}\n style={{ cursor: 'pointer', touchAction: 'none' }}\n >\n <rect\n width={CHIP_W}\n height={CHIP_H}\n rx={6}\n fill={isSelected ? 'var(--node-fill-selected)' : 'var(--node-fill)'}\n stroke={isSelected ? HOVER_COLOR : (color || 'var(--node-stroke)')}\n strokeWidth={isSelected ? 2.5 : 1.5}\n />\n <foreignObject\n x={0}\n y={0}\n width={CHIP_W}\n height={CHIP_H}\n style={{ pointerEvents: 'none', userSelect: 'none' }}\n >\n <div\n style={{\n display: 'flex', alignItems: 'center', justifyContent: 'center',\n width: '100%', height: '100%', color: 'var(--node-text)', fontSize: '14px',\n whiteSpace: 'nowrap', overflow: 'hidden',\n }}\n dangerouslySetInnerHTML={{ __html: label }}\n />\n </foreignObject>\n </g>\n )\n}\n\nconst UNBOUND_COLOR = '#f59e0b'\n\nfunction quadPoint(p0: { x: number; y: number }, c: { x: number; y: number }, p1: { x: number; y: number }, t: number) {\n const mt = 1 - t\n return {\n x: mt * mt * p0.x + 2 * mt * t * c.x + t * t * p1.x,\n y: mt * mt * p0.y + 2 * mt * t * c.y + t * t * p1.y,\n }\n}\n\nfunction distToArrow(from: { x: number; y: number }, to: { x: number; y: number }, p: { x: number; y: number }): number {\n const dx = to.x - from.x\n const dy = to.y - from.y\n const dist = Math.sqrt(dx * dx + dy * dy) || 1\n const ux = -dy / dist\n const uy = dx / dist\n const c = { x: (from.x + to.x) / 2 + ux * 8, y: (from.y + to.y) / 2 + uy * 8 }\n let best = Infinity\n for (let i = 0; i <= 20; i++) {\n const q = quadPoint(from, c, to, i / 20)\n best = Math.min(best, Math.hypot(q.x - p.x, q.y - p.y))\n }\n return best\n}\n\ninterface CustomActionEditorProps {\n group: Group\n vw: number\n vh: number\n setSize: number\n arrows: GroupActionArrow[]\n error: CustomArrowError | null\n onAddArrow: (from: number, to: number, generatorId?: string | null) => void\n onBindArrow: (from: number, to: number, generatorId: string) => void\n onRemoveArrow: (from: number, generatorId?: string | null, to?: number) => void\n onReplaceGenArrows: (generatorId: string | null, pairs: [number, number][]) => void\n}\n\nfunction CustomActionEditor({ group, vw, vh, setSize: actionSetSize, arrows: actionArrows, error: actionError, onAddArrow: addArrow, onBindArrow: bindArrow, onRemoveArrow: removeArrow, onReplaceGenArrows: replaceGenArrows }: CustomActionEditorProps) {\n const { t } = useTranslation()\n const [selectedGen, setSelectedGen] = useState<string | null>(null)\n const [drag, setDrag] = useState<{ symbol: string; x: number; y: number } | null>(null)\n const [hoverArrow, setHoverArrow] = useState<number | null>(null)\n const [draw, setDraw] = useState<{ from: number; x: number; y: number; snap: number | null } | null>(null)\n const drawInfoRef = useRef<{ from: number; origin: { x: number; y: number }; snap: number | null; justStarted: boolean; justPicked: boolean } | null>(null)\n const movedRef = useRef(false)\n const dragRef = useRef<{ symbol: string; from: number } | null>(null)\n const downPosRef = useRef<{ x: number; y: number } | null>(null)\n const dragMovedRef = useRef(false)\n const hoverArrowRef = useRef<number | null>(null)\n\n const n = actionSetSize\n const ringR = Math.max(220, n * 22)\n const cx = vw / 2\n const cy = vh / 2 + 40\n const pos = (i: number) => {\n const angle = (i / n) * 2 * Math.PI - Math.PI / 2\n return { x: cx + Math.cos(angle) * ringR, y: cy + Math.sin(angle) * ringR }\n }\n\n const genColor = (symbol: string) => {\n const gen = group.generators.find(g => g.symbol === symbol)\n return gen?.color || 'var(--node-stroke)'\n }\n\n const toViewBox = (clientX: number, clientY: number, svg: SVGSVGElement) => {\n const r = svg.getBoundingClientRect()\n const scale = Math.min(r.width / vw, r.height / vh)\n const x0 = r.left + (r.width - vw * scale) / 2\n const y0 = r.top + (r.height - vh * scale) / 2\n return { x: (clientX - x0) / scale, y: (clientY - y0) / scale }\n }\n\n const startDrag = (e: React.PointerEvent, symbol: string) => {\n if (e.button !== 0) return\n const svg = (e.currentTarget as SVGElement).ownerSVGElement\n if (!svg) return\n e.preventDefault()\n e.stopPropagation()\n ;(e.currentTarget as Element).setPointerCapture(e.pointerId)\n const p = toViewBox(e.clientX, e.clientY, svg)\n dragMovedRef.current = false\n downPosRef.current = p\n dragRef.current = { symbol, from: -1 }\n setDrag({ symbol, x: p.x, y: p.y })\n }\n\n const onDragMove = (e: React.PointerEvent) => {\n if (!dragRef.current) return\n const svg = (e.currentTarget as SVGElement).ownerSVGElement\n if (!svg) return\n const p = toViewBox(e.clientX, e.clientY, svg)\n if (downPosRef.current && Math.hypot(p.x - downPosRef.current.x, p.y - downPosRef.current.y) > 14) {\n dragMovedRef.current = true\n }\n let bestIdx: number | null = null\n let bestDist = 48\n actionArrows.forEach((a, i) => {\n if (a.generatorId !== null) return\n const d = distToArrow(pos(a.from), pos(a.to), p)\n if (d < bestDist) {\n bestDist = d\n bestIdx = i\n }\n })\n hoverArrowRef.current = bestIdx\n setHoverArrow(bestIdx)\n setDrag(d => (d ? { ...d, x: p.x, y: p.y } : d))\n }\n\n const onDragEnd = () => {\n if (!dragRef.current) return\n const targetIdx = hoverArrowRef.current\n const moved = dragMovedRef.current\n const symbol = dragRef.current.symbol\n dragRef.current = null\n downPosRef.current = null\n hoverArrowRef.current = null\n setDrag(null)\n setHoverArrow(null)\n if (moved && targetIdx !== null) {\n const a = actionArrows[targetIdx]\n if (a && a.generatorId === null) bindArrow(a.from, a.to, symbol)\n }\n window.setTimeout(() => { dragMovedRef.current = false }, 0)\n }\n\n const startArrowDraw = (e: React.PointerEvent, i: number) => {\n if (e.button !== 0) return\n if (drawInfoRef.current) return\n const svg = (e.currentTarget as SVGElement).ownerSVGElement\n if (!svg) return\n e.preventDefault()\n e.stopPropagation()\n ;(e.currentTarget as Element).setPointerCapture(e.pointerId)\n const p = toViewBox(e.clientX, e.clientY, svg)\n movedRef.current = false\n drawInfoRef.current = { from: i, origin: p, snap: null, justStarted: true, justPicked: false }\n setDraw({ from: i, x: p.x, y: p.y, snap: null })\n }\n\n const onArrowMove = (e: React.PointerEvent) => {\n const info = drawInfoRef.current\n if (!info) return\n const svg = (e.currentTarget as SVGElement).ownerSVGElement\n if (!svg) return\n const p = toViewBox(e.clientX, e.clientY, svg)\n if (Math.hypot(p.x - info.origin.x, p.y - info.origin.y) > 6) movedRef.current = true\n let snap: number | null = null\n for (let j = 0; j < n; j++) {\n const q = pos(j)\n if (Math.hypot(p.x - q.x, p.y - q.y) < SNAP_R) {\n snap = j\n break\n }\n }\n drawInfoRef.current = { ...info, snap }\n setDraw(d => (d ? { ...d, x: p.x, y: p.y, snap } : d))\n }\n\n const deployArrow = (from: number, to: number) => {\n addArrow(from, to, selectedGen)\n drawInfoRef.current = null\n setDraw(null)\n }\n\n const onArrowUp = () => {\n const info = drawInfoRef.current\n if (!info) return\n if (movedRef.current) {\n drawInfoRef.current = null\n setDraw(null)\n if (info.snap !== null && info.snap !== info.from) {\n addArrow(info.from, info.snap, selectedGen)\n }\n return\n }\n if (info.justStarted) {\n drawInfoRef.current = { ...info, justStarted: false, justPicked: true }\n }\n }\n\n const k = group.generators.length\n const genColX = 60\n const genTop = cy - ((k - 1) / 2) * CHIP_ROW_H\n const genChips = group.generators.map((gen, i) => {\n return (\n <g\n key={`genchip-${i}`}\n transform={`translate(${genColX}, ${genTop + i * CHIP_ROW_H})`}\n onPointerMove={onDragMove}\n onPointerUp={onDragEnd}\n >\n <ElementChip\n label={renderTex(texify(gen.symbol))}\n color={gen.color}\n symbol={gen.symbol}\n isSelected={selectedGen === gen.symbol}\n onClick={() => { if (!dragMovedRef.current) setSelectedGen(prev => (prev === gen.symbol ? null : gen.symbol)) }}\n onPointerDown={startDrag}\n />\n </g>\n )\n })\n\n const dirCount = new Map<string, number>()\n const dirIndex = new Map<number, number>()\n actionArrows.forEach((a, i) => {\n if (a.from === a.to) return\n const key = `${Math.min(a.from, a.to)}|${Math.max(a.from, a.to)}`\n const dk = a.from < a.to ? `${key}f` : `${key}b`\n const c = dirCount.get(dk) ?? 0\n dirCount.set(dk, c + 1)\n dirIndex.set(i, c)\n })\n\n const loopGroups = new Map<number, number[]>()\n actionArrows.forEach((a, i) => {\n if (a.from !== a.to) return\n const arr = loopGroups.get(a.from)\n if (arr) arr.push(i)\n else loopGroups.set(a.from, [i])\n })\n const loopSlot = new Map<number, number>()\n loopGroups.forEach(arr => arr.forEach((idx, slot) => loopSlot.set(idx, slot)))\n\n const arrowsEls = actionArrows.map((a, i) => {\n const from = pos(a.from)\n const to = pos(a.to)\n const isUnbound = a.generatorId === null\n const color = a.generatorId === null ? UNBOUND_COLOR : genColor(a.generatorId)\n const handleClick = () => {\n if (dragMovedRef.current) return\n if (isUnbound) {\n if (selectedGen) bindArrow(a.from, a.to, selectedGen)\n else removeArrow(a.from, null, a.to)\n } else {\n removeArrow(a.from, a.generatorId)\n }\n }\n if (a.from === a.to) {\n const slot = loopSlot.get(i) ?? 0\n const cy = from.y - 32 + slot * 24\n return (\n <g key={`loop-${a.generatorId ?? 'u'}-${a.from}`} style={{ cursor: 'pointer' }} onClick={(e) => { e.stopPropagation(); handleClick() }}>\n <circle cx={from.x} cy={cy} r={16} fill=\"none\" stroke=\"transparent\" strokeWidth={16} />\n <circle cx={from.x} cy={cy} r={12} fill=\"none\" stroke={color} strokeWidth={isUnbound ? 4.5 : 3} strokeDasharray={isUnbound ? '5 4' : undefined} opacity={1} />\n <polygon points={`${from.x},${cy - 14} ${from.x - 6},${cy - 23} ${from.x + 6},${cy - 23}`} fill={color} opacity={1} />\n </g>\n )\n }\n const offset = 8 + (dirIndex.get(i) ?? 0) * 18\n return (\n <DirectedEdge\n key={`${a.from}-${i}`}\n sx={from.x}\n sy={from.y}\n ex={to.x}\n ey={to.y}\n color={color}\n width={isUnbound ? 4.5 : 3}\n headSize={isUnbound ? 13 : 12}\n nodeR={20}\n offset={offset}\n dashed={isUnbound}\n opacity={1}\n highlight={hoverArrow === i}\n onClick={handleClick}\n />\n )\n })\n\n const hintY = genTop + k * CHIP_ROW_H + 16\n\n const chainArrows =\n selectedGen !== null\n ? actionArrows.some(a => a.generatorId === selectedGen)\n ? actionArrows.filter(a => a.generatorId === selectedGen)\n : actionArrows.filter(a => a.generatorId === null)\n : actionArrows.filter(a => a.generatorId === null)\n const candidates = computeCycleCandidates(chainArrows, n)\n\n return (\n <g onPointerMove={onArrowMove} onPointerUp={onArrowUp}>\n <rect\n x={0}\n y={0}\n width={vw}\n height={vh}\n fill=\"transparent\"\n onClick={() => {\n drawInfoRef.current = null\n setDraw(null)\n }}\n />\n {genChips}\n {candidates.length > 0 && (\n <foreignObject x={0} y={24} width={vw} height={46} style={{ pointerEvents: 'none' }}>\n <div\n style={{\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n gap: 8,\n flexWrap: 'wrap',\n pointerEvents: 'auto',\n }}\n >\n <span style={{ fontSize: 13, color: 'var(--text-secondary)' }}>{t('action.cycleCandidates')}</span>\n {candidates.map(c => (\n <button\n key={c.length}\n onClick={() => {\n if (dragMovedRef.current) return\n replaceGenArrows(selectedGen, c.pairs)\n }}\n style={{\n fontSize: 13,\n padding: '3px 10px',\n cursor: 'pointer',\n borderRadius: 6,\n border: '1px solid var(--node-stroke)',\n background: 'var(--node-fill)',\n color: 'var(--text-primary)',\n }}\n >\n {c.length} {t('action.cycleUnit')} {c.label}\n </button>\n ))}\n </div>\n </foreignObject>\n )}\n <text x={genColX} y={hintY} fill=\"var(--text-secondary)\" fontSize={14}>\n {t('action.editHint')}\n </text>\n <text x={genColX} y={hintY + 22} fill=\"var(--text-secondary)\" fontSize={13}>\n {t('action.genSelectHint')}\n </text>\n {arrowsEls}\n {draw && (\n <DirectedEdge\n sx={pos(draw.from).x}\n sy={pos(draw.from).y}\n ex={draw.snap !== null ? pos(draw.snap).x : draw.x}\n ey={draw.snap !== null ? pos(draw.snap).y : draw.y}\n color={HOVER_COLOR}\n width={3}\n headSize={13}\n nodeR={20}\n dashed\n opacity={0.9}\n />\n )}\n {Array.from({ length: n }, (_, i) => (\n <ClusterNode\n key={i}\n x={pos(i).x}\n y={pos(i).y}\n label=\"\"\n showNumber={i + 1}\n isSelected={draw?.snap === i}\n isFixed={false}\n nodeR={20}\n testId={`action-edit-node-${i + 1}`}\n onPointerDown={(e) => startArrowDraw(e, i)}\n onClick={() => {\n const info = drawInfoRef.current\n if (!info) return\n if (info.justPicked) {\n drawInfoRef.current = { ...info, justPicked: false }\n return\n }\n deployArrow(info.from, i)\n }}\n />\n ))}\n {drag && (\n <g transform={`translate(${drag.x}, ${drag.y})`} opacity={0.92} style={{ pointerEvents: 'none' }}>\n <rect x={-CHIP_W / 2} y={-CHIP_H / 2} width={CHIP_W} height={CHIP_H} rx={6}\n fill={genColor(drag.symbol)} fillOpacity={0.35}\n stroke={genColor(drag.symbol)} strokeWidth={2.5} />\n <text x={0} y={5} textAnchor=\"middle\" fill=\"var(--node-text)\" fontSize={17} fontWeight=\"bold\" style={{ pointerEvents: 'none' }}>\n {drag.symbol}\n </text>\n <text x={0} y={CHIP_H / 2 + 16} textAnchor=\"middle\" fill={HOVER_COLOR} fontSize={13} style={{ pointerEvents: 'none' }}>\n {t('action.dropHint')}\n </text>\n </g>\n )}\n {actionError && (\n <text x={cx} y={cy + ringR + 92} textAnchor=\"middle\" fill=\"#f43f5e\" fontSize={14}>\n {actionError.type === 'homomorphism'\n ? t('action.error.homomorphism', {\n g: actionError.g ?? '',\n gen: actionError.generatorId ?? '',\n x: String(actionError.from + 1),\n })\n : t(`action.error.${actionError.type}`, {\n gen: actionError.generatorId ?? '',\n from: String(actionError.from + 1),\n to: String(actionError.to + 1),\n })}\n </text>\n )}\n </g>\n )\n}\n\nfunction computeFitVB(computation: GroupActionComputation, showLabels = true): { width: number; height: number } {\n const widths = computation.orbits.map(o => 2 * (clusterRadius(o.elements.length) + NODE_R + CLUSTER_PAD))\n const totalW = widths.reduce((a, b) => a + b, 0) + CLUSTER_GAP * Math.max(0, computation.orbits.length - 1)\n let yAcc = 0\n if (showLabels) {\n computation.orbits.forEach(o => {\n const size = o.elements.length\n yAcc += GRP_HDR + Math.ceil(size / CHIP_PER_ROW) * CHIP_ROW_H + 2 * GRP_PAD + GRP_GAP\n })\n }\n const chipsH = showLabels ? yAcc - GRP_GAP : 0\n // showLabels=false(嵌入窗口缺省):顶部 chips 区隐藏,只留生成元图例高度\n const topRegion = (showLabels ? 12 : 42) + chipsH + 30\n const maxH = Math.max(0, ...widths)\n const contentH = topRegion + 60 + maxH + 60\n const contentW = Math.max(totalW + 2 * CLUSTER_GAP, 320)\n return { width: Math.ceil(contentW), height: Math.ceil(contentH) }\n}\n\ninterface DisplayModeProps {\n group: Group\n computation: GroupActionComputation\n kind: GroupActionKind\n selectedElement: number | null\n onSelectedElementChange?: (x: number | null) => void\n hoveredElement: string | null\n onHoverElementChange?: (id: string | null) => void\n /** chips 群元素点击 → 主画布全局选中;窗口不传(chips 缺省隐藏也无需此交互) */\n onSetElementSelect?: (id: string) => void\n /** 节点常驻标签 + 顶部轨道 chips 区;缺省 true(主画布观感)。窗口 false:节点空圈 + chips 区隐藏 */\n showLabels: boolean\n /** 悬停就地气泡(窗口接 handleHover);主画布壳不传 */\n onHover?: (el: GroupElement | null, anchor?: { x: number; y: number } | null) => void\n legendHover: string | null\n onLegendHover: (s: string | null) => void\n viewBoxOverride?: { width: number; height: number }\n canvasTransform: CanvasTransform\n viewBoxSize: { width: number; height: number }\n}\n\nfunction DisplayMode({ group, computation, kind, selectedElement, onSelectedElementChange, hoveredElement, onHoverElementChange, onSetElementSelect, showLabels, onHover, legendHover, onLegendHover, viewBoxOverride, canvasTransform, viewBoxSize }: DisplayModeProps) {\n const { t } = useTranslation()\n const vw = viewBoxOverride?.width ?? viewBoxSize.width\n const vh = viewBoxOverride?.height ?? viewBoxSize.height\n\n const { n, perms, orbits, orbitOf } = computation\n const fixed = useMemo(() => new Set(computeFixedPoints(perms, n)), [perms, n])\n const isConjugation = kind === 'conjugation'\n const showsElements = isConjugation || kind === 'regular'\n const hoverActive = !!hoveredElement\n\n // 场景 svg viewBox = computeFitVB 内容包围盒(vw/vh),但 .view-svg 拉伸填满\n // 视口(viewBoxSize = 容器 CSS 像素)。宽高比不一致时浏览器按 preserveAspectRatio\n // 居中缩放(letterbox)→ 视口坐标 = viewBox 坐标经仿射 (s, ox, oy)。锚点必须套同一\n // 仿射,否则就地气泡偏离节点(其它视图 svg viewBox=容器尺寸 1:1,无需此步)。\n const svgFit = Math.min(viewBoxSize.width / Math.max(vw, 1), viewBoxSize.height / Math.max(vh, 1))\n const letterboxX = (viewBoxSize.width - vw * svgFit) / 2\n const letterboxY = (viewBoxSize.height - vh * svgFit) / 2\n const anchorOf = (p: { x: number; y: number }) => ({\n x: (p.x * canvasTransform.scale + canvasTransform.x) * svgFit + letterboxX,\n y: (p.y * canvasTransform.scale + canvasTransform.y) * svgFit + letterboxY,\n })\n\n const widths = orbits.map(o => 2 * (clusterRadius(o.elements.length) + NODE_R + CLUSTER_PAD))\n const totalW = widths.reduce((a, b) => a + b, 0) + CLUSTER_GAP * (orbits.length - 1)\n const heights = orbits.map(o => 2 * (clusterRadius(o.elements.length) + NODE_R + CLUSTER_PAD))\n const maxH = Math.max(0, ...heights)\n\n const legendStart = vw - 40 - group.generators.length * 110\n const legend = group.generators.map((gen, i) => (\n <g\n key={`legend-${i}`}\n transform={`translate(${legendStart + i * 110}, 0)`}\n onMouseEnter={() => onLegendHover(gen.symbol)}\n onMouseLeave={() => onLegendHover(null)}\n style={{ cursor: 'pointer' }}\n >\n <circle cx={10} cy={10} r={6} fill={gen.color || 'var(--node-stroke)'} />\n <text x={22} y={15} fill=\"var(--text-secondary)\" fontSize={14}>{gen.symbol}</text>\n </g>\n ))\n\n const grpW: number[] = []\n const grpH: number[] = []\n orbits.forEach(o => {\n const size = o.elements.length\n const colsInRow = Math.min(CHIP_PER_ROW, size)\n grpW.push(colsInRow * CHIP_W + (colsInRow - 1) * CHIP_GAP + 2 * GRP_PAD)\n grpH.push(GRP_HDR + Math.ceil(size / CHIP_PER_ROW) * CHIP_ROW_H + 2 * GRP_PAD)\n })\n\n let yAcc = 0\n const lineTop = orbits.map((_, gi) => {\n const top = yAcc\n yAcc += grpH[gi] + GRP_GAP\n return top\n })\n const chipsH = showLabels ? yAcc - GRP_GAP : 0\n\n const topRegion = (showLabels ? 12 : 42) + chipsH + 30\n const contentH = topRegion + 60 + maxH\n const vOffset = Math.max(30, (vh - contentH) / 2)\n\n const centers: { x: number; y: number; r: number }[] = []\n let cursorX = Math.max(0, (vw - totalW) / 2)\n for (let i = 0; i < orbits.length; i++) {\n const r = clusterRadius(orbits[i].elements.length)\n centers.push({ x: cursorX + widths[i] / 2, y: vOffset + topRegion + 60 + maxH / 2, r })\n cursorX += widths[i] + CLUSTER_GAP\n }\n\n const nodePos = (x: number) => {\n const oi = orbitOf[x]\n const c = centers[oi]\n const idx = orbits[oi].elements.indexOf(x)\n const angle = (idx / orbits[oi].elements.length) * 2 * Math.PI - Math.PI / 2\n return { x: c.x + Math.cos(angle) * c.r, y: c.y + Math.sin(angle) * c.r }\n }\n\n const hoverPerm = useMemo(() => {\n if (!hoveredElement) return null\n return perms.get(hoveredElement) ?? null\n }, [hoveredElement, perms])\n\n if (isConjugation && computation.n !== group.order) return null\n\n interface PairRec { x: number; y: number; gi: number }\n const pairMap = new Map<string, PairRec[]>()\n const edgeList: { key: string; rec: PairRec }[] = []\n for (let gi = 0; gi < group.generators.length; gi++) {\n const gen = group.generators[gi]\n const genEl = gen.apply(group.identity)\n const p = perms.get(genEl.id)\n if (!p) continue\n for (let x = 0; x < n; x++) {\n const y = p[x]\n if (y === x) continue\n const a = Math.min(x, y)\n const b = Math.max(x, y)\n const key = `${a}|${b}`\n const rec: PairRec = { x, y, gi }\n const arr = pairMap.get(key)\n if (arr) arr.push(rec)\n else pairMap.set(key, [rec])\n edgeList.push({ key, rec })\n }\n }\n\n const genEdges: React.ReactNode[] = []\n for (const { key, rec } of edgeList) {\n const { x, y, gi } = rec\n const gen = group.generators[gi]\n const arr = pairMap.get(key)!\n const slot = arr.indexOf(rec)\n const total = arr.length\n const from = nodePos(x)\n const to = nodePos(y)\n const edgeLen = Math.sqrt((to.x - from.x) ** 2 + (to.y - from.y) ** 2) || 1\n const step = Math.max(10, Math.min(16, edgeLen * 0.06))\n const offset = (slot - (total - 1) / 2) * step\n const c = centers[orbitOf[x]]\n const ref = nodePos(arr[0].x)\n const angA = Math.atan2(ref.y - c.y, ref.x - c.x)\n const tFrom = { x: -Math.sin(angA), y: Math.cos(angA) }\n const isLegendTarget = legendHover !== null && legendHover === gen.symbol\n const dimmed = hoverActive || (legendHover !== null && !isLegendTarget)\n genEdges.push(\n <DirectedEdge\n key={`genedge-${gi}-${x}`}\n sx={from.x}\n sy={from.y}\n ex={to.x}\n ey={to.y}\n color={dimmed ? 'var(--node-stroke)' : (gen.color || 'var(--node-stroke)')}\n width={dimmed ? 1.2 : (isLegendTarget ? 3.4 : 3)}\n headSize={18}\n nodeR={NODE_R}\n offset={offset}\n tFrom={tFrom}\n dashed={dimmed}\n opacity={dimmed ? 0.18 : 0.95}\n />\n )\n }\n\n const hoverEdges: React.ReactNode[] = []\n if (hoverPerm) {\n for (let x = 0; x < n; x++) {\n const y = hoverPerm[x]\n if (y === x) {\n const p = nodePos(x)\n hoverEdges.push(\n <circle key={`loop-${x}`} cx={p.x} cy={p.y - NODE_R - 6} r={5} fill=\"none\" stroke={HOVER_COLOR} strokeWidth={1.5} />\n )\n continue\n }\n const from = nodePos(x)\n const to = nodePos(y)\n hoverEdges.push(\n <DirectedEdge\n key={`h-${x}`}\n sx={from.x}\n sy={from.y}\n ex={to.x}\n ey={to.y}\n color={HOVER_COLOR}\n width={3}\n headSize={18}\n nodeR={NODE_R}\n opacity={0.95}\n dir={x < y ? 1 : -1}\n />\n )\n }\n }\n\n const selectedOrbit = selectedElement !== null ? orbitOf[selectedElement] : -1\n\n const chips: React.ReactNode[] = []\n orbits.forEach((o, g) => {\n const xStart = (vw - grpW[g]) / 2\n const gy = vOffset + 12 + lineTop[g]\n const groupChips = o.elements.map((x, ci) => {\n const row = Math.floor(ci / CHIP_PER_ROW)\n const col = ci % CHIP_PER_ROW\n const el = showsElements ? group.elements[x] : null\n const label = el\n ? renderTex(texify(el.label))\n : computation.setLabels?.[x]\n ? renderTex(texify(computation.setLabels[x]))\n : String(x + 1)\n return (\n <g key={el ? el.id : `s-${x}`} transform={`translate(${GRP_PAD + col * (CHIP_W + CHIP_GAP)}, ${GRP_HDR + GRP_PAD + row * CHIP_ROW_H})`}>\n <ElementChip\n label={label}\n isSelected={el ? hoveredElement === el.id : selectedElement === x}\n onClick={el ? () => onSetElementSelect?.(el.id) : () => {\n const next = selectedElement === x ? null : x\n onHoverElementChange?.(null)\n onSelectedElementChange?.(next)\n }}\n onHover={el ? (on) => onHoverElementChange?.(on ? el.id : null) : undefined}\n />\n </g>\n )\n })\n chips.push(\n <g key={`grp-${g}`} transform={`translate(${xStart}, ${gy})`}>\n <rect\n width={grpW[g]}\n height={grpH[g]}\n rx={8}\n fill=\"var(--node-fill)\"\n fillOpacity={0.15}\n stroke=\"var(--node-stroke)\"\n strokeOpacity={0.25}\n strokeDasharray=\"3 3\"\n />\n <text x={GRP_PAD + 2} y={GRP_HDR - 4} fill=\"var(--text-secondary)\" fontSize={13}>\n {t('action.orbitGroup', { size: String(o.elements.length) })}\n </text>\n {groupChips}\n </g>\n )\n })\n\n return (\n <>\n {legend}\n {showLabels && chips}\n {centers.map((c, oi) => (\n <circle\n key={`glow-${oi}`}\n cx={c.x}\n cy={c.y}\n r={c.r + NODE_R + 14}\n fill=\"none\"\n stroke={selectedOrbit === oi ? HOVER_COLOR : 'var(--node-stroke)'}\n strokeWidth={selectedOrbit === oi ? 3 : 1}\n strokeOpacity={selectedOrbit === oi ? 0.9 : 0.25}\n strokeDasharray={selectedOrbit === oi ? undefined : '4 6'}\n />\n ))}\n {genEdges}\n {hoverEdges}\n {Array.from({ length: n }, (_, x) => {\n const p = nodePos(x)\n const el = showsElements ? group.elements[x] : null\n // 窗口模式(onHover 传入):节点悬停触发就地气泡 + 金色箭头联动;\n // 主画布壳不传 onHover → 不挂 hover,保持原行为零变化\n const canHover = !!el && !!onHover\n return (\n <ClusterNode\n key={x}\n x={p.x}\n y={p.y}\n label={showLabels && showsElements ? renderTex(texify(group.elements[x].label)) : showLabels && computation.setLabels?.[x] ? renderTex(texify(computation.setLabels[x])) : ''}\n showNumber={showsElements ? undefined : (computation.setLabels ? undefined : x + 1)}\n isSelected={selectedElement === x}\n isFixed={fixed.has(x)}\n testId={`action-node-${x}`}\n onClick={() => onSelectedElementChange?.(selectedElement === x ? null : x)}\n onHoverIn={canHover ? () => {\n onHoverElementChange?.(el!.id)\n onHover?.(el, anchorOf(p))\n } : undefined}\n onHoverOut={canHover ? () => {\n onHoverElementChange?.(null)\n onHover?.(null, null)\n } : undefined}\n />\n )\n })}\n </>\n )\n}\n\n// ─── ActionScene:banner + svg 场景 + Stab box 全场景 ──────────────────────\n\nexport interface ActionSceneProps {\n group: Group\n /** 作用来源;窗口范围 conjugation/regular/custom(sylow/coset 仅主画布壳会传) */\n kind: GroupActionKind\n computation: GroupActionComputation | null\n /** custom 编辑模式(渲染 CustomActionEditor,不吃 canvasTransform) */\n editing?: boolean\n /** 编辑模式 |X|(1..20) */\n setSize?: number | null\n /** 编辑模式箭头列表 */\n arrows?: GroupActionArrow[]\n /** 编辑模式错误(画布内红字提示) */\n error?: CustomArrowError | null\n onAddArrow?: (from: number, to: number, generatorId?: string | null) => void\n onBindArrow?: (from: number, to: number, generatorId: string) => void\n onRemoveArrow?: (from: number, generatorId?: string | null, to?: number) => void\n onReplaceGenArrows?: (generatorId: string | null, pairs: [number, number][]) => void\n /** 选中集合元素索引(OST 交互 + 底部 Stab box) */\n selectedElement?: number | null\n onSelectedElementChange?: (x: number | null) => void\n /** 悬停群元素 id(金色箭头联动;主画布壳接 context) */\n hoveredElement?: string | null\n onHoverElementChange?: (id: string | null) => void\n /** chips 群元素点击 → 主画布全局选中;窗口不传 */\n onSetElementSelect?: (id: string) => void\n /** 节点常驻标签 + 顶部轨道 chips 区;缺省 true(主画布观感)。窗口传 false:\n * 节点空圈 + chips 区隐藏 + conjugation/regular 节点悬停就地气泡 */\n showLabels?: boolean\n /** 悬停就地气泡回调(窗口接 handleHover) */\n onHover?: (el: GroupElement | null, anchor?: { x: number; y: number } | null) => void\n /** 内容平移缩放(主画布壳接 canvasTransform,窗口接窗口 ct);编辑模式不吃 */\n canvasTransform?: CanvasTransform\n /** 视口尺寸;fitVB 自适应时作为兜底 */\n viewBoxSize?: { width: number; height: number }\n /** sylow 作用的素数(banner 标题用);窗口不传 */\n prime?: number | null\n /** 视图主题作用域(`'dark' | 'light'`)。缺省不注入、跟随外层主题;显式传值时在本子树内\n * 应用 `theme.css` 对应变量块(需宿主已 `import '@groupviz/react/theme.css'`) */\n theme?: SceneTheme\n}\n\nexport function ActionScene(props: ActionSceneProps) {\n return (\n <SceneThemeRoot theme={props.theme}>\n <ActionSceneBody {...props} />\n </SceneThemeRoot>\n )\n}\n\nconst DEFAULT_TRANSFORM: CanvasTransform = { x: 0, y: 0, scale: 1 }\nconst DEFAULT_VB = { width: 2000, height: 2000 }\n\nfunction ActionSceneBody({\n group,\n kind,\n computation,\n editing = false,\n setSize = null,\n arrows = [],\n error = null,\n onAddArrow,\n onBindArrow,\n onRemoveArrow,\n onReplaceGenArrows,\n selectedElement = null,\n onSelectedElementChange,\n hoveredElement = null,\n onHoverElementChange,\n onSetElementSelect,\n showLabels = true,\n onHover,\n canvasTransform = DEFAULT_TRANSFORM,\n viewBoxSize = DEFAULT_VB,\n prime = null,\n}: ActionSceneProps) {\n const { t } = useTranslation()\n const [legendHover, setLegendHover] = useState<string | null>(null)\n\n const isConjugation = kind === 'conjugation'\n const showsElements = isConjugation || kind === 'regular'\n const hoverEl = hoveredElement ? group.elements.find(e => e.id === hoveredElement) ?? null : null\n const showBanner = !!computation && !editing\n // 窗口模式(onHover 传入)banner 收敛为一行核心公式,隐藏第二行动态说明:\n // kind 名已在窗口标题栏,轨道/弧线含义由视图自明(custom 无公式 → 整条 banner 隐藏)。\n // 主画布壳不传 onHover → 保留原两行完整说明,零行为变化。\n const isWindow = !!onHover\n const titleLine = isWindow\n ? isConjugation ? 'g·x = g·x·g⁻¹'\n : kind === 'regular' ? 'g·x = g·x'\n : ''\n : isConjugation\n ? t('action.viewTitle.conjugation')\n : kind === 'sylow'\n ? t('action.viewTitle.sylow', { p: prime ?? '' })\n : kind === 'regular'\n ? t('action.viewTitle.regular')\n : kind === 'coset'\n ? t('action.viewTitle.coset')\n : t('action.viewTitle.custom')\n const edgeLine = hoverEl\n ? t('action.hoverElEdges', { el: hoverEl.label })\n : legendHover\n ? t('action.hoverGenEdges', { gen: legendHover })\n : selectedElement !== null\n ? t('action.selHint')\n : t('action.edgeBlurb')\n const edgeColor = hoverEl || legendHover ? HOVER_COLOR : 'var(--text-secondary)'\n\n const fitVB = computation && !editing ? computeFitVB(computation, showLabels) : null\n const editRingR = Math.max(220, (setSize ?? 1) * 22)\n const editVH = Math.max(900, 2 * editRingR + 520)\n const vb = editing ? { width: 1200, height: editVH } : fitVB ?? viewBoxSize\n\n const stabElements = computation && selectedElement !== null\n ? (computation.stabilizers.get(selectedElement) ?? [])\n .map(id => group.elements.find(e => e.id === id))\n .filter((el): el is NonNullable<typeof el> => !!el)\n : []\n const selLabel = computation && selectedElement !== null\n ? (showsElements\n ? renderTex(texify(group.elements[selectedElement]?.label ?? ''))\n : computation.setLabels?.[selectedElement]\n ? renderTex(texify(computation.setLabels[selectedElement]))\n : String(selectedElement + 1))\n : ''\n const showStabBox = !!computation && !editing && selectedElement !== null && stabElements.length > 0\n\n return (\n <>\n {showBanner && titleLine !== '' && (\n <div\n style={{\n position: 'absolute',\n top: 8,\n left: '50%',\n transform: 'translateX(-50%)',\n zIndex: 5,\n maxWidth: '92%',\n background: 'var(--panel-bg)',\n opacity: 0.94,\n padding: isWindow ? '4px 12px' : '6px 14px',\n borderRadius: 8,\n border: '1px solid var(--border-color, rgba(128,128,128,0.35))',\n textAlign: 'center',\n pointerEvents: 'none',\n }}\n >\n <div style={{ fontSize: isWindow ? 12 : 13, fontWeight: 600, color: 'var(--text-primary)' }}>{titleLine}</div>\n {!isWindow && <div style={{ fontSize: 12, color: edgeColor, marginTop: 2 }}>{edgeLine}</div>}\n </div>\n )}\n <svg viewBox={`0 0 ${vb.width} ${vb.height}`} className=\"view-svg\" style={{ userSelect: 'none' }}>\n <defs>\n <filter id=\"node-shadow\" x=\"-30%\" y=\"-30%\" width=\"160%\" height=\"160%\">\n <feDropShadow dx=\"0\" dy=\"2\" stdDeviation=\"3\" floodColor=\"#000000\" floodOpacity=\"0.25\" />\n </filter>\n </defs>\n <g transform={editing ? undefined : `translate(${canvasTransform.x}, ${canvasTransform.y}) scale(${canvasTransform.scale})`}>\n {editing ? (\n <CustomActionEditor\n group={group}\n vw={1200}\n vh={editVH}\n setSize={setSize ?? 1}\n arrows={arrows}\n error={error}\n onAddArrow={onAddArrow ?? (() => {})}\n onBindArrow={onBindArrow ?? (() => {})}\n onRemoveArrow={onRemoveArrow ?? (() => {})}\n onReplaceGenArrows={onReplaceGenArrows ?? (() => {})}\n />\n ) : computation ? (\n <DisplayMode\n group={group}\n computation={computation}\n kind={kind}\n selectedElement={selectedElement}\n onSelectedElementChange={onSelectedElementChange}\n hoveredElement={hoveredElement}\n onHoverElementChange={onHoverElementChange}\n onSetElementSelect={onSetElementSelect}\n showLabels={showLabels}\n onHover={onHover}\n legendHover={legendHover}\n onLegendHover={setLegendHover}\n viewBoxOverride={fitVB ?? undefined}\n canvasTransform={canvasTransform}\n viewBoxSize={viewBoxSize}\n />\n ) : (\n <text x={viewBoxSize.width / 2} y={viewBoxSize.height / 2} textAnchor=\"middle\" fill=\"var(--text-secondary)\" fontSize={22}>\n {t('action.noAction')}\n </text>\n )}\n </g>\n </svg>\n {showStabBox && (\n <div\n style={{\n position: 'absolute',\n bottom: 8,\n left: '50%',\n transform: 'translateX(-50%)',\n zIndex: 5,\n maxWidth: '92%',\n background: 'var(--panel-bg)',\n opacity: 0.96,\n padding: '8px 14px',\n borderRadius: 8,\n border: '1px solid var(--border-color, rgba(128,128,128,0.35))',\n boxShadow: '0 4px 14px rgba(0,0,0,0.25)',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>\n <span style={{ fontSize: 13, fontWeight: 700, color: 'var(--text-primary)' }}>\n <span dangerouslySetInnerHTML={{ __html: t('action.stabilizerFor', { el: selLabel }) }} /> <span style={{ color: 'var(--text-secondary)', fontWeight: 400 }}>|G_x| = {stabElements.length}</span>\n </span>\n <button\n onClick={() => onSelectedElementChange?.(null)}\n style={{\n marginLeft: 'auto', border: 'none', background: 'none', cursor: 'pointer',\n color: 'var(--text-secondary)', fontSize: 14, lineHeight: 1, padding: '2px 4px',\n }}\n title={t('action.closeStab')}\n >×</button>\n </div>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginTop: 6, maxHeight: 160, overflowY: 'auto' }}>\n {stabElements.map(el => (\n <span\n key={el.id}\n style={{\n padding: '2px 8px', borderRadius: 10, fontSize: 12,\n background: 'var(--bg-interactive)', border: '1px solid var(--border-primary)',\n color: 'var(--text-primary)', whiteSpace: 'nowrap',\n }}\n dangerouslySetInnerHTML={{ __html: renderTex(texify(el.label)) }}\n />\n ))}\n </div>\n </div>\n )}\n </>\n )\n}\n","import { useMemo, useState, useCallback, useRef, type ReactNode } from 'react'\nimport { SceneThemeRoot, type SceneTheme } from './SceneThemeRoot'\nimport { useTranslation } from '../../i18n/useTranslation'\nimport { renderTex, texify } from '../../utils/texify'\nimport { verifyHomomorphism, getHomomorphismProperties } from '../../core/algebra/homomorphisms'\nimport { computeCayleyActionEdges } from '../../core/algebra/cayleyEdges'\nimport { cayleyCircleLayout } from '../../core/algebra/forceLayout'\nimport { COLOR_PALETTE } from '../../core/types'\nimport type { Group, GroupElement, HomomorphismResult } from '../../core/types'\n\nconst HOMO_COLORS = [\n '#4ecdc4', '#a78bfa', '#ffd93d', '#f97316',\n '#38bdf8', '#84cc16', '#f43f5e', '#eab308',\n '#6366f1', '#ec4899', '#14b8a6', '#0ea5e9',\n '#22c55e', '#a855f7', '#06b6d4',\n]\n\nconst KERNEL_RED = '#ff6b6b'\nconst IMAGE_CYAN = '#4ecdc4'\n\nfunction bezierPath(x1: number, y1: number, x2: number, y2: number): string {\n const dx = Math.abs(x2 - x1) * 0.3\n return `M ${x1} ${y1} C ${x1 + dx} ${y1}, ${x2 - dx} ${y2}, ${x2} ${y2}`\n}\n\nfunction findGeneratorElements(group: { elements: GroupElement[]; generators: { name: string; symbol: string; apply: (el: GroupElement) => GroupElement }[]; identity: GroupElement }): GroupElement[] {\n const result: GroupElement[] = []\n for (const gen of group.generators) {\n let el = group.elements.find(e => e.label === gen.symbol || e.label === gen.name)\n if (!el) {\n const image = gen.apply(group.identity)\n el = group.elements.find(e => e.id === image.id)\n }\n if (el) result.push(el)\n }\n return result\n}\n\n// ─── Homomorphism props-化内核 ──────────────────────────────────────────\n// 受控 ViewWindow (FGVE) 与主画布(经 context 壳 HomomorphismView)共用。\n// source/target/mapping 之外全部可选:主画布壳由全局 Provider 组装\n// (含 theoremMode 定理动画注入);窗口引擎自包含时只传双群 + mapping。\n\nexport interface HomomorphismSceneProps {\n source: Group | null\n target: Group | null\n mapping: Map<string, string>\n /** 预计算结果(null=源/目标缺失或 mapping 为空)。缺省(undefined)由 Scene 内部 verifyHomomorphism 推导 */\n result?: HomomorphismResult | null\n /** 映射显示名(TeX 或纯文本);缺省 `${source.symbol} → ${target.symbol}` */\n name?: string\n /** 定理模式(第一同构定理动画);缺省 false。动画内容由 theoremAnimation 注入 */\n theoremMode?: boolean\n onTheoremModeChange?: (v: boolean) => void\n /** 定理动画内容(主画布壳注入 <FirstIsomorphismAnimation>);窗口不传 */\n theoremAnimation?: ReactNode\n /** 节点常驻标签;缺省 true(主画布行为);嵌入窗口默认关,读元素靠悬停就地气泡 */\n showLabels?: boolean\n /** 悬停节点(源/目标元素 + 视口内屏幕锚点);主画布壳不传(内部高亮即可),窗口接就地气泡 */\n onHover?: (el: GroupElement | null, anchor?: { x: number; y: number } | null) => void\n /** 视图主题作用域(`'dark' | 'light'`)。缺省不注入、跟随外层主题;显式传值时在本子树内\n * 应用 `theme.css` 对应变量块(需宿主已 `import '@groupviz/react/theme.css'`) */\n theme?: SceneTheme\n}\n\nexport function HomomorphismScene(props: HomomorphismSceneProps) {\n return (\n <SceneThemeRoot theme={props.theme}>\n <HomomorphismSceneBody {...props} />\n </SceneThemeRoot>\n )\n}\n\nfunction HomomorphismSceneBody({\n source,\n target,\n mapping,\n result,\n name,\n theoremMode = false,\n onTheoremModeChange,\n theoremAnimation,\n showLabels = true,\n onHover,\n}: HomomorphismSceneProps) {\n const { t } = useTranslation()\n const svgRef = useRef<SVGSVGElement>(null)\n\n const [hoverSource, setHoverSource] = useState<string | null>(null)\n const [hoverTarget, setHoverTarget] = useState<string | null>(null)\n const [pinnedSource, setPinnedSource] = useState<string | null>(null)\n\n const resolvedResult = useMemo(() => {\n if (result !== undefined) return result\n if (!source || !target || mapping.size === 0) return null\n return verifyHomomorphism(source, target, mapping)\n }, [source, target, mapping, result])\n\n const kernelIds = resolvedResult?.kernel || []\n const imageIds = resolvedResult?.image || []\n\n const properties = resolvedResult?.isHomomorphism\n ? getHomomorphismProperties(source!, target!, resolvedResult)\n : null\n\n const kernelSet = new Set(kernelIds)\n const imageSet = new Set(imageIds)\n\n const highlightedSource = pinnedSource || hoverSource\n const highlightedTargetId = highlightedSource ? mapping.get(highlightedSource) : hoverTarget\n\n const highlightPreimageIds = useMemo(() => {\n if (!highlightedTargetId || highlightedSource) return new Set<string>()\n const preimages = new Set<string>()\n mapping.forEach((tgt, src) => {\n if (tgt === highlightedTargetId) preimages.add(src)\n })\n return preimages\n }, [highlightedTargetId, highlightedSource, mapping])\n\n const handleSourceClick = useCallback((elId: string) => {\n setPinnedSource(prev => prev === elId ? null : elId)\n }, [])\n\n const gCayleyEdges = useMemo(() => {\n if (!source) return []\n const genEls = findGeneratorElements(source)\n if (genEls.length === 0) return []\n const actions = genEls.map((el, i) => ({\n elementId: el.id,\n enabled: true,\n color: COLOR_PALETTE[i % COLOR_PALETTE.length],\n }))\n return computeCayleyActionEdges(source, actions, 'right')\n }, [source])\n\n const hCayleyEdges = useMemo(() => {\n if (!target) return []\n const genEls = findGeneratorElements(target)\n if (genEls.length === 0) return []\n const actions = genEls.map((el, i) => ({\n elementId: el.id,\n enabled: true,\n color: COLOR_PALETTE[i % COLOR_PALETTE.length],\n }))\n return computeCayleyActionEdges(target, actions, 'right')\n }, [target])\n\n if (!source || !target) {\n return (\n <svg viewBox=\"0 0 800 500\" style={{ width: '100%', height: '100%' }}>\n <text x=\"400\" y=\"250\" textAnchor=\"middle\" fill=\"var(--text-muted)\" fontSize=\"16\">\n {t('homo.selectSourceFirst')}\n </text>\n </svg>\n )\n }\n\n if (theoremMode) {\n return (\n <div style={{ display: 'flex', flexDirection: 'column', width: '100%', height: '100%' }}>\n <div style={{ display: 'flex', justifyContent: 'flex-start', padding: '4px 8px' }}>\n <button className=\"panel-btn\"\n onClick={() => onTheoremModeChange?.(false)}\n style={{ fontSize: '10px', padding: '3px 8px' }}>\n ← {t('homo.title')}\n </button>\n </div>\n <div style={{ flex: 1 }}>\n {theoremAnimation}\n </div>\n </div>\n )\n }\n\n const vw = 800\n const vh = 500\n const leftCx = 170\n const rightCx = 630\n const midY = vh * 0.48\n\n const srcR = Math.min(140, Math.max(65, source.order * 4.5))\n const tgtR = Math.min(140, Math.max(65, target.order * 4.5))\n const sourcePositions = cayleyCircleLayout(source, leftCx, midY, srcR)\n const targetPositions = cayleyCircleLayout(target, rightCx, midY, tgtR)\n\n function renderEdge(\n posMap: Map<string, { x: number; y: number }>,\n fromId: string, toId: string, color: string, key: string,\n width = 1.5, opacity = 0.5, selfLoop = false, _isBidirectional = false,\n pairOffset = 0,\n ) {\n const from = posMap.get(fromId)\n const to = posMap.get(toId)\n if (!from || !to) return null\n if (selfLoop) return null\n const dx = to.x - from.x; const dy = to.y - from.y\n const dist = Math.sqrt(dx * dx + dy * dy)\n if (dist < 0.5) return null\n if (pairOffset === 0) {\n return (\n <line key={key} x1={from.x} y1={from.y} x2={to.x} y2={to.y}\n stroke={color} strokeWidth={width} opacity={opacity} />\n )\n }\n const len = dist || 1\n const nx = -dy / len; const ny = dx / len\n const mx = (from.x + to.x) / 2 + nx * pairOffset\n const my = (from.y + to.y) / 2 + ny * pairOffset\n return (\n <path key={key} d={`M ${from.x} ${from.y} Q ${mx} ${my} ${to.x} ${to.y}`}\n stroke={color} strokeWidth={width} fill=\"none\" opacity={opacity} />\n )\n }\n\n function buildPairOffsets(edges: { fromId: string; toId: string }[]) {\n const pairMap = new Map<string, number[]>()\n edges.forEach((e, i) => {\n const pair = [e.fromId, e.toId].sort()\n const key = `${pair[0]}|${pair[1]}`\n const arr = pairMap.get(key)\n if (arr) arr.push(i)\n else pairMap.set(key, [i])\n })\n const offsets = new Array<number>(edges.length).fill(0)\n pairMap.forEach((indices) => {\n if (indices.length < 2) return\n const total = indices.length\n indices.forEach((idx, slot) => {\n offsets[idx] = (slot - (total - 1) / 2) * 14\n })\n })\n return offsets\n }\n\n const mappingLines: {\n srcId: string\n tgtId: string\n color: string\n pathD: string\n isKernel: boolean\n isHighlighted: boolean\n }[] = []\n\n mapping.forEach((targetId, sourceId) => {\n const from = sourcePositions.get(sourceId)\n const to = targetPositions.get(targetId)\n if (!from || !to) return\n\n const isKernel = kernelSet.has(sourceId)\n const tgtIdx = target.elements.findIndex(e => e.id === targetId)\n const baseColor = isKernel ? KERNEL_RED : HOMO_COLORS[tgtIdx >= 0 ? tgtIdx % HOMO_COLORS.length : 0]\n\n const isHL = highlightedSource === sourceId || highlightedTargetId === targetId\n\n mappingLines.push({\n srcId: sourceId,\n tgtId: targetId,\n color: baseColor,\n pathD: bezierPath(from.x, from.y, to.x, to.y),\n isKernel,\n isHighlighted: !!isHL,\n })\n })\n\n return (\n <svg ref={svgRef} viewBox={`0 0 ${vw} ${vh}`} style={{ width: '100%', height: '100%' }}>\n {/* Background separator line */}\n <line x1={vw / 2} y1={40} x2={vw / 2} y2={vh - 10}\n stroke=\"var(--border-color)\" strokeWidth={0.5} strokeDasharray=\"4,6\" opacity={0.5} />\n\n {/* Title */}\n <foreignObject x={vw / 2 - 140} y={4} width={280} height={28}>\n <div style={{ fontSize: '16px', fontWeight: 'bold', textAlign: 'center', color: 'var(--text-primary)', lineHeight: '28px' }}\n dangerouslySetInnerHTML={{ __html: renderTex(texify(name || `${source.symbol} → ${target.symbol}`)) }} />\n </foreignObject>\n\n {/* Domain Label */}\n <foreignObject x={leftCx - 70} y={34} width={140} height={22}>\n <div style={{ fontSize: '12px', fontWeight: 'bold', textAlign: 'center', color: 'var(--text-primary)', lineHeight: '22px' }}\n dangerouslySetInnerHTML={{ __html: `${renderTex(texify(source.symbol))} <span style=\"color:var(--text-muted);font-weight:400\">(|G|=${source.order})</span>` }} />\n </foreignObject>\n {/* Codomain Label */}\n <foreignObject x={rightCx - 70} y={34} width={140} height={22}>\n <div style={{ fontSize: '12px', fontWeight: 'bold', textAlign: 'center', color: 'var(--text-primary)', lineHeight: '22px' }}\n dangerouslySetInnerHTML={{ __html: `${renderTex(texify(target.symbol))} <span style=\"color:var(--text-muted);font-weight:400\">(|H|=${target.order})</span>` }} />\n </foreignObject>\n\n {/* ═══ G Cayley edges ═══ */}\n {(() => {\n const gOffsets = buildPairOffsets(gCayleyEdges)\n return gCayleyEdges.map((e, i) =>\n renderEdge(\n sourcePositions, e.fromId, e.toId, e.color, `gce-${i}`,\n 1.8, 0.7, e.isSelfLoop, e.isBidirectional, gOffsets[i],\n )\n )\n })()}\n\n {/* ═══ H Cayley edges ═══ */}\n {(() => {\n const hOffsets = buildPairOffsets(hCayleyEdges)\n return hCayleyEdges.map((e, i) =>\n renderEdge(\n targetPositions, e.fromId, e.toId, e.color, `hce-${i}`,\n 1.4, 0.65, e.isSelfLoop, e.isBidirectional, hOffsets[i],\n )\n )\n })()}\n\n {/* Mapping Lines — layered: non-highlighted first, highlighted on top */}\n {mappingLines.filter(l => !l.isHighlighted).map((line, i) => (\n <path\n key={`nl-${i}`}\n d={line.pathD}\n stroke={line.color}\n strokeWidth={line.isKernel ? 2.0 : 1.0}\n strokeOpacity={line.isKernel ? 0.45 : 0.28}\n fill=\"none\"\n />\n ))}\n {mappingLines.filter(l => l.isHighlighted).map((line, i) => (\n <path\n key={`hl-${i}`}\n d={line.pathD}\n stroke={line.color}\n strokeWidth={2.5}\n strokeOpacity={0.85}\n fill=\"none\"\n style={{ filter: 'drop-shadow(0 0 4px currentColor)' }}\n />\n ))}\n\n {/* Source Nodes */}\n {source.elements.map((el) => {\n const pos = sourcePositions.get(el.id)\n if (!pos) return null\n const inKernel = kernelSet.has(el.id)\n const isMapped = mapping.has(el.id)\n const isHL = highlightedSource === el.id || highlightPreimageIds.has(el.id)\n const isPinned = pinnedSource === el.id\n const dimmed = highlightedSource && !isHL\n\n let fill = 'var(--node-fill)'\n if (inKernel) fill = KERNEL_RED\n else if (isMapped) {\n const mTgt = mapping.get(el.id)!\n const tgtIdx = target.elements.findIndex(e => e.id === mTgt)\n if (tgtIdx >= 0) fill = HOMO_COLORS[tgtIdx % HOMO_COLORS.length]\n }\n\n return (\n <g key={`s-${el.id}`} data-homo-source-node\n onMouseEnter={(e) => {\n setHoverSource(el.id)\n const rect = svgRef.current?.getBoundingClientRect()\n if (rect && onHover) onHover(el, { x: e.clientX - rect.left, y: e.clientY - rect.top })\n }}\n onMouseLeave={() => { setHoverSource(null); onHover?.(null, null) }}\n onClick={() => handleSourceClick(el.id)}\n style={{ cursor: 'pointer' }}\n >\n {isHL && (\n <circle cx={pos.x} cy={pos.y} r={18}\n fill=\"none\" stroke={inKernel ? KERNEL_RED : 'var(--accent-teal)'}\n strokeWidth={2} opacity={0.6}\n style={{ filter: 'drop-shadow(0 0 6px currentColor)' }} />\n )}\n <circle\n cx={pos.x} cy={pos.y} r={isMapped ? 13 : 8}\n fill={fill}\n stroke={inKernel ? KERNEL_RED : isMapped ? 'var(--border-color)' : 'var(--border-color)'}\n strokeWidth={inKernel ? 2 : 1}\n opacity={dimmed ? 0.3 : 1}\n />\n {isPinned && (\n <circle cx={pos.x} cy={pos.y} r={15}\n fill=\"none\" stroke=\"var(--accent-teal)\" strokeWidth={2}\n opacity={0.8} />\n )}\n {showLabels && (\n <foreignObject\n x={pos.x - 24} y={pos.y + 6}\n width={48} height={18}\n style={{ overflow: 'visible' }}\n >\n <div style={{\n fontSize: '8px',\n textAlign: 'center',\n color: inKernel ? KERNEL_RED : dimmed ? 'var(--text-muted)' : 'var(--text-primary)',\n fontWeight: inKernel || isHL ? 700 : 400,\n pointerEvents: 'none',\n }} dangerouslySetInnerHTML={{ __html: renderTex(el.label) }} />\n </foreignObject>\n )}\n </g>\n )\n })}\n\n {/* Target Nodes */}\n {target.elements.map((el) => {\n const pos = targetPositions.get(el.id)\n if (!pos) return null\n const inImage = imageSet.has(el.id)\n const isHL = highlightedTargetId === el.id\n const dimmed = highlightedTargetId && !isHL\n\n return (\n <g key={`t-${el.id}`} data-homo-target-node\n onMouseEnter={(e) => {\n setHoverTarget(el.id)\n const rect = svgRef.current?.getBoundingClientRect()\n if (rect && onHover) onHover(el, { x: e.clientX - rect.left, y: e.clientY - rect.top })\n }}\n onMouseLeave={() => { setHoverTarget(null); onHover?.(null, null) }}\n style={{ cursor: 'pointer' }}\n >\n {isHL && (\n <circle cx={pos.x} cy={pos.y} r={18}\n fill=\"none\" stroke={IMAGE_CYAN}\n strokeWidth={2} opacity={0.6}\n style={{ filter: 'drop-shadow(0 0 8px currentColor)' }} />\n )}\n <circle\n cx={pos.x} cy={pos.y} r={inImage ? 13 : 8}\n fill={inImage ? IMAGE_CYAN : 'var(--node-fill)'}\n stroke={inImage ? IMAGE_CYAN : 'var(--border-color)'}\n strokeWidth={inImage ? 2 : 1}\n opacity={dimmed ? 0.3 : 1}\n />\n {highlightPreimageIds.size > 0 && isHL && (\n <text x={pos.x} y={pos.y - 18} textAnchor=\"middle\" fill=\"var(--text-muted)\" fontSize=\"9\">\n ← {highlightPreimageIds.size}\n </text>\n )}\n {showLabels && (\n <foreignObject\n x={pos.x - 24} y={pos.y + 6}\n width={48} height={18}\n style={{ overflow: 'visible' }}\n >\n <div style={{\n fontSize: '8px',\n textAlign: 'center',\n color: inImage ? IMAGE_CYAN : dimmed ? 'var(--text-muted)' : 'var(--text-primary)',\n fontWeight: inImage || isHL ? 700 : 400,\n pointerEvents: 'none',\n }} dangerouslySetInnerHTML={{ __html: renderTex(el.label) }} />\n </foreignObject>\n )}\n </g>\n )\n })}\n\n {/* Legend / status line at bottom */}\n <g transform={`translate(0, ${vh - 16})`}>\n {resolvedResult?.isHomomorphism && properties && (\n <>\n <rect x={leftCx - 50} y={-12} width={100} height={16} rx={3}\n fill={properties.isInjective ? 'rgba(78,205,196,0.15)' : 'rgba(255,107,107,0.1)'} />\n <text x={leftCx} y={0} textAnchor=\"middle\" fontSize=\"9\"\n fill={properties.isInjective ? 'var(--accent-teal)' : KERNEL_RED}>\n {properties.isInjective ? t('homo.injective') : t('homo.notInjective')}\n </text>\n\n <rect x={vw / 2 - 60} y={-12} width={120} height={16} rx={3}\n fill=\"rgba(78,205,196,0.08)\" />\n <text x={vw / 2} y={0} textAnchor=\"middle\" fontSize=\"9\" fill=\"var(--text-muted)\">\n Ker={kernelSet.size}{' '}|{' '}Im={imageSet.size}{' '}|{' '}G/Ker={source.order}/{kernelSet.size}={source.order / (kernelSet.size || 1)}\n </text>\n\n <rect x={rightCx - 50} y={-12} width={100} height={16} rx={3}\n fill={properties.isSurjective ? 'rgba(78,205,196,0.15)' : 'rgba(255,107,107,0.1)'} />\n <text x={rightCx} y={0} textAnchor=\"middle\" fontSize=\"9\"\n fill={properties.isSurjective ? 'var(--accent-teal)' : KERNEL_RED}>\n {properties.isSurjective ? t('homo.surjective') : t('homo.notSurjective')}\n </text>\n\n {properties.isIsomorphism && (\n <>\n <rect x={vw / 2 - 40} y={-26} width={80} height={14} rx={3}\n fill=\"rgba(78,205,196,0.2)\" stroke=\"var(--accent-teal)\" strokeWidth={0.5} />\n <text x={vw / 2} y={-15} textAnchor=\"middle\" fontSize=\"10\" fontWeight=\"bold\" fill=\"var(--accent-teal)\">\n {t('homo.isomorphism')}\n </text>\n </>\n )}\n </>\n )}\n {resolvedResult && !resolvedResult.isHomomorphism && (\n <text x={vw / 2} y={0} textAnchor=\"middle\" fontSize=\"10\" fill={KERNEL_RED} fontWeight=\"bold\">\n ✗ {t('homo.invalid')}\n </text>\n )}\n {/* Interactive hint */}\n <text x={vw - 10} y={0} textAnchor=\"end\" fontSize=\"8\" fill=\"var(--text-muted)\" opacity={0.6}>\n {t('homo.interactiveHint')}\n </text>\n </g>\n </svg>\n )\n}\n","import { useMemo, useState, useRef, useEffect } from 'react'\r\nimport { Canvas, useFrame } from '@react-three/fiber'\r\nimport { OrbitControls, Html } from '@react-three/drei'\r\nimport * as THREE from 'three'\r\nimport { useTranslation } from '../../i18n/useTranslation'\r\nimport { texify, renderTex } from '../../utils/texify'\r\nimport { resolveElementWarn } from '../../utils/elementRef'\r\nimport type { SceneTheme } from './SceneThemeRoot'\r\nimport { computeElementRotation } from '../../core/elementRotation'\r\nimport type { Group, GroupElement } from '../../core/types'\r\nimport { getSymmetryType } from '../../core/symmetryType'\r\nimport type { SymmetryType } from '../../core/symmetryType'\r\n\r\ninterface SymmetryData {\r\n vertices: THREE.Vector3[]\r\n edges: [number, number][]\r\n directed?: boolean\r\n}\r\n\r\nfunction getCyclicFigure(n: number, radius: number): SymmetryData {\r\n const vertices: THREE.Vector3[] = []\r\n const edges: [number, number][] = []\r\n for (let i = 0; i < n; i++) {\r\n const angle = (2 * Math.PI * i) / n - Math.PI / 2\r\n vertices.push(new THREE.Vector3(Math.cos(angle) * radius, 0, Math.sin(angle) * radius))\r\n edges.push([i, (i + 1) % n])\r\n }\r\n return { vertices, edges, directed: true }\r\n}\r\n\r\nfunction getDihedralFigure(n: number, radius: number): SymmetryData {\r\n const vertices: THREE.Vector3[] = []\r\n const edges: [number, number][] = []\r\n for (let i = 0; i < n; i++) {\r\n const angle = (2 * Math.PI * i) / n - Math.PI / 2\r\n vertices.push(new THREE.Vector3(Math.cos(angle) * radius, 0, Math.sin(angle) * radius))\r\n edges.push([i, (i + 1) % n])\r\n }\r\n return { vertices, edges }\r\n}\r\n\r\nfunction getTetrahedron(radius: number): SymmetryData {\r\n const s = radius / Math.sqrt(3)\r\n const vertices = [\r\n new THREE.Vector3(1, 1, 1).multiplyScalar(s),\r\n new THREE.Vector3(1, -1, -1).multiplyScalar(s),\r\n new THREE.Vector3(-1, 1, -1).multiplyScalar(s),\r\n new THREE.Vector3(-1, -1, 1).multiplyScalar(s),\r\n ]\r\n const edges: [number, number][] = []\r\n for (let i = 0; i < 4; i++) for (let j = i + 1; j < 4; j++) edges.push([i, j])\r\n return { vertices, edges }\r\n}\r\n\r\nfunction getCube(radius: number): SymmetryData {\r\n const s = radius / Math.sqrt(3)\r\n const signs = [-1, 1]\r\n const vertices: THREE.Vector3[] = []\r\n for (const x of signs) for (const y of signs) for (const z of signs)\r\n vertices.push(new THREE.Vector3(x * s, y * s, z * s))\r\n const edges: [number, number][] = []\r\n for (let i = 0; i < 8; i++) {\r\n for (let j = i + 1; j < 8; j++) {\r\n const dx = Math.abs(vertices[i].x - vertices[j].x)\r\n const dy = Math.abs(vertices[i].y - vertices[j].y)\r\n const dz = Math.abs(vertices[i].z - vertices[j].z)\r\n if ([dx, dy, dz].filter(v => v > 0.001).length === 1) edges.push([i, j])\r\n }\r\n }\r\n return { vertices, edges }\r\n}\r\n\r\nfunction getIcosahedron(radius: number): SymmetryData {\r\n const φ = (1 + Math.sqrt(5)) / 2\r\n const raw = [[0,1,φ],[0,-1,φ],[0,1,-φ],[0,-1,-φ],[1,φ,0],[-1,φ,0],[1,-φ,0],[-1,-φ,0],[φ,0,1],[φ,0,-1],[-φ,0,1],[-φ,0,-1]]\r\n const maxCoord = Math.sqrt(1 + φ * φ)\r\n const s = radius / maxCoord\r\n const vertices = raw.map(([x,y,z]) => new THREE.Vector3(x*s,y*s,z*s))\r\n const edges: [number,number][] = []\r\n const targetDistSq = 4 * s * s, tol = 0.01 * targetDistSq\r\n for (let i = 0; i < 12; i++)\r\n for (let j = i + 1; j < 12; j++)\r\n if (Math.abs(vertices[i].distanceToSquared(vertices[j]) - targetDistSq) < tol) edges.push([i, j])\r\n return { vertices, edges }\r\n}\r\n\r\nconst TRIANGULAR_FACE_CACHE = new Map<string, [number, number, number][]>()\r\n\r\nfunction getRectangle(radius: number): SymmetryData {\r\n const hw = radius * 1.0, hh = radius * 0.55\r\n const vertices = [new THREE.Vector3(-hw,0,-hh),new THREE.Vector3(hw,0,-hh),new THREE.Vector3(hw,0,hh),new THREE.Vector3(-hw,0,hh)]\r\n const edges: [number,number][] = [[0,1],[1,2],[2,3],[3,0]]\r\n return { vertices, edges }\r\n}\r\n\r\nfunction getOctahedron(radius: number): SymmetryData {\r\n const vertices = [new THREE.Vector3(radius,0,0),new THREE.Vector3(-radius,0,0),new THREE.Vector3(0,radius,0),new THREE.Vector3(0,-radius,0),new THREE.Vector3(0,0,radius),new THREE.Vector3(0,0,-radius)]\r\n const edges: [number,number][] = []\r\n for (let i = 0; i < 6; i++)\r\n for (let j = i + 1; j < 6; j++)\r\n if (Math.abs(vertices[i].distanceToSquared(vertices[j]) - 4*radius*radius) > 0.01) edges.push([i, j])\r\n return { vertices, edges }\r\n}\r\n\r\nfunction getDodecahedron(radius: number): SymmetryData {\r\n const φ = (1+Math.sqrt(5))/2, a=1, b=1/φ, c=φ\r\n const raw: [number,number,number][] = []\r\n for (const x of [-1,1]) for (const y of [-1,1]) for (const z of [-1,1]) raw.push([x*a,y*a,z*a])\r\n for (const s1 of [-1,1]) for (const s2 of [-1,1]) raw.push([0,s1*c,s2*b])\r\n for (const s1 of [-1,1]) for (const s2 of [-1,1]) raw.push([s2*b,0,s1*c])\r\n for (const s1 of [-1,1]) for (const s2 of [-1,1]) raw.push([s1*c,s2*b,0])\r\n const maxCoord = Math.sqrt(a*a+a*a+a*a), ss = radius/maxCoord\r\n const vertices = raw.map(([x,y,z])=>new THREE.Vector3(x*ss,y*ss,z*ss))\r\n const edgeDist = (2*b)*ss, tol = edgeDist*0.05\r\n const edges: [number,number][] = []\r\n for (let i = 0; i < 20; i++)\r\n for (let j = i + 1; j < 20; j++)\r\n if (Math.abs(vertices[i].distanceTo(vertices[j]) - edgeDist) < tol) edges.push([i, j])\r\n return { vertices, edges }\r\n}\r\n\r\nfunction getVertexColor(index: number, total: number): string {\r\n const hue = (index / total) * 360\r\n return `hsl(${hue}, 70%, 60%)`\r\n}\r\n\r\nfunction computeTriangularFaces(data: SymmetryData): [number, number, number][] {\r\n const key = `${data.vertices.length}:${data.edges.map(e => e.join('-')).join('|')}`\r\n const cached = TRIANGULAR_FACE_CACHE.get(key)\r\n if (cached) return cached\r\n const adj = new Map<number, number[]>()\r\n for (let i = 0; i < data.vertices.length; i++) adj.set(i, [])\r\n for (const [a, b] of data.edges) { adj.get(a)!.push(b); adj.get(b)!.push(a) }\r\n const faceSet = new Set<string>()\r\n const faces: [number, number, number][] = []\r\n for (let vi = 0; vi < data.vertices.length; vi++) {\r\n const neighbors = adj.get(vi)!\r\n if (neighbors.length < 2) continue\r\n const vPos = data.vertices[vi], vDir2 = vPos.clone().normalize()\r\n const refDir = new THREE.Vector3().subVectors(data.vertices[neighbors[0]], vPos).normalize()\r\n const sorted = neighbors.map(ni => ({\r\n ni,\r\n angle: Math.atan2(\r\n new THREE.Vector3().crossVectors(refDir, new THREE.Vector3().subVectors(data.vertices[ni], vPos).normalize()).dot(vDir2),\r\n refDir.dot(new THREE.Vector3().subVectors(data.vertices[ni], vPos).normalize())\r\n )\r\n }))\r\n sorted.sort((a, b) => a.angle - b.angle)\r\n for (let si = 0; si < sorted.length; si++) {\r\n const a = sorted[si].ni, b2 = sorted[(si + 1) % sorted.length].ni\r\n if (adj.get(a)?.includes(b2)) {\r\n const fKey = [vi, a, b2].sort().join(',')\r\n if (!faceSet.has(fKey)) {\r\n faceSet.add(fKey)\r\n faces.push([vi, a, b2])\r\n }\r\n }\r\n }\r\n }\r\n TRIANGULAR_FACE_CACHE.set(key, faces)\r\n return faces\r\n}\r\n\r\nfunction getCubeFaceCenters(data: SymmetryData): THREE.Vector3[] {\r\n const s = data.vertices[0].length() / Math.sqrt(3)\r\n return [\r\n new THREE.Vector3(s, 0, 0), new THREE.Vector3(-s, 0, 0),\r\n new THREE.Vector3(0, s, 0), new THREE.Vector3(0, -s, 0),\r\n new THREE.Vector3(0, 0, s), new THREE.Vector3(0, 0, -s),\r\n ]\r\n}\r\n\r\nfunction computeFaceCenters(data: SymmetryData, triangularFaces: [number, number, number][]): THREE.Vector3[] {\r\n const centers: THREE.Vector3[] = []\r\n if (triangularFaces.length > 0 && data.vertices.length <= 12) {\r\n for (const [vi, vj, vk] of triangularFaces) {\r\n centers.push(data.vertices[vi].clone().add(data.vertices[vj]).add(data.vertices[vk]).multiplyScalar(1 / 3))\r\n }\r\n return centers\r\n }\r\n if (data.vertices.length === 8) {\r\n return getCubeFaceCenters(data)\r\n }\r\n if (data.vertices.length >= 20) {\r\n const adj = new Map<number, Set<number>>()\r\n for (let i = 0; i < data.vertices.length; i++) adj.set(i, new Set())\r\n for (const [a, b] of data.edges) { adj.get(a)!.add(b); adj.get(b)!.add(a) }\r\n const found = new Set<string>()\r\n for (let v0 = 0; v0 < data.vertices.length; v0++) {\r\n const neis = [...adj.get(v0)!]\r\n for (let i = 0; i < neis.length; i++) {\r\n for (let j = i + 1; j < neis.length; j++) {\r\n const v1 = neis[i], v2 = neis[j]\r\n if (!adj.get(v1)!.has(v2)) continue\r\n const seeds = adj.get(v2)!.size === 3\r\n ? [...adj.get(v2)!].filter(x => x !== v0 && x !== v1)\r\n : [v2]\r\n for (const v3 of seeds) {\r\n const finalCands = [...adj.get(v3)!].filter(x => x !== v2 && adj.get(v0)!.has(x))\r\n for (const v4 of finalCands) {\r\n const pathVerts = [v0, v1, v2, v3, v4]\r\n const sorted = [...pathVerts].sort((a, b) => a - b)\r\n const key = sorted.join(',')\r\n if (found.has(key)) continue\r\n found.add(key)\r\n const c = new THREE.Vector3()\r\n for (const vi of pathVerts) c.add(data.vertices[vi])\r\n centers.push(c.multiplyScalar(1 / 5))\r\n }\r\n }\r\n }\r\n }\r\n }\r\n return centers\r\n }\r\n return []\r\n}\r\n\r\n/** 轴与转角完全由 core 的置换反解给出(几何体与 core 点模型同源),\r\n * react 侧不再二次选轴——单一真源,避免两层各算一遍导致语义漂移。 */\r\nfunction computeGeometricRotation(group: Group, element: GroupElement): { axis: [number,number,number]; angleRad: number; label: string } | null {\r\n return computeElementRotation(group, element)\r\n}\r\n\r\nexport interface SymmetryViewSceneProps {\r\n /** 展示群(null 由调用方自行占位,本组件要求非空) */\r\n group: Group\r\n /** 对称类型;缺省按 getSymmetryType(group) 推导(unsupported 群渲染提示 overlay) */\r\n symmetryType?: SymmetryType\r\n /** 深色场景配色(背景 + 顶部标注文字);主画布传主主题,ViewWindow 传窗口主题(解耦) */\r\n dark?: boolean\r\n /** 对偶多面体(cube↔octahedron / icosahedron↔dodecahedron):受控形态(false=主形 / true=对偶形)。\r\n * 切换入口由宿主提供(ViewWindow ⚙ 面板 / 主画布 ViewPanel 的 Shape 选项),场景内不再悬浮切换按钮 */\r\n variant?: boolean\r\n /** 元素作用演示开关;缺省 false */\r\n showAction?: boolean\r\n /** 演示元素 id(受控,toggle 语义:点活跃元素回到恒等姿态);缺省 null */\r\n actionElementId?: string | null\r\n /** 动画倍速 0.2–5;缺省 1 */\r\n rotateSpeed?: number\r\n /** 顶部群名 + 几何描述标注;缺省 true(小窗可关) */\r\n showFigureTitle?: boolean\r\n /** 锁定相机交互(拖拽旋转/平移/缩放);演示动画期间本就禁用 */\r\n locked?: boolean\r\n /** 演示状态提示回调(主画布接 hint bar,ViewWindow 显示为内容区底部唯一浮条);缺省无 */\r\n onHint?: (msg: string) => void\r\n /** 演示开启但当前元素无可旋转作用(恒等/未选)时,是否上抛 clickHint 引导;\r\n * 主画布缺省 true(提示去其它视图点元素);ViewWindow 传 false(引导文案写在参数面板,浮条只显示真实状态) */\r\n hintOnIdle?: boolean\r\n /** 重放信号:宿主自增该值即对当前演示元素重播一次动画(姿态不改变目标,\r\n * 解决同元素动画播完一次后无入口重看的缺口);缺省 0 */\r\n replaySignal?: number\r\n /** 显式主题(`'dark' | 'light'`);与 `dark` 二选一,本项优先。\r\n * 推荐新代码用 `theme` —— 与其余 Scene 命名统一(`dark` 作为兼容别名保留) */\r\n theme?: SceneTheme\r\n /** 演示动画期间是否禁用相机旋转 / 平移;缺省 `false`。\r\n * **注意行为变更**:旧实现恒等于 `true`(`enableRotate = !showAction && !locked`),\r\n * 导致\"演示元素未命中 / 恒等元素时动画不跑,视角却已被锁死\"。需要旧行为的宿主显式传 `true`。 */\r\n lockCameraOnAction?: boolean\r\n /** 演示动画播放结束(姿态落定)回调;用于宿主编排「看完自动切下一个」等自定义流程 */\r\n onAnimationEnd?: () => void\r\n}\r\n\r\n/** 对称性视图纯渲染核(props 化、主题解耦):Canvas + 场景 + 顶部标注 + 演示动画。\r\n * 主画布经 SymmetryView 适配器接入全局 context;ViewWindow(FGVE 引擎)受控直接使用。 */\r\nexport function SymmetryViewScene({\r\n group,\r\n symmetryType: symmetryTypeProp,\r\n dark = false,\r\n variant = false,\r\n showAction = false,\r\n actionElementId = null,\r\n rotateSpeed = 1,\r\n showFigureTitle = true,\r\n locked = false,\r\n onHint,\r\n hintOnIdle = true,\r\n replaySignal = 0,\r\n theme,\r\n lockCameraOnAction = false,\r\n onAnimationEnd,\r\n}: SymmetryViewSceneProps) {\r\n const symmetryType = symmetryTypeProp ?? getSymmetryType(group)\r\n const isDark = theme ? theme === 'dark' : dark\r\n\r\n // hooks 前置(不随 unsupported 分支提前返回,保证切换群时 hooks 顺序稳定)\r\n const data = useMemo((): SymmetryData => {\r\n const radius = 4\r\n switch (symmetryType) {\r\n case 'cyclic': return getCyclicFigure(group.order, radius)\r\n case 'dihedral': { const n = group.order / 2; return getDihedralFigure(Math.round(n), radius) }\r\n case 'tetrahedron': return getTetrahedron(radius)\r\n case 'cube': return variant ? getOctahedron(radius) : getCube(radius)\r\n case 'icosahedron': return variant ? getDodecahedron(radius) : getIcosahedron(radius)\r\n case 'rectangle': return getRectangle(radius)\r\n default: return getCyclicFigure(1, radius)\r\n }\r\n }, [group, symmetryType, variant])\r\n\r\n if (symmetryType === 'unsupported') return <UnsupportedOverlay group={group} />\r\n\r\n const bgColor = isDark ? '#0a0a1a' : '#f4f4f7'\r\n\r\n return (\r\n <div style={{ width: '100%', height: '100%', background: bgColor }}>\r\n <Canvas camera={{ position: [0, 3, 10], fov: 50, near: 0.1, far: 100 }} gl={{ antialias: true, alpha: false, preserveDrawingBuffer: true }}>\r\n <color attach=\"background\" args={[bgColor]} />\r\n <SymmetryScene\r\n group={group}\r\n symmetryType={symmetryType}\r\n data={data}\r\n variant={variant}\r\n showAction={showAction}\r\n actionElementId={actionElementId}\r\n rotateSpeed={rotateSpeed}\r\n showFigureTitle={showFigureTitle}\r\n dark={isDark}\r\n locked={locked}\r\n onHint={onHint}\r\n hintOnIdle={hintOnIdle}\r\n replaySignal={replaySignal}\r\n lockCameraOnAction={lockCameraOnAction}\r\n onAnimationEnd={onAnimationEnd}\r\n />\r\n </Canvas>\r\n </div>\r\n )\r\n}\r\n\r\n\r\nfunction useAnimatedRotation(\r\n targetQuat: THREE.Quaternion | null,\r\n speed: number,\r\n onPhaseChange: (phase: 'rest' | 'reset' | 'rotating') => void,\r\n replaySignal?: number,\r\n onAnimationEnd?: () => void,\r\n) {\r\n const stateRef = useRef({\r\n target: null as THREE.Quaternion | null,\r\n t: 2,\r\n speed: 1,\r\n phase: 'rest' as 'rest' | 'reset' | 'rotating',\r\n settled: false,\r\n currentQuat: new THREE.Quaternion(),\r\n })\r\n\r\n // 结束回调放 ref:避免宿主每帧传新闭包导致 useFrame 里读到过期函数。\r\n // 用 effect 同步而非渲染期赋值 —— 渲染期写 ref 会触发 react-hooks/refs。\r\n const endRef = useRef(onAnimationEnd)\r\n useEffect(() => { endRef.current = onAnimationEnd }, [onAnimationEnd])\r\n\r\n useEffect(() => { stateRef.current.speed = speed }, [speed])\r\n\r\n useEffect(() => {\r\n if (targetQuat) {\r\n stateRef.current.target = targetQuat.clone()\r\n stateRef.current.t = 0\r\n stateRef.current.phase = 'reset'\r\n stateRef.current.settled = false\r\n onPhaseChange('reset')\r\n } else {\r\n stateRef.current.target = null\r\n stateRef.current.t = 2\r\n stateRef.current.settled = false\r\n stateRef.current.phase = 'rest'\r\n stateRef.current.currentQuat.identity()\r\n onPhaseChange('rest')\r\n }\r\n }, [targetQuat, onPhaseChange])\r\n\r\n // 显式重放:replaySignal 递增即对当前姿态再播一次(不改变目标),\r\n // 解决\"动画只在元素切换时播一次、同元素无法重看\"的交互缺口。\r\n useEffect(() => {\r\n const st = stateRef.current\r\n if (!replaySignal || !st.target) return\r\n st.t = 0\r\n st.phase = 'reset'\r\n st.settled = false\r\n onPhaseChange('reset')\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [replaySignal])\r\n\r\n useFrame((_, dt) => {\r\n const st = stateRef.current\r\n if (!st.target || st.t > 1.5) return\r\n st.t += dt * st.speed\r\n if (st.phase === 'reset') {\r\n if (st.t >= 0.5) { st.phase = 'rotating'; st.t = 0.5; onPhaseChange('rotating') }\r\n else { st.currentQuat.identity(); return }\r\n }\r\n if (st.t >= 1) {\r\n st.t = 2; st.settled = true; st.phase = 'rest'; onPhaseChange('rest')\r\n st.currentQuat.copy(st.target)\r\n // 姿态落定 → 通知宿主「这次演示播完了」(重放会再次触发)\r\n endRef.current?.()\r\n } else {\r\n st.currentQuat.slerpQuaternions(new THREE.Quaternion(), st.target, (st.t - 0.5) / 0.5)\r\n }\r\n })\r\n\r\n return stateRef\r\n}\r\n\r\nfunction AnimatedGeo({ data, symmetryType, isDirected, animState }: {\r\n data: SymmetryData\r\n symmetryType: SymmetryType\r\n isDirected: boolean\r\n animState: { current: { currentQuat: THREE.Quaternion } }\r\n}) {\r\n const [group] = useState(() => new THREE.Group())\r\n\r\n useEffect(() => {\r\n while (group.children.length > 0) group.remove(group.children[0])\r\n\r\n data.vertices.forEach((v, i) => {\r\n const mesh = new THREE.Mesh(\r\n new THREE.SphereGeometry(0.28, 16, 16),\r\n new THREE.MeshStandardMaterial({ color: getVertexColor(i, data.vertices.length), roughness: 0.3, metalness: 0.1, emissive: getVertexColor(i, data.vertices.length), emissiveIntensity: 0.3 })\r\n )\r\n mesh.position.copy(v)\r\n group.add(mesh)\r\n })\r\n\r\n data.edges.forEach(([a, b]) => {\r\n const from = data.vertices[a], to = data.vertices[b]\r\n const pts = [from.clone(), to.clone()]\r\n const geom = new THREE.BufferGeometry().setFromPoints(pts)\r\n const color = isDirected ? '#ff6b6b' : '#66aaff'\r\n group.add(new THREE.Line(geom, new THREE.LineBasicMaterial({ color })))\r\n if (isDirected) {\r\n const dir = new THREE.Vector3().subVectors(to, from).normalize()\r\n const p = new THREE.Vector3(-dir.z, 0, dir.x)\r\n const tip = to.clone().addScaledVector(dir, -0.35)\r\n const w1 = tip.clone().addScaledVector(dir, -0.12).addScaledVector(p, 0.1)\r\n const w2 = tip.clone().addScaledVector(dir, -0.12).addScaledVector(p, -0.1)\r\n const ag = new THREE.BufferGeometry().setFromPoints([w1, tip, w2])\r\n group.add(new THREE.Line(ag, new THREE.LineBasicMaterial({ color })))\r\n }\r\n })\r\n\r\n if (['tetrahedron', 'cube', 'icosahedron'].includes(symmetryType)) {\r\n const fc = symmetryType === 'cube' ? '#ff9944' : symmetryType === 'tetrahedron' ? '#44cc88' : '#cc66ff'\r\n const faces = computeTriangularFaces(data)\r\n if (faces.length > 0) {\r\n const pos: number[] = [], idx: number[] = []\r\n for (const [vi, a, b2] of faces) {\r\n const i2 = pos.length / 3\r\n const va = data.vertices[vi], vb = data.vertices[a], vc = data.vertices[b2]\r\n pos.push(va.x, va.y, va.z, vb.x, vb.y, vb.z, vc.x, vc.y, vc.z)\r\n idx.push(i2, i2 + 1, i2 + 2)\r\n }\r\n const fg = new THREE.BufferGeometry()\r\n fg.setAttribute('position', new THREE.Float32BufferAttribute(pos, 3))\r\n fg.setIndex(idx)\r\n fg.computeVertexNormals()\r\n group.add(new THREE.Mesh(fg, new THREE.MeshStandardMaterial({ color: fc, transparent: true, opacity: 0.3, side: THREE.DoubleSide, depthWrite: false })))\r\n }\r\n }\r\n }, [data, symmetryType, isDirected, group])\r\n\r\n useFrame(() => {\r\n group.quaternion.copy(animState.current.currentQuat)\r\n })\r\n\r\n return <primitive object={group} />\r\n}\r\n\r\nfunction AxisMarker({ from, to, intersections }: {\r\n from: THREE.Vector3\r\n to: THREE.Vector3\r\n intersections: { pos: THREE.Vector3; kind: 'vertex' | 'edge' | 'face-center' }[]\r\n}) {\r\n const mid = useMemo(() => from.clone().add(to).multiplyScalar(0.5), [from, to])\r\n const dir = useMemo(() => to.clone().sub(from).normalize(), [from, to])\r\n const len = useMemo(() => to.distanceTo(from), [from, to])\r\n const quat = useMemo(() => {\r\n const q = new THREE.Quaternion()\r\n q.setFromUnitVectors(new THREE.Vector3(0, 1, 0), dir)\r\n return q\r\n }, [dir])\r\n\r\n return (\r\n <group>\r\n <mesh position={mid} quaternion={quat}>\r\n <cylinderGeometry args={[0.12, 0.12, len, 8]} />\r\n <meshStandardMaterial color=\"#ff3333\" emissive=\"#ff0000\" emissiveIntensity={1.0} roughness={0.1} />\r\n </mesh>\r\n <mesh position={to} quaternion={quat}>\r\n <coneGeometry args={[0.28, 0.7, 8, 1]} />\r\n <meshStandardMaterial color=\"#ff3333\" emissive=\"#ff0000\" emissiveIntensity={1.0} roughness={0.1} />\r\n </mesh>\r\n {intersections.map((intr, i) => (\r\n <mesh key={i} position={intr.pos}>\r\n <sphereGeometry args={[intr.kind === 'vertex' ? 0.24 : intr.kind === 'face-center' ? 0.22 : 0.16, 12, 12]} />\r\n <meshStandardMaterial\r\n color={intr.kind === 'vertex' ? '#ffd93d' : intr.kind === 'face-center' ? '#84cc16' : '#4ecdc4'}\r\n emissive={intr.kind === 'vertex' ? '#ffd93d' : intr.kind === 'face-center' ? '#84cc16' : '#4ecdc4'}\r\n emissiveIntensity={0.7}\r\n roughness={0.1}\r\n />\r\n </mesh>\r\n ))}\r\n </group>\r\n )\r\n}\r\n\r\nfunction SymmetryScene({\r\n group, symmetryType, data, variant,\r\n showAction, actionElementId, rotateSpeed,\r\n showFigureTitle, dark, locked, onHint, hintOnIdle, replaySignal,\r\n lockCameraOnAction, onAnimationEnd,\r\n}: {\r\n group: Group\r\n symmetryType: SymmetryType\r\n data: SymmetryData | null\r\n variant: boolean\r\n showAction: boolean\r\n actionElementId: string | null\r\n rotateSpeed: number\r\n showFigureTitle: boolean\r\n dark: boolean\r\n locked: boolean\r\n onHint?: (msg: string) => void\r\n hintOnIdle: boolean\r\n replaySignal: number\r\n lockCameraOnAction: boolean\r\n onAnimationEnd?: () => void\r\n}) {\r\n const { t } = useTranslation()\r\n const [animPhase, setAnimPhase] = useState<'rest' | 'reset' | 'rotating'>('rest')\r\n\r\n const animInfo = useMemo(() => {\r\n if (!showAction || !actionElementId || !data) return null\r\n // 引用解析接受 id / label / value —— 传 label 不再是静默失败(未命中会 warn 一次)\r\n const el = resolveElementWarn(group, actionElementId, 'SymmetryViewScene.actionElementId')\r\n if (!el) return null\r\n const result = computeGeometricRotation(group, el)\r\n if (!result || result.angleRad === 0) return null\r\n return result\r\n }, [showAction, actionElementId, group, data])\r\n\r\n const targetQuat = useMemo(() => {\r\n if (!animInfo || animInfo.angleRad === 0) return null\r\n const q = new THREE.Quaternion()\r\n q.setFromAxisAngle(new THREE.Vector3(...animInfo.axis), animInfo.angleRad)\r\n return q\r\n }, [animInfo])\r\n\r\n const animRef = useAnimatedRotation(targetQuat, rotateSpeed, setAnimPhase, replaySignal, onAnimationEnd)\r\n\r\n // 演示状态反馈:统一经 onHint 上抛(主画布 hint bar / ViewWindow 底部浮条),宿主各自决定单处展示位置\r\n const activeEl = useMemo(\r\n () => (showAction && actionElementId\r\n ? resolveElementWarn(group, actionElementId, 'SymmetryViewScene.actionElementId')\r\n : null),\r\n [showAction, actionElementId, group],\r\n )\r\n const statusText = useMemo(() => {\r\n if (!activeEl || !animInfo) return null\r\n const phaseSuffix = animPhase === 'reset' ? ` — ${t('symmetry.reset')}`\r\n : animPhase === 'rotating' ? ` — ${t('symmetry.rotating')}`\r\n : ''\r\n return { label: activeEl.label, action: animInfo.label, suffix: phaseSuffix }\r\n }, [activeEl, animInfo, animPhase, t])\r\n\r\n useEffect(() => {\r\n if (!showAction) return\r\n if (!statusText) {\r\n // 演示开启但当前元素无可演示的几何旋转(未选 / 恒等)→ 仅主画布需要 clickHint 引导;\r\n // ViewWindow 的引导文案写在 ⚙ 面板元素列表旁(hintOnIdle=false),浮条只显示真实演示状态\r\n if (hintOnIdle) onHint?.(t('symmetry.clickHint'))\r\n return\r\n }\r\n onHint?.(`<span class=\"hint-highlight\">${statusText.label}</span>: ${statusText.action}${statusText.suffix}`)\r\n }, [showAction, statusText, onHint, hintOnIdle, t])\r\n\r\n const hasData = !!data\r\n const isDirected = data?.directed === true\r\n const topY = useMemo(() => data ? data.vertices.reduce((max, v) => Math.max(max, v.y), -Infinity) : 0, [data])\r\n const dataRadius = useMemo(() => data ? data.vertices[0].length() : 4, [data])\r\n\r\n const showAxis = animInfo && Math.abs(animInfo.angleRad) > 1e-10\r\n const axisLen = dataRadius * 1.4\r\n const axisTo = showAxis\r\n ? new THREE.Vector3(...animInfo!.axis).normalize().multiplyScalar(axisLen)\r\n : new THREE.Vector3()\r\n const axisNeg = showAxis\r\n ? new THREE.Vector3(...animInfo!.axis).normalize().multiplyScalar(-axisLen * 0.6)\r\n : new THREE.Vector3()\r\n const axisIntersections = useMemo(() => {\r\n if (!showAxis || !data) return []\r\n const dir = new THREE.Vector3(...animInfo!.axis).normalize()\r\n const intersections: { pos: THREE.Vector3; kind: 'vertex' | 'edge' | 'face-center' }[] = []\r\n const VERTEX_THRESH = 0.25\r\n const EDGE_MID_THRESH = 0.25\r\n const FACE_CENTER_THRESH = 0.25\r\n\r\n for (const v of data.vertices) {\r\n const proj = v.dot(dir)\r\n const closest = dir.clone().multiplyScalar(proj)\r\n if (v.distanceTo(closest) < VERTEX_THRESH) {\r\n intersections.push({ pos: closest.clone(), kind: 'vertex' })\r\n }\r\n }\r\n\r\n for (const [a, b] of data.edges) {\r\n const mid = data.vertices[a].clone().add(data.vertices[b]).multiplyScalar(0.5)\r\n const proj = mid.dot(dir)\r\n const closest = dir.clone().multiplyScalar(proj)\r\n if (mid.distanceTo(closest) < EDGE_MID_THRESH) {\r\n intersections.push({ pos: closest.clone(), kind: 'edge' })\r\n }\r\n }\r\n\r\n const triangularFaces = computeTriangularFaces(data)\r\n const faceCenters = computeFaceCenters(data, triangularFaces)\r\n for (const fc of faceCenters) {\r\n const proj = fc.dot(dir)\r\n const closest = dir.clone().multiplyScalar(proj)\r\n if (fc.distanceTo(closest) < FACE_CENTER_THRESH) {\r\n intersections.push({ pos: closest.clone(), kind: 'face-center' })\r\n }\r\n }\r\n\r\n const merged: { pos: THREE.Vector3; kind: 'vertex' | 'edge' | 'face-center' }[] = []\r\n for (const intr of intersections) {\r\n const dup = merged.find(m => m.pos.distanceTo(intr.pos) < 0.01)\r\n if (!dup) merged.push(intr)\r\n else if (intr.kind === 'vertex' && dup.kind !== 'vertex') {\r\n dup.kind = 'vertex'; dup.pos.copy(intr.pos)\r\n } else if (intr.kind === 'face-center' && dup.kind === 'edge') {\r\n dup.kind = 'face-center'; dup.pos.copy(intr.pos)\r\n }\r\n }\r\n\r\n return merged\r\n }, [showAxis, animInfo, data])\r\n\r\n if (!hasData) return null\r\n\r\n return (\r\n <>\r\n <ambientLight intensity={0.4} />\r\n <directionalLight position={[5, 8, 5]} intensity={1.2} />\r\n <directionalLight position={[-5, -2, -3]} intensity={0.6} />\r\n <pointLight position={[0, 5, 0]} intensity={0.5} />\r\n\r\n {showFigureTitle && (\r\n <Html position={[0, topY + 1.5, 0]} center zIndexRange={[2, 0]} wrapperClass=\"gv-html-overlay\">\r\n <div style={{ color: dark ? '#fff' : '#1a1a2e', fontSize: '20px', fontWeight: 'bold', textShadow: dark ? '0 0 10px rgba(0,0,0,0.8)' : 'none', whiteSpace: 'nowrap', userSelect: 'none', pointerEvents: 'none' }}\r\n dangerouslySetInnerHTML={{ __html: renderTex(texify(group.name)) }} />\r\n </Html>\r\n )}\r\n\r\n {showFigureTitle && (\r\n <Html position={[0, topY + 2.2, 0]} center zIndexRange={[2, 0]} wrapperClass=\"gv-html-overlay\">\r\n <div style={{ color: dark ? '#aaa' : '#555566', fontSize: '13px', textShadow: dark ? '0 0 8px rgba(0,0,0,0.8)' : 'none', whiteSpace: 'nowrap', userSelect: 'none', pointerEvents: 'none' }}\r\n dangerouslySetInnerHTML={{ __html: renderTex(\r\n // 副标题只描述几何形态(群名已在上方标题行,不再重复符号前缀)\r\n symmetryType === 'cyclic' ? t('symmetry.geo.cyclicText', { n: group.order }) :\r\n symmetryType === 'dihedral' ? t('symmetry.geo.dihedralText', { n: group.order / 2 }) :\r\n symmetryType === 'cube' ? (variant ? t('symmetry.geo.octahedron') : t('symmetry.geo.cube')) :\r\n symmetryType === 'icosahedron' ? (variant ? t('symmetry.geo.dodecahedron') : t('symmetry.geo.icosahedron')) :\r\n t('symmetry.geo.' + symmetryType)\r\n ) }} />\r\n </Html>\r\n )}\r\n\r\n {showAxis && (\r\n <AxisMarker\r\n from={axisNeg}\r\n to={axisTo}\r\n intersections={axisIntersections}\r\n />\r\n )}\r\n\r\n <AnimatedGeo data={data} symmetryType={symmetryType} isDirected={isDirected} animState={animRef} />\r\n\r\n {symmetryType === 'dihedral' && data.vertices.length > 2 && (\r\n <mesh rotation={[-Math.PI / 2, 0, 0]}>\r\n <circleGeometry args={[data.vertices[0].length() * 0.97, 64]} />\r\n <meshStandardMaterial color=\"#66aaff\" transparent opacity={0.15} side={THREE.DoubleSide} depthWrite={false} />\r\n </mesh>\r\n )}\r\n\r\n {symmetryType === 'cyclic' && (\r\n <mesh rotation={[-Math.PI / 2, 0, 0]}>\r\n <ringGeometry args={[data.vertices[0].length() * 0.93, data.vertices[0].length() * 0.97, 64]} />\r\n <meshStandardMaterial color=\"#ff6b6b\" transparent opacity={0.3} side={THREE.DoubleSide} depthWrite={false} />\r\n </mesh>\r\n )}\r\n\r\n <OrbitControls\r\n enableDamping={false}\r\n minDistance={2}\r\n maxDistance={20}\r\n enableRotate={!locked && !(showAction && lockCameraOnAction)}\r\n enablePan={!locked && !(showAction && lockCameraOnAction)}\r\n enableZoom={!locked}\r\n />\r\n </>\r\n )\r\n}\r\n\r\nfunction UnsupportedOverlay({ group }: { group: Group }) {\r\n const { t } = useTranslation()\r\n return (\r\n <div style={{ width: '100%', height: '100%', background: 'var(--bg-canvas)', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', color: 'var(--text-muted)' }}>\r\n <p style={{ fontSize: '18px', marginBottom: '8px' }}><span dangerouslySetInnerHTML={{ __html: renderTex(texify(group.name)) }} /></p>\r\n <p style={{ fontSize: '14px', color: 'var(--text-subtle)' }}>{t('symmetry.unsupported')}</p>\r\n <p style={{ fontSize: '12px', color: 'var(--text-dim)', marginTop: '12px' }}>{t('symmetry.supported')}</p>\r\n </div>\r\n )\r\n}\r\n","import { createContext, useState, useCallback, useEffect, type ReactNode } from 'react'\n\nexport type Theme = 'dark' | 'light'\n\nexport interface ThemeContextValue {\n theme: Theme\n toggleTheme: () => void\n /** 视图窗口(浮动窗/ViewWindow)独立的深浅色主题,与主界面 theme 解耦 */\n viewWindowTheme: Theme\n toggleViewWindowTheme: () => void\n}\n\n// eslint-disable-next-line react-refresh/only-export-components\nexport const ThemeContext = createContext<ThemeContextValue>({\n theme: 'dark',\n toggleTheme: () => { },\n viewWindowTheme: 'dark',\n toggleViewWindowTheme: () => { },\n})\n\nfunction getSystemTheme(): Theme {\n if (typeof window === 'undefined') return 'dark'\n if (window.matchMedia('(prefers-color-scheme: light)').matches) return 'light'\n return 'dark'\n}\n\nfunction getStoredTheme(): Theme | null {\n if (typeof window === 'undefined') return null\n try {\n const stored = localStorage.getItem('groupviz-theme')\n if (stored === 'dark' || stored === 'light') return stored\n } catch { /* localStorage unavailable (e.g., privacy mode) */ }\n return null\n}\n\nfunction getStoredViewWindowTheme(): Theme | null {\n if (typeof window === 'undefined') return null\n try {\n const stored = localStorage.getItem('groupviz-viewwindow-theme')\n if (stored === 'dark' || stored === 'light') return stored\n } catch { /* localStorage unavailable (e.g., privacy mode) */ }\n return null\n}\n\nfunction applyTheme(theme: Theme) {\n if (typeof document === 'undefined') return\n document.documentElement.setAttribute('data-theme', theme)\n}\n\nexport function ThemeProvider({ children }: { children: ReactNode }) {\n const [theme, setThemeState] = useState<Theme>(() => {\n const stored = getStoredTheme()\n if (stored) return stored\n return getSystemTheme()\n })\n\n // 视图窗口主题:独立于主界面 theme,默认深色(图形对比度更佳)\n const [viewWindowTheme, setViewWindowThemeState] = useState<Theme>(() => {\n return getStoredViewWindowTheme() ?? 'dark'\n })\n\n const toggleTheme = useCallback(() => {\n setThemeState(prev => {\n const next = prev === 'dark' ? 'light' : 'dark'\n localStorage.setItem('groupviz-theme', next)\n return next\n })\n }, [])\n\n const toggleViewWindowTheme = useCallback(() => {\n setViewWindowThemeState(prev => {\n const next = prev === 'dark' ? 'light' : 'dark'\n localStorage.setItem('groupviz-viewwindow-theme', next)\n return next\n })\n }, [])\n\n const setTheme = useCallback((t: Theme) => {\n setThemeState(t)\n localStorage.setItem('groupviz-theme', t)\n }, [])\n\n useEffect(() => {\n applyTheme(theme)\n }, [theme])\n\n useEffect(() => {\n const mql = window.matchMedia('(prefers-color-scheme: light)')\n const handler = (e: MediaQueryListEvent) => {\n const stored = getStoredTheme()\n if (!stored) {\n setTheme(e.matches ? 'light' : 'dark')\n }\n }\n mql.addEventListener('change', handler)\n return () => mql.removeEventListener('change', handler)\n }, [setTheme])\n\n return (\n <ThemeContext.Provider value={{ theme, toggleTheme, viewWindowTheme, toggleViewWindowTheme }}>\n {children}\n </ThemeContext.Provider>\n )\n}\n","import { useContext } from 'react'\nimport { ThemeContext, ThemeProvider } from './ThemeContext'\n\nexport function useTheme() {\n return useContext(ThemeContext)\n}\n\nexport { ThemeProvider }\nexport type { Theme } from './ThemeContext'\n","import type * as THREE from 'three'\n\n// 3D 凯莱图视图的轨道控制注册桥:导出 GIF 时按「帧序号 × 帧延时」精确驱动相机旋转。\n// Cayley3DView 挂载时注册(仅主视口 .canvas-viewport 内的实例),导出完成后恢复原视角。\n// GIF 相机在独立离屏渲染器上工作:不触碰实时轨道/相机,导出期间展示区照常旋转。\n\nexport interface Cayley3DOrbitSnapshot {\n theta: number\n phi: number\n radius: number\n target: THREE.Vector3\n}\n\nexport interface Cayley3DControlAPI {\n isReady: () => boolean\n snapshotOrbit: () => Cayley3DOrbitSnapshot\n beginRotation: (radPerSec: number) => void\n endRotation: (snapshot?: Cayley3DOrbitSnapshot | null) => void\n // 展示区当前的自动旋转角速度(与 ▶ 自动旋转/拖拽后同公式):GIF 按此速度导出,\n // 保证导出动图与展示区转速一致(rad/s,与群阶数无关)\n displayAngVel: () => number\n // 导出第 index 帧:将离屏相机设到「基准角 + radPerSec × index × frameDelayMs」并渲染,\n // 返回渲染好的离屏 canvas(导出循环直接 drawImage 采集,不动实时画面)\n frameAt: (index: number, frameDelayMs: number) => HTMLCanvasElement | null\n}\n\nlet registered: Cayley3DControlAPI | null = null\n\nexport function registerCayley3DControls(api: Cayley3DControlAPI) {\n registered = api\n}\n\nexport function unregisterCayley3DControls(api: Cayley3DControlAPI) {\n if (registered === api) registered = null\n}\n\nexport function getCayley3DControls(): Cayley3DControlAPI | null {\n return registered\n}","import { useRef, useMemo, useEffect, useState, useCallback, memo } from 'react'\r\nimport { Canvas, useFrame, useThree } from '@react-three/fiber'\r\nimport { Html } from '@react-three/drei'\r\nimport * as THREE from 'three'\r\nimport { useTranslation } from '../../i18n/useTranslation'\r\nimport { useTheme } from '../../theme/useTheme'\r\nimport type { Group, GroupElement, Generator, MultiplyType, Layout3D } from '../../core/types'\r\nimport { getDefaultLayout3D } from '../../core/types'\r\nimport { computeCayleyActionEdges } from '../../core/algebra/forceLayout'\r\nimport { compute3DPositions } from '../../core/algebra/layout3D'\r\nimport { texify, renderTex } from '../../utils/texify'\r\nimport { registerCayley3DControls, unregisterCayley3DControls } from '../../utils/cayley3dControls'\r\nimport type { Cayley3DControlAPI } from '../../utils/cayley3dControls'\r\nimport { normalizeCayleyActions } from '../../context/cayleyActions'\r\nimport type { CayleyActionParam, Cayley3DFaceFillParams } from '../../core/types/viewConfig'\r\nimport { subgroupFaces, buildUndirectedEdgeKeys, FACE_COLOR_PALETTE } from '../../core/algebra/faces3D'\r\n\r\ninterface EdgeData {\r\n fromIdx: number\r\n toIdx: number\r\n fromId: string\r\n toId: string\r\n fromPos: THREE.Vector3\r\n toPos: THREE.Vector3\r\n gen: Generator\r\n isSelfLoop: boolean\r\n isBidirectional?: boolean\r\n}\r\n\r\nfunction getElementColor(idx: number, total: number, isAbelian: boolean): string {\r\n if (isAbelian) {\r\n const hue = (idx / total) * 360\r\n return `hsl(${hue}, 60%, 55%)`\r\n }\r\n const hue = (idx * 137.508) % 360\r\n return `hsl(${hue}, 65%, 55%)`\r\n}\r\n\r\ninterface NodeSphereProps {\r\n position: THREE.Vector3\r\n label: string\r\n color: string\r\n isSelected: boolean\r\n isHovered: boolean\r\n subsetColor: string | null\r\n element: GroupElement\r\n nodeScale: number\r\n showLabel: boolean\r\n /** 深色主题(label 阴影深浅)。由 Scene 层从 theme prop / ThemeContext 统一解析后传入(FGVE 入包:子组件不再读 context) */\r\n isDark: boolean\r\n onSelectElement: (id: string, additive: boolean) => void\r\n onPointerEnter: (el: GroupElement) => void\r\n onPointerLeave: (el: GroupElement | null) => void\r\n}\r\n\r\nconst NodeSphere = memo(function NodeSphere({ position, label, color, isSelected, isHovered, subsetColor, element, nodeScale, showLabel, isDark, onSelectElement, onPointerEnter, onPointerLeave }: NodeSphereProps) {\r\n const texLabel = useMemo(() => renderTex(texify(label)), [label])\r\n const primary = isSelected || isHovered\r\n const seg = primary ? 24 : 12\r\n\r\n return (\r\n <group position={position}>\r\n <mesh\r\n onClick={(e) => {\r\n e.stopPropagation()\r\n onSelectElement(element.id, e.nativeEvent.ctrlKey || e.nativeEvent.metaKey)\r\n }}\r\n onPointerEnter={() => onPointerEnter(element)}\r\n onPointerLeave={() => onPointerLeave(null)}\r\n >\r\n <sphereGeometry args={[primary ? 0.55 * nodeScale : 0.42 * nodeScale, seg, seg]} />\r\n <meshStandardMaterial\r\n color={primary ? color : subsetColor || color}\r\n emissive={primary ? color : subsetColor || color}\r\n emissiveIntensity={primary ? 0.6 : subsetColor ? 0.4 : 0.2}\r\n roughness={0.3}\r\n metalness={0.1}\r\n />\r\n </mesh>\r\n {subsetColor && !isSelected && (\r\n <mesh>\r\n <sphereGeometry args={[0.55 * nodeScale, 32, 32]} />\r\n <meshBasicMaterial color={subsetColor} transparent opacity={0.25} />\r\n </mesh>\r\n )}\r\n {isSelected && (\r\n <mesh>\r\n <sphereGeometry args={[0.62 * nodeScale, 32, 32]} />\r\n <meshBasicMaterial color=\"#ffd93d\" transparent opacity={0.3} />\r\n </mesh>\r\n )}\r\n {showLabel && primary && (\r\n <Html distanceFactor={12} center style={{ pointerEvents: 'none', userSelect: 'none' }} wrapperClass=\"gv-html-overlay\">\r\n <div\r\n style={{\r\n color: 'var(--node-text)', fontSize: 11, fontWeight: 'bold',\r\n textShadow: isDark ? '0 0 6px rgba(0,0,0,0.8)' : '0 0 4px rgba(255,255,255,0.9)', whiteSpace: 'nowrap',\r\n fontFamily: 'serif', display: 'flex', alignItems: 'center', justifyContent: 'center'\r\n }}\r\n dangerouslySetInnerHTML={{ __html: texLabel }}\r\n />\r\n </Html>\r\n )}\r\n </group>\r\n )\r\n})\r\n\r\ninterface EdgeLineProps {\r\n start: THREE.Vector3\r\n end: THREE.Vector3\r\n color: string\r\n isHighlighted: boolean\r\n isSelfLoop: boolean\r\n isBidirectional?: boolean\r\n showArrow?: boolean\r\n}\r\n\r\nconst StraightEdge = memo(function StraightEdge({ start, end, color, isHighlighted }: { start: THREE.Vector3; end: THREE.Vector3; color: string; isHighlighted: boolean }) {\r\n const meshRef = useRef<THREE.Mesh>(null)\r\n\r\n const dir = new THREE.Vector3().subVectors(end, start)\r\n const len = dir.length()\r\n dir.normalize()\r\n\r\n const mid = new THREE.Vector3().addVectors(start, end).multiplyScalar(0.5)\r\n const thickness = isHighlighted ? 0.08 : 0.05\r\n\r\n useEffect(() => {\r\n const mesh = meshRef.current\r\n // 真实 R3F 下 mesh 是 THREE.Mesh(quaternion 必在);测试 stub 的 DOM 元素无此属性,跳过\r\n if (!mesh?.quaternion) return\r\n const quat = new THREE.Quaternion()\r\n quat.setFromUnitVectors(new THREE.Vector3(0, 1, 0), dir.clone())\r\n mesh.quaternion.copy(quat)\r\n }, [dir])\r\n\r\n return (\r\n <mesh ref={meshRef} position={mid}>\r\n <cylinderGeometry args={[thickness, thickness, len, 4, 1]} />\r\n <meshStandardMaterial color={color} emissive={color} emissiveIntensity={isHighlighted ? 0.7 : 0.25} roughness={0.4} />\r\n </mesh>\r\n )\r\n})\r\n\r\n// 直线边箭头锥:仅小群渲染(避免大群 draw call 爆炸);与 2D 约定一致,双向边不画箭头\r\nconst ArrowCone = memo(function ArrowCone({ position, direction, color, isHighlighted }: {\r\n position: THREE.Vector3\r\n direction: THREE.Vector3\r\n color: string\r\n isHighlighted: boolean\r\n}) {\r\n const quat = useMemo(() => {\r\n const q = new THREE.Quaternion()\r\n q.setFromUnitVectors(new THREE.Vector3(0, 1, 0), direction)\r\n return q\r\n }, [direction])\r\n return (\r\n <mesh position={position} quaternion={quat}>\r\n <coneGeometry args={[0.11, 0.32, 8, 1]} />\r\n <meshStandardMaterial color={color} emissive={color} emissiveIntensity={isHighlighted ? 0.7 : 0.25} roughness={0.4} />\r\n </mesh>\r\n )\r\n})\r\n\r\nconst EdgeLine = memo(function EdgeLine({ start, end, color, isHighlighted, isSelfLoop, isBidirectional, showArrow }: EdgeLineProps) {\r\n if (isSelfLoop) {\r\n return (\r\n <group position={start}>\r\n <mesh rotation={[Math.PI / 2, 0, 0]} position={[0, 1.0, 0]}>\r\n <torusGeometry args={[0.4, 0.04, 8, 16]} />\r\n <meshStandardMaterial color={color} emissive={color} emissiveIntensity={isHighlighted ? 0.7 : 0.2} roughness={0.4} />\r\n </mesh>\r\n <mesh position={[0.4, 1.0, 0]}>\r\n <coneGeometry args={[0.08, 0.2, 6, 8]} />\r\n <meshStandardMaterial color={color} emissive={color} emissiveIntensity={isHighlighted ? 0.7 : 0.2} roughness={0.4} />\r\n </mesh>\r\n </group>\r\n )\r\n }\r\n\r\n const dir = new THREE.Vector3().subVectors(end, start)\r\n dir.normalize()\r\n\r\n return (\r\n <group>\r\n <StraightEdge start={start} end={end} color={color} isHighlighted={isHighlighted} />\r\n {showArrow && !isBidirectional && (\r\n <ArrowCone\r\n position={end.clone().addScaledVector(dir, -0.66)}\r\n direction={dir}\r\n color={color}\r\n isHighlighted={isHighlighted}\r\n />\r\n )}\r\n </group>\r\n )\r\n})\r\n\r\nconst NOOP_SELECT = () => {}\r\n\r\nexport interface Cayley3DSceneProps {\r\n /** 群;null → .view-empty 占位 */\r\n group: Group | null\r\n /** 选中元素集合(调用方自持会话态) */\r\n selectedElements: Set<string>\r\n /** 节点点击选中回调;缺省 no-op */\r\n onSelectElement?: (id: string, additive: boolean) => void\r\n /** 作用边元素集合;缺省 = 群生成元(normalizeCayleyActions 归一化) */\r\n actions?: CayleyActionParam[]\r\n /** 边的乘法方向;缺省 'right' */\r\n multiplyType?: MultiplyType\r\n /** 3D 布局形状;缺省 getDefaultLayout3D(group) */\r\n layout3D?: Layout3D\r\n /** 节点球缩放 0.5–2.0;缺省 1 */\r\n nodeScale?: number\r\n /** 自动旋转;缺省 false。prop 优先,未设置时内部 ▶ 按钮本地态兜底 */\r\n autoRotate?: boolean\r\n /** 是否显示 hover/选中 Html 标签;缺省 true */\r\n showLabels?: boolean\r\n /** 锁定相机交互(轨道拖拽/滚轮缩放/右键平移);保留点击选中与双击复位 */\r\n locked?: boolean\r\n /** 子集高亮(元素 id → 颜色);context subsets 的同构映射 */\r\n subsetHighlights?: { elementIds: string[]; color: string }[]\r\n /** 渲染主题(canvas 背景 / label 阴影)。缺省回落到 ThemeContext(无 Provider 时 'dark');\r\n * 主应用壳不传即保持现状(读全局主题),包消费端显式传以与容器主题解耦 */\r\n theme?: 'dark' | 'light'\r\n /** 子群陪集面填充(面 = 某真子群单个陪集在布局中占满的平面凸多边形)。\r\n * 作者在 ⚙ 面板选择子群 H 后,几何上成面的陪集以半透明多边形显示,可逐面指定颜色 */\r\n faceFill?: Cayley3DFaceFillParams\r\n}\r\n\r\nfunction Cayley3DSceneBody({\r\n group,\r\n selectedElements,\r\n onSelectElement,\r\n actions: actionsProp,\r\n multiplyType: multiplyTypeProp,\r\n layout3D: layout3DProp,\r\n nodeScale: nodeScaleProp,\r\n autoRotate: autoRotateProp,\r\n showLabels: showLabelsProp,\r\n locked = false,\r\n subsetHighlights = [],\r\n theme = 'dark',\r\n faceFill,\r\n}: Cayley3DSceneProps & { group: Group }) {\r\n const { t } = useTranslation()\r\n const { gl, camera, scene } = useThree()\r\n\r\n const actions = useMemo(() => normalizeCayleyActions(group, actionsProp), [group, actionsProp])\r\n const multiplyType = multiplyTypeProp ?? 'right'\r\n const layout3D = layout3DProp ?? getDefaultLayout3D(group)\r\n const nodeScale = nodeScaleProp ?? 1\r\n const showLabels = showLabelsProp !== false\r\n const selectElement = onSelectElement ?? NOOP_SELECT\r\n\r\n const [autoRotateState, setAutoRotateState] = useState(false)\r\n const autoRotate = autoRotateProp ?? autoRotateState\r\n const [hoverElement, setHoverElement] = useState<GroupElement | null>(null)\r\n\r\n // 自定义轨道状态(替代 drei OrbitControls):theta/phi 球坐标,phi 无界(可无限翻越上下极点,无 makeSafe 钳制)\r\n const orbit = useRef({\r\n theta: 0,\r\n phi: Math.acos(3 / Math.sqrt(3 ** 2 + 12 ** 2)),\r\n radius: Math.sqrt(3 ** 2 + 12 ** 2),\r\n target: new THREE.Vector3(0, 0, 0),\r\n initialized: false,\r\n })\r\n // 最近一次鼠标拖拽向量:自动旋转时按此方向持续旋转(而非固定方向)\r\n const dragVec = useRef({ x: 0, y: 0 })\r\n const dragState = useRef({ active: false, lastX: 0, lastY: 0, x: 0, y: 0, button: 0 })\r\n // GIF 导出期间的角度驱动:beginRotation 记录基准角并创建独立离屏渲染器/相机,\r\n // frameAt 按帧索引精确求角并渲染到离屏 canvas(每帧角度 = 基准 + radPerSec × 帧延时 × 帧序号,\r\n // 与实时渲染耗时无关);实时轨道/相机全程不被触碰,展示区照常旋转\r\n const externalRotation = useRef<{\r\n active: boolean\r\n radPerSec: number\r\n baseTheta: number\r\n basePhi: number\r\n radius: number\r\n target: THREE.Vector3\r\n renderer: THREE.WebGLRenderer | null\r\n ecam: THREE.PerspectiveCamera | null\r\n }>({\r\n active: false, radPerSec: 0, baseTheta: 0, basePhi: 0, radius: 1,\r\n target: new THREE.Vector3(), renderer: null, ecam: null,\r\n })\r\n\r\n // 展示区自动旋转角速度(与 ▶ 自动旋转同一公式;拖拽后按拖拽向量长度降速):\r\n // GIF 导出用同一值,保证导出动图与展示区转速一致\r\n const displayAngVel = useCallback(() => {\r\n const d = dragVec.current\r\n const len = Math.hypot(d.x, d.y)\r\n return (len >= 8 ? 0.35 + Math.min(0.65, len / 360) : 1) * 2 * Math.PI\r\n }, [])\r\n\r\n const isLargeGroup = group.order > 100\r\n const visibleElementIds = useMemo(() => {\r\n if (!isLargeGroup) return new Set(group.elements.map(e => e.id))\r\n const ids = new Set<string>([group.identity.id])\r\n for (const a of actions.filter(x => x.enabled).slice(0, 4)) ids.add(a.elementId)\r\n for (const id of selectedElements) ids.add(id)\r\n for (let i = 0; i < group.elements.length; i += Math.max(1, Math.ceil(group.order / 24))) {\r\n ids.add(group.elements[i].id)\r\n }\r\n return ids\r\n }, [group, actions, selectedElements, isLargeGroup])\r\n\r\n const cayleyEdges = useMemo(() => {\r\n return computeCayleyActionEdges(group, actions, multiplyType)\r\n }, [group, actions, multiplyType])\r\n\r\n const positions = useMemo(() => {\r\n return compute3DPositions(group, layout3D).map(\r\n p => new THREE.Vector3(p[0], p[1], p[2])\r\n )\r\n }, [group, layout3D])\r\n\r\n // 外接球:节点云质心为球心,最大距离为半径(含节点球/自环余量),复位与初始视角均基于它\r\n const bounds = useMemo(() => {\r\n const center = new THREE.Vector3(0, 0, 0)\r\n if (positions.length === 0) return { center, radius: 3 }\r\n for (const p of positions) center.add(p)\r\n center.divideScalar(positions.length)\r\n let r = 0\r\n for (const p of positions) r = Math.max(r, p.distanceTo(center))\r\n return { center, radius: r + 1.4 }\r\n }, [positions])\r\n\r\n // 默认视角(复位目标):外接球直径 ≈ 视口高度 2/3(d = 1.5R/tan(fov/2)),相机远在球外(d ≈ 3.2R > R)。\r\n // minRadius = 球外(视角不可进入外接球);maxRadius = 适配距离 3 倍\r\n const fitOrbit = useMemo(() => {\r\n const halfFov = ((camera as THREE.PerspectiveCamera).fov * Math.PI) / 360\r\n const dist = (bounds.radius * 1.5) / Math.tan(halfFov)\r\n return {\r\n theta: 0,\r\n phi: Math.acos(3 / Math.sqrt(3 ** 2 + 12 ** 2)),\r\n radius: dist,\r\n minRadius: Math.max(1.5, bounds.radius + 0.8),\r\n maxRadius: Math.max(30, dist * 3),\r\n target: bounds.center.clone(),\r\n }\r\n }, [bounds, camera])\r\n\r\n // latestFit 在每次渲染后同步,供复位与切群/切形状自动回正使用(避免 fitOrbit 对象身份波动触发)\r\n const latestFit = useRef(fitOrbit)\r\n useEffect(() => {\r\n latestFit.current = fitOrbit\r\n })\r\n const groupKey = `${group.symbol}|${group.order}`\r\n\r\n const resetCamera = useCallback(() => {\r\n const o = orbit.current\r\n const fit = latestFit.current\r\n o.theta = fit.theta\r\n o.phi = fit.phi\r\n o.radius = fit.radius\r\n o.target.copy(fit.target)\r\n }, [])\r\n\r\n // 切换群或切换 3D 形状时自动回到默认适配视角\r\n useEffect(() => {\r\n resetCamera()\r\n }, [groupKey, layout3D, resetCamera])\r\n\r\n useEffect(() => {\r\n if (locked) return\r\n const el = gl.domElement\r\n const onDown = (e: PointerEvent) => {\r\n dragState.current = { active: true, lastX: e.clientX, lastY: e.clientY, x: 0, y: 0, button: e.button }\r\n el.setPointerCapture?.(e.pointerId)\r\n }\r\n const onMove = (e: PointerEvent) => {\r\n const s = dragState.current\r\n if (!s.active) return\r\n const dx = e.clientX - s.lastX\r\n const dy = e.clientY - s.lastY\r\n s.lastX = e.clientX\r\n s.lastY = e.clientY\r\n s.x += dx\r\n s.y += dy\r\n const o = orbit.current\r\n if (s.button === 2) {\r\n // 右键平移 target:沿相机局部 right/up 平面移动,尺度随 radius\r\n const right = new THREE.Vector3().setFromMatrixColumn(camera.matrix, 0)\r\n const up = new THREE.Vector3().setFromMatrixColumn(camera.matrix, 1)\r\n o.target.addScaledVector(right, -dx * o.radius * 0.0012).addScaledVector(up, dy * o.radius * 0.0012)\r\n } else {\r\n // 左键旋转:与 OrbitControls 同约定(拖右 theta -=;拖下 phi -=),phi 无界可翻越极点\r\n o.theta -= dx * 0.006\r\n o.phi -= dy * 0.006\r\n }\r\n }\r\n const onUp = (e: PointerEvent) => {\r\n const s = dragState.current\r\n s.active = false\r\n if (Math.hypot(s.x, s.y) >= 8) dragVec.current = { x: s.x, y: s.y }\r\n el.releasePointerCapture?.(e.pointerId)\r\n }\r\n const onWheel = (e: WheelEvent) => {\r\n e.preventDefault()\r\n const o = orbit.current\r\n o.radius = Math.min(fitOrbit.maxRadius, Math.max(fitOrbit.minRadius, o.radius * Math.pow(0.95, -e.deltaY / 100)))\r\n }\r\n el.addEventListener('pointerdown', onDown)\r\n el.addEventListener('pointermove', onMove)\r\n el.addEventListener('pointerup', onUp)\r\n el.addEventListener('pointercancel', onUp)\r\n el.addEventListener('wheel', onWheel, { passive: false })\r\n return () => {\r\n el.removeEventListener('pointerdown', onDown)\r\n el.removeEventListener('pointermove', onMove)\r\n el.removeEventListener('pointerup', onUp)\r\n el.removeEventListener('pointercancel', onUp)\r\n el.removeEventListener('wheel', onWheel)\r\n }\r\n }, [gl, camera, fitOrbit, locked])\r\n\r\n // 按最后一次拖拽方向将角速度分解到 theta/phi 两个分量(与手动拖拽同约定:拖右 theta -=,拖下 phi -=),\r\n // 未拖拽过则默认绕竖轴(theta)旋转;拖拽含竖直分量时同步带动俯仰旋转——与 ▶ 自动旋转方向完全一致\r\n const applyOrbitRotation = (\r\n o: { theta: number; phi: number },\r\n angVel: number,\r\n delta: number,\r\n ) => {\r\n const d = dragVec.current\r\n const len = Math.hypot(d.x, d.y)\r\n if (len >= 8) {\r\n o.theta -= (d.x / len) * angVel * delta\r\n o.phi -= (d.y / len) * angVel * delta\r\n } else {\r\n o.theta -= angVel * delta\r\n }\r\n }\r\n\r\n // 由球坐标轨道写入相机(位置/up 极点翻转/lookAt):帧循环与 GIF 导出 frameAt 共用,保证画面与 GIF 帧一致\r\n const applyCameraFromOrbit = useCallback((o: { theta: number; phi: number; radius: number; target: THREE.Vector3 }) => {\r\n const sinP = Math.sin(o.phi)\r\n camera.position.set(\r\n o.target.x + o.radius * sinP * Math.sin(o.theta),\r\n o.target.y + o.radius * Math.cos(o.phi),\r\n o.target.z + o.radius * sinP * Math.cos(o.theta)\r\n )\r\n // 越过上下任一极点(sinφ 变号)时翻转 up,保持画面正立连续\r\n camera.up.set(0, sinP >= 0 ? 1 : -1, 0)\r\n camera.lookAt(o.target)\r\n }, [camera])\r\n\r\n // 每帧:手动拖拽的 theta/phi 已在 pointer 处理中直接更新;此处应用自动旋转增量并同步相机。\r\n // 球坐标 phi 无界(可无限翻越上下极点);GIF 导出期间角度由 frameAt 精确驱动,此处仅同步相机\r\n useFrame((_, delta) => {\r\n const o = orbit.current\r\n if (!o.initialized) {\r\n // 初始视角 = 复位适配视角(外接球居中、直径占视口高度 2/3、相机在球外)\r\n o.theta = fitOrbit.theta\r\n o.phi = fitOrbit.phi\r\n o.radius = fitOrbit.radius\r\n o.target.copy(fitOrbit.target)\r\n o.initialized = true\r\n }\r\n if (autoRotate) {\r\n // GIF 导出期间实时循环不受影响:导出相机独立离屏渲染,展示区照常按此速度旋转\r\n applyOrbitRotation(o, displayAngVel(), delta)\r\n }\r\n applyCameraFromOrbit(o)\r\n })\r\n\r\n useEffect(() => {\r\n const el = gl.domElement\r\n const onDoubleClick = () => resetCamera()\r\n el.addEventListener('dblclick', onDoubleClick)\r\n return () => el.removeEventListener('dblclick', onDoubleClick)\r\n }, [gl, resetCamera])\r\n\r\n // 仅主视口(.canvas-viewport 内)的 3D 实例注册到导出桥;浮动窗口实例不注册,避免覆盖\r\n useEffect(() => {\r\n if (!gl.domElement.closest('.canvas-viewport')) return\r\n const api: Cayley3DControlAPI = {\r\n isReady: () => true,\r\n snapshotOrbit: () => {\r\n const o = orbit.current\r\n return { theta: o.theta, phi: o.phi, radius: o.radius, target: o.target.clone() }\r\n },\r\n displayAngVel: () => displayAngVel(),\r\n beginRotation: (radPerSec) => {\r\n // 记录基准角/半径/目标,并创建独立离屏渲染器 + 相机(与实时轨道/相机完全隔离,\r\n // 导出期间展示区照常旋转;offline renderer 的 drawing buffer 与主视口同尺寸)\r\n const o = orbit.current\r\n const renderer = new THREE.WebGLRenderer({ antialias: false, preserveDrawingBuffer: true })\r\n renderer.setSize(gl.domElement.width, gl.domElement.height, false)\r\n const ecam = new THREE.PerspectiveCamera(\r\n (camera as THREE.PerspectiveCamera).fov,\r\n (camera as THREE.PerspectiveCamera).aspect,\r\n camera.near,\r\n camera.far\r\n )\r\n externalRotation.current = {\r\n active: true, radPerSec,\r\n baseTheta: o.theta, basePhi: o.phi,\r\n radius: o.radius, target: o.target.clone(),\r\n renderer, ecam,\r\n }\r\n // 预热渲染一次(编译离屏 GL 着色器并建立绘制流水线),首帧角度与 frameAt(0) 一致\r\n const sinP0 = Math.sin(o.phi)\r\n ecam.position.set(\r\n o.target.x + o.radius * sinP0 * Math.sin(o.theta),\r\n o.target.y + o.radius * Math.cos(o.phi),\r\n o.target.z + o.radius * sinP0 * Math.cos(o.theta)\r\n )\r\n ecam.up.set(0, sinP0 >= 0 ? 1 : -1, 0)\r\n ecam.lookAt(o.target)\r\n renderer.render(scene, ecam)\r\n },\r\n // GIF 导出的第 index 帧:按帧序号与帧延时精确计算角度(与实时渲染耗时无关,\r\n // 方向沿用最后一次拖拽分解),渲染到离屏 canvas 并返回供导出循环采集\r\n frameAt: (index, frameDelayMs) => {\r\n const e = externalRotation.current\r\n if (!e.active || !e.renderer || !e.ecam) return null\r\n const total = (e.radPerSec * index * frameDelayMs) / 1000\r\n const d = dragVec.current\r\n const len = Math.hypot(d.x, d.y)\r\n let theta: number\r\n let phi: number\r\n if (len >= 8) {\r\n theta = e.baseTheta - (d.x / len) * total\r\n phi = e.basePhi - (d.y / len) * total\r\n } else {\r\n theta = e.baseTheta - total\r\n phi = e.basePhi\r\n }\r\n const sinP = Math.sin(phi)\r\n e.ecam.position.set(\r\n e.target.x + e.radius * sinP * Math.sin(theta),\r\n e.target.y + e.radius * Math.cos(phi),\r\n e.target.z + e.radius * sinP * Math.cos(theta)\r\n )\r\n e.ecam.up.set(0, sinP >= 0 ? 1 : -1, 0)\r\n e.ecam.lookAt(e.target)\r\n e.renderer.render(scene, e.ecam)\r\n return e.renderer.domElement\r\n },\r\n endRotation: () => {\r\n // 实时轨道/相机全程未被触碰,无需恢复;仅释放离屏渲染器\r\n const e = externalRotation.current\r\n e.active = false\r\n e.renderer?.dispose()\r\n e.renderer = null\r\n e.ecam = null\r\n },\r\n }\r\n registerCayley3DControls(api)\r\n return () => unregisterCayley3DControls(api)\r\n }, [gl, scene, camera, displayAngVel])\r\n\r\n const elementLookup = useMemo(() => {\r\n const m = new Map<string, GroupElement>()\r\n for (const el of group.elements) m.set(el.id, el)\r\n return m\r\n }, [group])\r\n\r\n const faceOpacity = faceFill?.enabled === false ? 0 : (faceFill?.opacity ?? 0.45)\r\n // 子群陪集面:几何上成面的陪集 → 半透明凸多边形 mesh(fan 三角化,双面渲染)\r\n const faceMeshes = useMemo(() => {\r\n const subgroup = faceFill?.subgroup\r\n if (faceOpacity <= 0 || !subgroup || subgroup.length === 0) return []\r\n const edgeKeys = buildUndirectedEdgeKeys(cayleyEdges.map(e => [e.fromIdx, e.toIdx] as [number, number]))\r\n const faces = subgroupFaces(\r\n group,\r\n subgroup,\r\n positions.map(v => [v.x, v.y, v.z] as [number, number, number]),\r\n edgeKeys,\r\n )\r\n if (!faces || faces.length === 0) return []\r\n const idxOf = new Map(group.elements.map((e, i) => [e.id, i]))\r\n return faces.map((f, i) => {\r\n const pts = f.hullElementIds.map(id => positions[idxOf.get(id)!])\r\n const c = new THREE.Vector3(0, 0, 0)\r\n for (const p of pts) c.add(p)\r\n c.divideScalar(pts.length)\r\n const arr: number[] = []\r\n for (let k = 0; k < pts.length; k++) {\r\n const p0 = pts[k]\r\n const p1 = pts[(k + 1) % pts.length]\r\n arr.push(c.x, c.y, c.z, p0.x, p0.y, p0.z, p1.x, p1.y, p1.z)\r\n }\r\n const geo = new THREE.BufferGeometry()\r\n geo.setAttribute('position', new THREE.Float32BufferAttribute(arr, 3))\r\n geo.computeVertexNormals()\r\n const color = faceFill?.faceColors?.[f.key] ?? FACE_COLOR_PALETTE[i % FACE_COLOR_PALETTE.length]\r\n return { key: f.key, geometry: geo, color }\r\n })\r\n }, [group, faceFill, cayleyEdges, positions, faceOpacity])\r\n\r\n useEffect(() => {\r\n return () => {\r\n for (const fm of faceMeshes) fm.geometry.dispose()\r\n }\r\n }, [faceMeshes])\r\n\r\n const actionLabelMap = useMemo(() => {\r\n const m = new Map<string, string>()\r\n for (const a of actions) {\r\n const el = elementLookup.get(a.elementId)\r\n if (el) m.set(a.elementId, el.label)\r\n }\r\n return m\r\n }, [actions, elementLookup])\r\n\r\n const subsetOf = useMemo(() => {\r\n const m = new Map<string, { color: string }>()\r\n for (const s of subsetHighlights) {\r\n for (const id of s.elementIds) {\r\n if (!m.has(id)) m.set(id, s)\r\n }\r\n }\r\n return m\r\n }, [subsetHighlights])\r\n\r\n const edgeDataMap = useMemo(() => {\r\n const m = new Map<string, EdgeData>()\r\n const edgeBudget = isLargeGroup ? Math.max(60, group.order * 2) : Number.POSITIVE_INFINITY\r\n for (const edge of cayleyEdges) {\r\n if (isLargeGroup && !visibleElementIds.has(edge.fromId) && !visibleElementIds.has(edge.toId)) continue\r\n const key = `${Math.min(edge.fromIdx, edge.toIdx)}|${Math.max(edge.fromIdx, edge.toIdx)}|${edge.actionElementId}`\r\n if (!m.has(key)) {\r\n m.set(key, {\r\n fromIdx: edge.fromIdx,\r\n toIdx: edge.toIdx,\r\n fromId: edge.fromId,\r\n toId: edge.toId,\r\n fromPos: positions[edge.fromIdx],\r\n toPos: positions[edge.toIdx],\r\n gen: {\r\n name: edge.actionElementId,\r\n symbol: elementLookup.get(edge.actionElementId)?.label || '',\r\n color: edge.color,\r\n apply: () => group.elements[0],\r\n inverse: {} as Generator\r\n },\r\n isSelfLoop: edge.isSelfLoop,\r\n isBidirectional: edge.isBidirectional,\r\n })\r\n }\r\n if (m.size >= edgeBudget) break\r\n }\r\n return m\r\n }, [cayleyEdges, positions, group, isLargeGroup, visibleElementIds, elementLookup])\r\n\r\n return (\r\n <>\r\n <ambientLight intensity={0.3} />\r\n <directionalLight position={[10, 15, 10]} intensity={0.8} color=\"#ffffff\" />\r\n <directionalLight position={[-10, -5, -10]} intensity={0.3} color=\"#4488ff\" />\r\n <pointLight position={[0, 0, 0]} intensity={0.3} color=\"#ffffff\" />\r\n\r\n <Html fullscreen position={[0, 0, 0]} style={{ pointerEvents: 'none' }} wrapperClass=\"gv-html-fullscreen\">\r\n <div style={{\r\n position: 'absolute', top: 10, right: 10,\r\n display: 'flex', gap: 6, alignItems: 'center', pointerEvents: 'auto'\r\n }}>\r\n <div style={{\r\n background: 'var(--bg-tooltip)', color: 'var(--text-secondary)',\r\n padding: '6px 12px', borderRadius: 8, fontSize: 13,\r\n fontFamily: 'monospace', pointerEvents: 'none'\r\n }}>\r\n <span style={{ fontWeight: 'bold' }} dangerouslySetInnerHTML={{ __html: renderTex(texify(group.symbol)) }} />\r\n <span style={{ marginLeft: 8, color: 'var(--text-muted)' }}>|G| = {group.order}</span>\r\n </div>\r\n <button\r\n onClick={() => setAutoRotateState(v => !v)}\r\n title={t('cayley3d.autoRotate')}\r\n aria-label={t('cayley3d.autoRotate')}\r\n style={{\r\n background: 'var(--bg-tooltip)',\r\n color: autoRotate ? 'var(--accent-teal)' : 'var(--text-secondary)',\r\n border: autoRotate ? '1px solid var(--accent-teal)' : '1px solid var(--border-primary)',\r\n borderRadius: 8, padding: '6px 10px', fontSize: 13,\r\n cursor: 'pointer', fontFamily: 'monospace'\r\n }}\r\n >\r\n {autoRotate ? '❚❚' : '▶'}\r\n </button>\r\n <button\r\n onClick={resetCamera}\r\n title={t('cayley3d.resetView')}\r\n aria-label={t('cayley3d.resetView')}\r\n style={{\r\n background: 'var(--bg-tooltip)', color: 'var(--text-secondary)',\r\n border: '1px solid var(--border-primary)', borderRadius: 8, padding: '6px 10px',\r\n fontSize: 13, cursor: 'pointer', fontFamily: 'monospace'\r\n }}\r\n >\r\n ⟲\r\n </button>\r\n </div>\r\n </Html>\r\n\r\n {actions.length > 0 && (\r\n <Html fullscreen position={[0, 0, 0]} style={{ pointerEvents: 'none' }} wrapperClass=\"gv-html-fullscreen\">\r\n <div style={{\r\n position: 'absolute', top: 10, left: 10,\r\n background: 'var(--bg-tooltip)', color: 'var(--text-secondary)',\r\n padding: '8px 14px', borderRadius: 8, fontSize: 13,\r\n fontFamily: 'monospace', pointerEvents: 'none'\r\n }}>\r\n <div style={{ fontWeight: 'bold', marginBottom: 4 }}>\r\n {multiplyType === 'right' ? t('cayley3d.multiplyRight') : t('cayley3d.multiplyLeft')}\r\n </div>\r\n {actions.filter(a => a.enabled).map(action => {\r\n const label = actionLabelMap.get(action.elementId) || action.elementId\r\n return (\r\n <div key={action.elementId} style={{ display: 'flex', alignItems: 'center', gap: 6, marginTop: 2 }}>\r\n <span style={{ display: 'inline-block', width: 12, height: 3, background: action.color, borderRadius: 2 }} />\r\n <span dangerouslySetInnerHTML={{ __html: renderTex(texify(label)) }} />\r\n </div>\r\n )\r\n })}\r\n </div>\r\n </Html>\r\n )}\r\n\r\n {faceMeshes.map(fm => (\r\n <mesh key={fm.key} geometry={fm.geometry} renderOrder={-2}>\r\n <meshBasicMaterial color={fm.color} transparent opacity={faceOpacity} side={THREE.DoubleSide} depthWrite={false} />\r\n </mesh>\r\n ))}\r\n\r\n {Array.from(edgeDataMap.values()).map((edge) => {\r\n const fromEl = elementLookup.get(edge.fromId)\r\n const toEl = elementLookup.get(edge.toId)\r\n if (!fromEl || !toEl) return null\r\n const isHighlighted = (\r\n selectedElements.has(fromEl.id) ||\r\n selectedElements.has(toEl.id)\r\n )\r\n return (\r\n <EdgeLine\r\n key={`edge-${edge.fromIdx}-${edge.toIdx}`}\r\n start={edge.fromPos}\r\n end={edge.toPos}\r\n color={edge.gen.color}\r\n isHighlighted={isHighlighted}\r\n isSelfLoop={edge.isSelfLoop}\r\n isBidirectional={edge.isBidirectional}\r\n showArrow={!isLargeGroup}\r\n />\r\n )\r\n })}\r\n\r\n {positions.map((pos, i) => {\r\n const el = group.elements[i]\r\n if (isLargeGroup && !visibleElementIds.has(el.id)) return null\r\n const isSelected = selectedElements.has(el.id)\r\n const parentSubset = subsetOf.get(el.id)\r\n return (\r\n <NodeSphere\r\n key={el.id}\r\n position={pos}\r\n label={el.label}\r\n color={getElementColor(i, group.order, group.isAbelian)}\r\n isSelected={isSelected}\r\n isHovered={hoverElement?.id === el.id}\r\n subsetColor={parentSubset ? parentSubset.color : null}\r\n element={el}\r\n nodeScale={nodeScale}\r\n showLabel={showLabels}\r\n isDark={theme === 'dark'}\r\n onSelectElement={selectElement}\r\n onPointerEnter={setHoverElement}\r\n onPointerLeave={setHoverElement}\r\n />\r\n )\r\n })}\r\n\r\n </>\r\n )\r\n}\r\n\r\n/** 受控 3D 凯莱图(props 驱动;ViewWindow 与测试用)。空群渲染占位,非空渲染 R3F 场景。 */\r\nexport function Cayley3DScene(props: Cayley3DSceneProps) {\r\n const { group, theme: themeProp } = props\r\n const { t } = useTranslation()\r\n const { theme: ctxTheme } = useTheme()\r\n const theme = themeProp ?? ctxTheme\r\n\r\n if (!group) {\r\n return (\r\n <div className=\"view-empty\">\r\n <p>{t('canvas.noGroup')}</p>\r\n </div>\r\n )\r\n }\r\n\r\n const bgColor = theme === 'dark' ? '#0a0a1a' : '#f4f4f7'\r\n\r\n return (\r\n <div style={{ width: '100%', height: '100%', background: bgColor }}>\r\n <Canvas\r\n camera={{ position: [0, 3, 12], fov: 50, near: 0.1, far: 400 }}\r\n gl={{ antialias: true, alpha: false, preserveDrawingBuffer: true }}\r\n style={{ width: '100%', height: '100%' }}\r\n >\r\n <color attach=\"background\" args={[bgColor]} />\r\n <Cayley3DSceneBody {...props} group={group} theme={theme} />\r\n </Canvas>\r\n </div>\r\n )\r\n}\r\n\r\n/** 主应用入口(context 组装壳):从全局 Provider 组装 Cayley3DScene 所需 props(保留原行为) */","import { useLayoutEffect, useMemo, useRef, useState, type ReactNode } from 'react'\r\nimport { useTranslation } from '../../i18n/useTranslation'\r\nimport { useTheme } from '../../theme/useTheme'\r\nimport {\r\n computeSubgroupLattice,\r\n mergeLatticeByConjugacy,\r\n subgroupSetKey,\r\n subgroupStructureSymbol,\r\n getGroupCenter,\r\n type SubgroupLatticeNode,\r\n type SubgroupLatticeEdge,\r\n} from '../../core/algebra/subgroups'\r\nimport {\r\n computeLatticeLayout,\r\n latticeLodTier,\r\n latticeSlotScreenSize,\r\n latticeFitScale,\r\n} from '../../core/algebra/latticeLayout'\r\nimport { texify, renderTex } from '../../utils/texify'\r\nimport { factorizeOrder } from '../../core/algebra/sylow'\r\nimport type { SeriesType, SeriesFactor } from '../../core/algebra/series'\r\nimport type {\r\n CanvasTransform,\r\n Group,\r\n GroupElement,\r\n LatticeLabelDetail,\r\n LatticeLodTier,\r\n Subset,\r\n} from '../../core/types'\r\n\r\nconst SERIES_COLORS: Record<SeriesType, { light: string; dark: string }> = {\r\n derived: { light: '#b8860b', dark: '#ffd93d' },\r\n upperCentral: { light: '#0e7490', dark: '#22d3ee' },\r\n lowerCentral: { light: '#0e7490', dark: '#22d3ee' },\r\n composition: { light: '#7c3aed', dark: '#c084fc' },\r\n}\r\n\r\n/** compact 档胶囊 / dots 档圆点的期望屏幕尺寸(px,被槽位尺寸封顶故永不重叠) */\r\nconst COMPACT_PILL = { w: 104, h: 28, font: 13 }\r\nconst DOT_R = 8\r\nconst ORBIT_FONT = 11\r\n\r\n/** 屏幕恒定 px → 世界单位(受 cap 封顶,cap 用世界单位表示) */\r\nfunction toWorld(screenPx: number, eff: number, cap: number): number {\r\n return Math.min(screenPx / Math.max(eff, 1e-4), cap)\r\n}\r\n\r\n/** 轨道格节点上携带的附加字段(未合并时都不存在) */\r\ninterface OrbitFields {\r\n orbitSize?: number\r\n normalizerOrder?: number\r\n}\r\n\r\nexport interface LatticeData {\r\n nodes: SubgroupLatticeNode[]\r\n edges: SubgroupLatticeEdge[]\r\n}\r\n\r\n/** 子群列(Series)状态:由宿主组装后传入,内核只负责高亮与面板呈现 */\r\nexport interface SublatticeSeriesState {\r\n type: SeriesType\r\n /** 系列项的元素集合;null 表示后端仍在计算 / 超过守卫 */\r\n terms: GroupElement[][] | null\r\n factors?: SeriesFactor[] | null\r\n solvable?: boolean\r\n nilpotent?: boolean\r\n chainCount?: number\r\n truncated?: boolean\r\n loading?: boolean\r\n}\r\n\r\nexport interface SublatticeSceneProps {\r\n group: Group | null\r\n /** 外部提供则优先(大群后端通路);缺省内核对 order ≤ 60 自行枚举 */\r\n lattice?: LatticeData | null\r\n canvasTransform?: CanvasTransform\r\n /** 宿主可用像素尺寸;缺省由 ResizeObserver 实测自身容器 */\r\n availableSize?: { width: number; height: number }\r\n /** 名片细节档,缺省 'auto'(按槽位屏幕宽度自动降级) */\r\n labelDetail?: LatticeLabelDetail\r\n /** 共轭子群合并为轨道节点,缺省 false */\r\n mergeConjugates?: boolean\r\n /** 名片与层距的世界单位乘子,缺省 1 */\r\n nodeScale?: number\r\n /** 底部子群列面板,缺省 true */\r\n showSeriesPanel?: boolean\r\n series?: SublatticeSeriesState | null\r\n /** 群中心元素 id 列表(宿主已算好时传入,省一次本地计算) */\r\n centerIds?: string[]\r\n subsets?: Subset[]\r\n activeNodeIdx?: number | null\r\n onActivateNode?: (idx: number | null, node: SubgroupLatticeNode | null) => void\r\n noGroupText?: string\r\n /** 渲染主题(格取色 palette)。缺省回落到 ThemeContext(无 Provider 时 'dark');\r\n * 主应用壳不传即保持现状(读全局主题),包消费端显式传以与容器主题解耦 */\r\n theme?: 'dark' | 'light'\r\n /** 本地枚举子群格的群阶上限(`order > 该值` 且未显式传 `lattice` 时不枚举、渲染空态);\r\n * 缺省 60(与 `findAllSubgroups` 内建守卫一致)。放开需自行确认性能与后端通路 */\r\n maxEnumerateOrder?: number\r\n}\r\n\r\nfunction buildPalette(theme: string) {\r\n if (theme === 'light') {\r\n return {\r\n edge: '#a9adbc',\r\n edgeOpacity: 0.95,\r\n edgeWidth: 2.5,\r\n pathEdge: '#d4a017',\r\n pathEdgeWidth: 4,\r\n nodeFill: '#eef1f5',\r\n nodeStroke: '#2d8f85',\r\n nodeStrokeNormal: '#7c5cc0',\r\n nodeText: '#1c1c28',\r\n nodeSubText: '#5a5a6a',\r\n pathFill: '#fbf1d0',\r\n pathStroke: '#d4a017',\r\n pathText: '#7a5d00',\r\n pathSubText: '#8a6d00cc',\r\n activeFill: '#d8ecda',\r\n trivialFill: '#e8e8f1',\r\n trivialStroke: '#9a9ab0',\r\n fullFill: '#e7edf7',\r\n fullStroke: '#3a6fb0',\r\n centerFill: '#fdf3c7',\r\n centerStroke: '#b8860b',\r\n sylowText: '#c2410c',\r\n dotPlain: '#8d93a8',\r\n seriesBadgeText: '#fff',\r\n }\r\n }\r\n return {\r\n edge: '#4a4a7a',\r\n edgeOpacity: 0.85,\r\n edgeWidth: 2.5,\r\n pathEdge: '#ffd93d',\r\n pathEdgeWidth: 4,\r\n nodeFill: '#151f1a',\r\n nodeStroke: '#3ea89e',\r\n nodeStrokeNormal: '#8968c8',\r\n nodeText: '#ddd',\r\n nodeSubText: '#777',\r\n pathFill: '#1e3a1e',\r\n pathStroke: '#ffd93d',\r\n pathText: '#ffd93d',\r\n pathSubText: '#ffd93dcc',\r\n activeFill: '#2a4a2a',\r\n trivialFill: '#1a1a2e',\r\n trivialStroke: '#555',\r\n fullFill: '#1a1f30',\r\n fullStroke: '#5588cc',\r\n centerFill: '#3a3020',\r\n centerStroke: '#ffd93d',\r\n sylowText: '#fb923c',\r\n dotPlain: '#6b7280',\r\n seriesBadgeText: '#111',\r\n }\r\n}\r\n\r\n/** 邻接表(无向)——只建一次,路径搜索不再每 pop 扫全边表 */\r\nfunction buildAdjacency(nodeCount: number, edges: SubgroupLatticeEdge[]): number[][] {\r\n const adj: number[][] = Array.from({ length: nodeCount }, () => [])\r\n for (const e of edges) {\r\n if (e.from >= 0 && e.from < nodeCount && e.to >= 0 && e.to < nodeCount) {\r\n adj[e.from].push(e.to)\r\n adj[e.to].push(e.from)\r\n }\r\n }\r\n return adj\r\n}\r\n\r\nfunction findPath(adjacency: number[][], start: number, end: number): number[] | null {\r\n if (start === end) return [start]\r\n const visited = new Set<number>()\r\n const queue: number[][] = [[start]]\r\n while (queue.length > 0) {\r\n const path = queue.shift()!\r\n const last = path[path.length - 1]\r\n if (last === end) return path\r\n if (visited.has(last)) continue\r\n visited.add(last)\r\n for (const nb of adjacency[last] ?? []) {\r\n if (!visited.has(nb)) queue.push([...path, nb])\r\n }\r\n }\r\n return null\r\n}\r\n\r\n// ────────────────────────── Series 面板(纯呈现) ──────────────────────────\r\n\r\ninterface SeriesPanelProps {\r\n group: Group\r\n series: SublatticeSeriesState\r\n color: string | null\r\n /** 渲染主题(徽标深浅色)。缺省回落到 ThemeContext */\r\n theme?: 'dark' | 'light'\r\n}\r\n\r\n/** 子群列链式展示:N₀ ⊵ N₁ ⊵ … + 各级阶 + 因子 + 可解/幂零徽标(由原视图内联 JSX 迁出) */\r\nexport function SeriesPanel({ group, series, color, theme: themeProp }: SeriesPanelProps) {\r\n const { t } = useTranslation()\r\n const { theme: ctxTheme } = useTheme()\r\n const theme = themeProp ?? ctxTheme\r\n const { type, terms, factors, solvable, nilpotent, chainCount, truncated, loading } = series\r\n\r\n const chainTeX = terms\r\n ? terms.map((term, ti) => {\r\n const label = term.length === 1\r\n ? '\\\\langle e \\\\rangle'\r\n : term.length === group.order\r\n ? texify(group.symbol)\r\n : `N_{${ti}}`\r\n return (ti === 0 ? '' : ' \\\\trianglerighteq ') + label\r\n }).join('')\r\n : ''\r\n const ordersTeX = terms\r\n ? terms.map((term, ti) => `|N_{${ti}}| = ${term.length}`).join(',\\\\;')\r\n : ''\r\n const factorsTeX = factors\r\n ? factors.map((f, i) => `N_{${i}}/N_{${i + 1}} \\\\cong ${f.label}`).join(',\\\\;')\r\n : ''\r\n const multisetText = factors\r\n ? [...factors]\r\n .sort((a, b) => a.order - b.order || a.label.localeCompare(b.label))\r\n .map(f => f.label)\r\n .join(', ')\r\n : ''\r\n\r\n const chipSolvable = theme === 'light' ? '#15803d' : '#4ade80'\r\n const chipNilpotent = theme === 'light' ? '#0369a1' : '#38bdf8'\r\n\r\n return (\r\n <div\r\n className=\"series-panel\"\r\n style={{\r\n borderTop: '1px solid var(--border-primary)',\r\n background: 'var(--bg-panel)',\r\n padding: '8px 12px',\r\n fontSize: 12,\r\n overflowX: 'auto',\r\n flexShrink: 0,\r\n }}\r\n >\r\n {terms ? (\r\n <>\r\n <div style={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: '4px 14px' }}>\r\n <span style={{ fontWeight: 600, color: color ?? undefined }}>{t(`series.${type}`)}</span>\r\n <span dangerouslySetInnerHTML={{ __html: renderTex(chainTeX) }} />\r\n </div>\r\n <div style={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: '4px 14px', marginTop: 3 }}>\r\n <span style={{ color: 'var(--text-muted)' }} dangerouslySetInnerHTML={{ __html: renderTex(ordersTeX) }} />\r\n </div>\r\n {factors && factors.length > 0 && (\r\n <div style={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: '4px 14px', marginTop: 3 }}>\r\n <span dangerouslySetInnerHTML={{ __html: renderTex(factorsTeX) }} />\r\n </div>\r\n )}\r\n <div style={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 8, marginTop: 5 }}>\r\n {solvable && (\r\n <span style={{ border: `1px solid ${chipSolvable}`, color: chipSolvable, borderRadius: 10, padding: '1px 8px', fontSize: 11 }}>{t('series.solvable')}</span>\r\n )}\r\n {nilpotent && (\r\n <span style={{ border: `1px solid ${chipNilpotent}`, color: chipNilpotent, borderRadius: 10, padding: '1px 8px', fontSize: 11 }}>{t('series.nilpotent')}</span>\r\n )}\r\n {type === 'composition' && factors && factors.length > 0 && (\r\n <>\r\n <span style={{ color: 'var(--text-muted)' }}>{t('series.factors')}: {multisetText}</span>\r\n <span style={{ color: 'var(--text-muted)' }}>{t('series.jordanHolder')}</span>\r\n </>\r\n )}\r\n {type === 'composition' && chainCount !== undefined && chainCount > 1 && (\r\n <span style={{ color: 'var(--text-muted)' }}>{t('series.alternativeChains', { n: String(chainCount) })}</span>\r\n )}\r\n {type === 'composition' && truncated && (\r\n <span style={{ color: 'var(--accent-yellow-text)' }}>{t('series.truncated')}</span>\r\n )}\r\n </div>\r\n </>\r\n ) : (\r\n <span style={{ color: 'var(--text-muted)' }}>\r\n {loading ? t('series.loading') : t('series.tooLarge')}\r\n </span>\r\n )}\r\n </div>\r\n )\r\n}\r\n\r\n// ────────────────────────── 受控内核 ──────────────────────────\r\n\r\n/**\r\n * 子群格受控内核(FGVE 阶段 2 批次三)。\r\n *\r\n * 小窗口里的可读性靠三件事:\r\n * 1. 布局世界坐标紧贴内容(`computeLatticeLayout`,无 1000×600 下限),适配缩放\r\n * 钳 ≤ 1,故主画布不会被撑大、小窗也不会被 letterbox 到不可读;\r\n * 2. 名片按\"槽位屏幕宽度\"自动降级 full → compact → dots;compact/dots 的几何按\r\n * `1/eff` 反算为屏幕恒定大小,同时被槽位宽封顶,所以在任何密度下都不重叠;\r\n * 3. 省掉的文字不丢——底部 caption 行按 hover ?? 选中给出完整名片;密度真的高时\r\n * 用 `mergeConjugates` 把共轭子群合成一个轨道节点(×n,n = |G : N_G(H)|)。\r\n */\r\nexport function SublatticeScene({\r\n group,\r\n lattice,\r\n canvasTransform,\r\n availableSize,\r\n labelDetail = 'auto',\r\n mergeConjugates = false,\r\n nodeScale = 1,\r\n showSeriesPanel = true,\r\n series = null,\r\n centerIds,\r\n subsets,\r\n activeNodeIdx: activeNodeIdxProp,\r\n onActivateNode,\r\n noGroupText,\r\n theme: themeProp,\r\n maxEnumerateOrder = 60,\r\n}: SublatticeSceneProps) {\r\n const { t } = useTranslation()\r\n const { theme: ctxTheme } = useTheme()\r\n const theme = themeProp ?? ctxTheme\r\n const palette = useMemo(() => buildPalette(theme), [theme])\r\n\r\n // 绘图区可用像素(不含 caption/series 面板):优先外部 availableSize,否则实测 svg 自身。\r\n // svg 必须是宿主的直接 flex 子元素并用 getBoundingClientRect 测量——若外面再包一层\r\n // div,svg 会按 viewBox 宽高比反推自身高度而撑破窗口。测得 0 → fit 视为 1。\r\n const svgHostRef = useRef<SVGSVGElement | null>(null)\r\n const [measured, setMeasured] = useState({ width: 0, height: 0 })\r\n useLayoutEffect(() => {\r\n const el = svgHostRef.current\r\n if (!el) return\r\n const update = () => {\r\n const r = el.getBoundingClientRect()\r\n setMeasured({ width: r.width, height: r.height })\r\n }\r\n update()\r\n if (typeof ResizeObserver === 'undefined') return\r\n const ro = new ResizeObserver(update)\r\n ro.observe(el)\r\n return () => ro.disconnect()\r\n }, [group?.symbol])\r\n const availW = availableSize?.width ?? measured.width\r\n const availH = availableSize?.height ?? measured.height\r\n\r\n const ct: CanvasTransform = canvasTransform ?? { x: 0, y: 0, scale: 1 }\r\n\r\n const baseLattice = useMemo<LatticeData | null>(() => {\r\n if (lattice !== undefined) return lattice\r\n if (!group || group.order > maxEnumerateOrder) return null\r\n return computeSubgroupLattice(group)\r\n }, [group, lattice, maxEnumerateOrder])\r\n\r\n // 共轭轨道合并:mergedOf[原下标] = 轨道格下标(未合并时 null)\r\n const { viewNodes, viewEdges, mergedOf, mergeUnavailable } = useMemo(() => {\r\n if (!baseLattice) {\r\n return {\r\n viewNodes: [] as SubgroupLatticeNode[],\r\n viewEdges: [] as SubgroupLatticeEdge[],\r\n mergedOf: null as number[] | null,\r\n mergeUnavailable: false,\r\n }\r\n }\r\n const identity = {\r\n viewNodes: baseLattice.nodes,\r\n viewEdges: baseLattice.edges,\r\n mergedOf: null as number[] | null,\r\n mergeUnavailable: false,\r\n }\r\n if (!mergeConjugates || !group) return identity\r\n const merged = mergeLatticeByConjugacy(group, baseLattice.nodes, baseLattice.edges)\r\n if (!merged) return { ...identity, mergeUnavailable: true }\r\n return {\r\n viewNodes: merged.nodes as SubgroupLatticeNode[],\r\n viewEdges: merged.edges,\r\n mergedOf: merged.orbitOf,\r\n mergeUnavailable: false,\r\n }\r\n }, [baseLattice, mergeConjugates, group])\r\n\r\n const layout = useMemo(\r\n () => computeLatticeLayout(viewNodes, viewEdges, { nodeScale }),\r\n [viewNodes, viewEdges, nodeScale]\r\n )\r\n\r\n // 疏密/降档推导:一次算好放进同一个 memo,避免逐帧重算的裸值进下游 memo 依赖\r\n const density = useMemo(() => {\r\n const fit = latticeFitScale(availW, availH, layout.viewW, layout.viewH)\r\n const eff = fit * ct.scale\r\n const { slotScreenWidth, rowScreenHeight } = latticeSlotScreenSize(\r\n layout.slotW, layout.rowH, fit, ct.scale\r\n )\r\n const tier: LatticeLodTier = labelDetail === 'auto'\r\n ? latticeLodTier(slotScreenWidth, rowScreenHeight)\r\n : labelDetail\r\n const edgeWidth = tier === 'full'\r\n ? palette.edgeWidth\r\n : toWorld(1.7, eff, layout.nodeRx * 0.1)\r\n return { fit, eff, slotScreenWidth, rowScreenHeight, tier, edgeWidth }\r\n }, [availW, availH, layout, ct.scale, labelDetail, palette])\r\n const { eff, slotScreenWidth, tier, edgeWidth } = density\r\n\r\n const { fullIdx, trivialIdx } = useMemo(() => {\r\n const order = group?.order ?? 0\r\n return {\r\n fullIdx: viewNodes.findIndex(nd => nd.order === order),\r\n trivialIdx: viewNodes.findIndex(nd => nd.order === 1),\r\n }\r\n }, [viewNodes, group])\r\n\r\n const centerSet = useMemo(() => {\r\n if (centerIds) return new Set(centerIds)\r\n if (!group || group.order > maxEnumerateOrder) return null\r\n return new Set(getGroupCenter(group).map(e => e.id))\r\n }, [group, centerIds, maxEnumerateOrder])\r\n\r\n const centerIdx = useMemo(() => {\r\n if (!centerSet || centerSet.size === 0) return -1\r\n return viewNodes.findIndex(nd => {\r\n if (nd.elementIds.length !== centerSet.size) return false\r\n return nd.elementIds.every(id => centerSet.has(id))\r\n })\r\n }, [viewNodes, centerSet])\r\n\r\n const sylowOrderToP = useMemo(() => {\r\n const map = new Map<number, number>()\r\n if (!group) return map\r\n for (const { prime, exponent } of factorizeOrder(group.order)) {\r\n let pPower = 1\r\n for (let i = 0; i < exponent; i++) pPower *= prime\r\n map.set(pPower, prime)\r\n }\r\n return map\r\n }, [group])\r\n\r\n const [activeNodeIdxState, setActiveNodeIdxState] = useState<number | null>(null)\r\n const activeNodeIdx = activeNodeIdxProp ?? activeNodeIdxState\r\n const [hoverIdx, setHoverIdx] = useState<number | null>(null)\r\n\r\n const adjacency = useMemo(\r\n () => buildAdjacency(viewNodes.length, viewEdges),\r\n [viewNodes, viewEdges]\r\n )\r\n\r\n const pathIndices = useMemo(() => {\r\n if (activeNodeIdx === null || viewNodes.length === 0) return new Set<number>()\r\n const set = new Set<number>()\r\n const upPath = fullIdx >= 0 ? findPath(adjacency, activeNodeIdx, fullIdx) : null\r\n const downPath = trivialIdx >= 0 ? findPath(adjacency, activeNodeIdx, trivialIdx) : null\r\n if (upPath) upPath.forEach(i => set.add(i))\r\n if (downPath) downPath.forEach(i => set.add(i))\r\n return set\r\n }, [activeNodeIdx, adjacency, fullIdx, trivialIdx, viewNodes])\r\n\r\n const pathEdgeSet = useMemo(() => {\r\n const set = new Set<number>()\r\n if (pathIndices.size === 0) return set\r\n for (let ei = 0; ei < viewEdges.length; ei++) {\r\n const e = viewEdges[ei]\r\n if (pathIndices.has(e.from) && pathIndices.has(e.to)) set.add(ei)\r\n }\r\n return set\r\n }, [pathIndices, viewEdges])\r\n\r\n const seriesColor = useMemo(() => {\r\n if (!series) return null\r\n const c = SERIES_COLORS[series.type]\r\n return theme === 'light' ? c.light : c.dark\r\n }, [series, theme])\r\n\r\n // 元素集合键 → 视图节点下标:合并态把轨道每个成员的键都指回该轨道节点,\r\n // 于是共轭但非相等的系列项仍能命中(D6)\r\n const keyToNodeIdx = useMemo(() => {\r\n const map = new Map<string, number>()\r\n if (!baseLattice) return map\r\n baseLattice.nodes.forEach((nd, i) => {\r\n const k = subgroupSetKey(nd.elementIds)\r\n if (!map.has(k)) map.set(k, mergedOf ? mergedOf[i] : i)\r\n })\r\n return map\r\n }, [baseLattice, mergedOf])\r\n\r\n const seriesNodeMap = useMemo(() => {\r\n const map = new Map<number, number>()\r\n if (!series?.terms) return map\r\n series.terms.forEach((term, ti) => {\r\n const ni = keyToNodeIdx.get(subgroupSetKey(term.map(e => e.id)))\r\n if (ni !== undefined && !map.has(ni)) map.set(ni, ti)\r\n })\r\n return map\r\n }, [series, keyToNodeIdx])\r\n\r\n const seriesNodeSet = useMemo(() => new Set(seriesNodeMap.keys()), [seriesNodeMap])\r\n\r\n const edgeElements = useMemo(() => {\r\n // 节点实际渲染高度按 tier 选:full 用 layout 默认矩形高度,compact 胶囊和 dots 圆点\r\n // 都是屏幕恒定像素,所以线段 y 偏移要用对应的世界单位——否则 compact/dots 下偏移过大,\r\n // 线段终点落到节点外侧\"线头\",看着像没对齐。\r\n const edgeNodeHalfH = tier === 'compact'\r\n ? toWorld(COMPACT_PILL.h / 2, eff, layout.nodeRy * 0.9)\r\n : tier === 'dots'\r\n ? toWorld(DOT_R, eff, layout.nodeRx * 0.42)\r\n : layout.nodeRy\r\n return viewEdges.map((edge, i) => {\r\n const fromPos = layout.positions[edge.from]\r\n const toPos = layout.positions[edge.to]\r\n if (!fromPos || !toPos) return null\r\n const onPath = pathEdgeSet.has(i)\r\n return (\r\n <line\r\n key={`edge-${i}`}\r\n x1={fromPos.x}\r\n y1={fromPos.y + edgeNodeHalfH}\r\n x2={toPos.x}\r\n y2={toPos.y - edgeNodeHalfH}\r\n stroke={onPath ? palette.pathEdge : palette.edge}\r\n strokeWidth={onPath ? Math.max(palette.pathEdgeWidth, edgeWidth) : edgeWidth}\r\n opacity={onPath ? 1 : tier === 'dots' ? 0.75 : palette.edgeOpacity}\r\n />\r\n )\r\n })\r\n }, [viewEdges, layout, pathEdgeSet, palette, tier, edgeWidth, eff])\r\n\r\n const subsetSets = useMemo(\r\n () => (subsets ?? []).map(s => ({ color: s.color, set: new Set(s.elementIds) })),\r\n [subsets]\r\n )\r\n\r\n const nodeElements = useMemo(() => {\r\n return viewNodes.map((node, i) => {\r\n const pos = layout.positions[i]\r\n if (!pos) return null\r\n\r\n const orbitSize = (node as SubgroupLatticeNode & OrbitFields).orbitSize ?? 1\r\n const onPath = pathIndices.has(i)\r\n const isActive = activeNodeIdx === i\r\n const isTrivial = node.order === 1\r\n const isFull = node.order === (group?.order ?? 0)\r\n const isCenter = i === centerIdx\r\n const sylowP = node.order > 1 ? sylowOrderToP.get(node.order) : undefined\r\n const termIdx = seriesNodeMap.get(i)\r\n const isDimmed = !!series?.terms && termIdx === undefined && !seriesNodeSet.has(i)\r\n\r\n let fillColor = palette.nodeFill\r\n let strokeColor = node.isNormal ? palette.nodeStrokeNormal : palette.nodeStroke\r\n let strokeWidth = 2.5\r\n let textColor = palette.nodeText\r\n\r\n if (onPath && !(termIdx !== undefined && seriesColor)) {\r\n fillColor = palette.pathFill\r\n strokeColor = palette.pathStroke\r\n strokeWidth = 4\r\n textColor = palette.pathText\r\n }\r\n if (isActive) {\r\n fillColor = palette.activeFill\r\n strokeWidth = 4\r\n }\r\n if (isCenter && !onPath) {\r\n fillColor = palette.centerFill\r\n strokeColor = palette.centerStroke\r\n }\r\n if (isTrivial && !onPath) {\r\n fillColor = palette.trivialFill\r\n strokeColor = palette.trivialStroke\r\n strokeWidth = 2\r\n }\r\n if (isFull && !onPath) {\r\n fillColor = palette.fullFill\r\n strokeColor = palette.fullStroke\r\n }\r\n if (termIdx !== undefined && seriesColor) {\r\n strokeColor = seriesColor\r\n strokeWidth = tier === 'full'\r\n ? 4\r\n : Math.max(toWorld(3, eff, layout.nodeRx * 0.1), edgeWidth)\r\n }\r\n\r\n const parentSubset = subsetSets.find(ss => node.elementIds.every(eid => ss.set.has(eid)))\r\n\r\n const handlers = {\r\n onMouseDown: (e: React.MouseEvent) => e.stopPropagation(),\r\n onClick: (e: React.MouseEvent) => {\r\n e.stopPropagation()\r\n if (activeNodeIdx === i) {\r\n setActiveNodeIdxState(null)\r\n onActivateNode?.(null, null)\r\n } else {\r\n setActiveNodeIdxState(i)\r\n onActivateNode?.(i, node)\r\n }\r\n },\r\n onMouseEnter: () => setHoverIdx(i),\r\n onMouseLeave: () => setHoverIdx(cur => (cur === i ? null : cur)),\r\n }\r\n const groupStyle = { cursor: 'pointer', opacity: isDimmed ? 0.22 : 1 }\r\n\r\n // ── dots:屏幕恒定圆点,类别靠颜色编码,×n 与系列命中保留 ──\r\n if (tier === 'dots') {\r\n const r = toWorld(DOT_R, eff, layout.nodeRx * 0.42)\r\n const dotFill = termIdx !== undefined && seriesColor\r\n ? seriesColor\r\n : isCenter\r\n ? palette.centerStroke\r\n : sylowP !== undefined\r\n ? palette.sylowText\r\n : isFull\r\n ? palette.fullStroke\r\n : isTrivial\r\n ? palette.trivialStroke\r\n : node.isNormal\r\n ? palette.nodeStrokeNormal\r\n : palette.dotPlain\r\n return (\r\n <g key={node.id} transform={`translate(${pos.x}, ${pos.y})`} style={groupStyle} data-lattice-node={i} {...handlers}>\r\n <circle cx={0} cy={0} r={toWorld(14, eff, layout.nodeRx)} fill=\"transparent\" stroke=\"none\" />\r\n <circle\r\n cx={0}\r\n cy={0}\r\n r={r}\r\n fill={onPath ? palette.pathFill : dotFill}\r\n stroke={onPath ? palette.pathStroke : dotFill}\r\n strokeWidth={onPath || isActive ? toWorld(2.5, eff, r) : 0}\r\n />\r\n {orbitSize > 1 && (\r\n <text\r\n x={r + toWorld(3, eff, layout.nodeRx * 0.2)}\r\n y={toWorld(-3, eff, layout.nodeRy * 0.5)}\r\n textAnchor=\"start\"\r\n fill={palette.nodeSubText}\r\n fontSize={toWorld(ORBIT_FONT, eff, layout.nodeRx * 0.6)}\r\n fontFamily=\"monospace\"\r\n style={{ pointerEvents: 'none', userSelect: 'none' }}\r\n >\r\n ×{orbitSize}\r\n </text>\r\n )}\r\n </g>\r\n )\r\n }\r\n\r\n // ── compact:屏幕恒定胶囊,只留一行(结构阶数字 / ×n / 顶层群符号) ──\r\n if (tier === 'compact') {\r\n const hw = toWorld(COMPACT_PILL.w / 2, eff, layout.nodeRx * 0.94)\r\n const hh = toWorld(COMPACT_PILL.h / 2, eff, layout.nodeRy * 0.9)\r\n const fs = toWorld(COMPACT_PILL.font, eff, layout.nodeRx * 0.5)\r\n return (\r\n <g key={node.id} transform={`translate(${pos.x}, ${pos.y})`} style={groupStyle} data-lattice-node={i} {...handlers}>\r\n <rect\r\n x={-hw}\r\n y={-hh}\r\n width={hw * 2}\r\n height={hh * 2}\r\n rx={hh}\r\n ry={hh}\r\n fill={fillColor}\r\n stroke={strokeColor}\r\n strokeWidth={strokeWidth}\r\n />\r\n {parentSubset && !onPath && (\r\n <rect x={-hw} y={-hh} width={hw * 2} height={hh * 2} rx={hh} ry={hh} fill={`${parentSubset.color}22`} stroke=\"none\" />\r\n )}\r\n <text\r\n y={fs * 0.36}\r\n textAnchor=\"middle\"\r\n fill={textColor}\r\n fontSize={fs}\r\n fontWeight={isActive ? 'bold' : 'normal'}\r\n fontFamily=\"monospace\"\r\n style={{ pointerEvents: 'none', userSelect: 'none' }}\r\n >\r\n {isTrivial\r\n ? 'e'\r\n : isFull\r\n ? ''\r\n : `${node.order}`}\r\n </text>\r\n {orbitSize > 1 && !isFull && (\r\n <text\r\n x={hw - fs * 0.35}\r\n y={fs * 0.36}\r\n textAnchor=\"end\"\r\n fill={palette.nodeSubText}\r\n fontSize={fs * 0.85}\r\n fontFamily=\"monospace\"\r\n style={{ pointerEvents: 'none', userSelect: 'none' }}\r\n >\r\n ×{orbitSize}\r\n </text>\r\n )}\r\n {isFull && group && (\r\n <foreignObject\r\n x={-hw}\r\n y={-hh}\r\n width={hw * 2}\r\n height={hh * 2}\r\n style={{ pointerEvents: 'none', userSelect: 'none' }}\r\n >\r\n <div\r\n style={{\r\n display: 'flex', alignItems: 'center', justifyContent: 'center',\r\n width: '100%', height: '100%', color: textColor, fontSize: fs,\r\n }}\r\n dangerouslySetInnerHTML={{ __html: renderTex(texify(group.symbol)) }}\r\n />\r\n </foreignObject>\r\n )}\r\n {termIdx !== undefined && seriesColor && (\r\n <circle cx={-hw + hh * 0.55} cy={0} r={hh * 0.3} fill={seriesColor} stroke=\"none\" style={{ pointerEvents: 'none' }} />\r\n )}\r\n {isCenter && (\r\n <circle cx={hw - hh * 0.55} cy={0} r={hh * 0.3} fill={palette.centerStroke} stroke=\"none\" style={{ pointerEvents: 'none' }} />\r\n )}\r\n </g>\r\n )\r\n }\r\n\r\n // ── full:完整名片(与 props 化之前的主画布一致) ──\r\n const nodeRx = layout.nodeRx\r\n const nodeRy = layout.nodeRy\r\n return (\r\n <g key={node.id} transform={`translate(${pos.x}, ${pos.y})`} style={groupStyle} data-lattice-node={i} {...handlers}>\r\n <rect\r\n x={-nodeRx}\r\n y={-nodeRy}\r\n width={nodeRx * 2}\r\n height={nodeRy * 2}\r\n rx={12}\r\n ry={12}\r\n fill={fillColor}\r\n stroke={strokeColor}\r\n strokeWidth={strokeWidth}\r\n />\r\n {parentSubset && !onPath && (\r\n <rect\r\n x={-nodeRx}\r\n y={-nodeRy}\r\n width={nodeRx * 2}\r\n height={nodeRy * 2}\r\n rx={12}\r\n ry={12}\r\n fill={`${parentSubset.color}22`}\r\n stroke=\"none\"\r\n />\r\n )}\r\n <text\r\n y={-8}\r\n textAnchor=\"middle\"\r\n fill={textColor}\r\n fontSize=\"15px\"\r\n fontWeight={isActive ? 'bold' : 'normal'}\r\n fontFamily=\"monospace\"\r\n style={{ pointerEvents: 'none', userSelect: 'none' }}\r\n >\r\n {isTrivial ? '⟨e⟩' : isFull ? '' : orbitSize > 1 ? `|H|=${node.order} ×${orbitSize}` : `|H|=${node.order}`}\r\n </text>\r\n {isCenter && (\r\n <text\r\n x={nodeRx - 6}\r\n y={-nodeRy + 12}\r\n textAnchor=\"end\"\r\n fill={palette.centerStroke}\r\n fontSize={10}\r\n fontWeight=\"bold\"\r\n fontFamily=\"monospace\"\r\n style={{ pointerEvents: 'none', userSelect: 'none' }}\r\n >\r\n Z(G)\r\n </text>\r\n )}\r\n {sylowP !== undefined && (\r\n <text\r\n x={-nodeRx + 6}\r\n y={-nodeRy + 12}\r\n textAnchor=\"start\"\r\n fill={palette.sylowText}\r\n fontSize={10}\r\n fontWeight=\"bold\"\r\n fontFamily=\"monospace\"\r\n style={{ pointerEvents: 'none', userSelect: 'none' }}\r\n >\r\n {t('lattice.sylow', { p: String(sylowP) })}\r\n </text>\r\n )}\r\n {termIdx !== undefined && seriesColor && (\r\n <g style={{ pointerEvents: 'none' }}>\r\n <circle cx={-nodeRx + 12} cy={nodeRy - 12} r={9} fill={seriesColor} stroke=\"none\" />\r\n <text\r\n x={-nodeRx + 12}\r\n y={nodeRy - 8}\r\n textAnchor=\"middle\"\r\n fontSize=\"10\"\r\n fontWeight=\"bold\"\r\n fill={palette.seriesBadgeText}\r\n fontFamily=\"monospace\"\r\n >\r\n {termIdx}\r\n </text>\r\n </g>\r\n )}\r\n {isFull && group && (\r\n <foreignObject\r\n x={-nodeRx + 6}\r\n y={-nodeRy + 2}\r\n width={nodeRx * 2 - 12}\r\n height={nodeRy * 2 - 4}\r\n style={{ pointerEvents: 'none', userSelect: 'none' }}\r\n >\r\n <div\r\n style={{\r\n display: 'flex', alignItems: 'center', justifyContent: 'center',\r\n width: '100%', height: '100%', color: textColor, fontSize: '15px',\r\n }}\r\n dangerouslySetInnerHTML={{ __html: renderTex(texify(group.symbol)) }}\r\n />\r\n </foreignObject>\r\n )}\r\n <text\r\n y={13}\r\n textAnchor=\"middle\"\r\n fill={onPath ? palette.pathSubText : node.isNormal ? palette.nodeStrokeNormal : palette.nodeSubText}\r\n fontSize=\"11px\"\r\n fontFamily=\"monospace\"\r\n style={{ pointerEvents: 'none', userSelect: 'none' }}\r\n >\r\n {isTrivial\r\n ? t('lattice.trivial')\r\n : isFull\r\n ? `|G|=${group?.order ?? ''}`\r\n : node.isNormal\r\n ? `◁ ${t('badge.normal')}`\r\n : t('lattice.subgroup')}\r\n </text>\r\n </g>\r\n )\r\n })\r\n }, [\r\n viewNodes, layout, pathIndices, activeNodeIdx, group, centerIdx, sylowOrderToP,\r\n seriesNodeMap, series, seriesNodeSet, seriesColor, palette, subsetSets, t,\r\n tier, eff, edgeWidth, onActivateNode,\r\n ])\r\n\r\n const seriesLines = useMemo(() => {\r\n if (!seriesColor) return null\r\n const byTerm = [...seriesNodeMap.entries()].sort((a, b) => a[1] - b[1])\r\n const lines: { from: { x: number; y: number }; to: { x: number; y: number } }[] = []\r\n for (let i = 0; i + 1 < byTerm.length; i++) {\r\n const fromPos = layout.positions[byTerm[i][0]]\r\n const toPos = layout.positions[byTerm[i + 1][0]]\r\n if (fromPos && toPos) lines.push({ from: fromPos, to: toPos })\r\n }\r\n return lines\r\n }, [seriesColor, seriesNodeMap, layout])\r\n\r\n // detail:hover 优先、否则选中。结构符号 O(|H|²),memo 即缓存(只在悬停节点变化时重算)\r\n const detailIdx = hoverIdx ?? activeNodeIdx\r\n const detailNode = detailIdx === null ? null : viewNodes[detailIdx] ?? null\r\n const detailSymbol = useMemo(() => {\r\n if (!group || !detailNode || detailNode.order === group.order) return null\r\n return subgroupStructureSymbol(group, detailNode.elementIds)\r\n }, [group, detailNode])\r\n\r\n const detailOrbit = detailNode as (SubgroupLatticeNode & OrbitFields) | null\r\n const detailTermIdx = detailIdx === null ? undefined : seriesNodeMap.get(detailIdx)\r\n\r\n // 就地气泡:屏幕坐标系下贴近 hover/选中节点,与底部 caption 行解耦,不再与 zoom slider 争位\r\n // 关键:foreignObject 内 HTML 用 13/eff 等反缩放字号,保证 ct.scale 变化时字号视觉恒定\r\n const bubble = useMemo(() => {\r\n if (!group || !detailNode || detailIdx === null) return null\r\n const pos = layout.positions[detailIdx]\r\n if (!pos) return null\r\n const nRy = layout.nodeRy\r\n const BUBBLE_PAD_X = 12 / eff\r\n const BUBBLE_PAD_Y = 6 / eff\r\n const BUBBLE_W = 280 / eff\r\n const BUBBLE_LINE_H = 18 / eff\r\n const BUBBLE_GAP = 8 / eff\r\n const lines: ReactNode[] = []\r\n lines.push(\r\n <span key=\"order\" dangerouslySetInnerHTML={{ __html: renderTex(`|H| = ${detailNode.order}`) }} />\r\n )\r\n if (detailSymbol) {\r\n lines.push(\r\n <span key=\"sym\" dangerouslySetInnerHTML={{ __html: renderTex(`\\\\cong ${detailSymbol}`) }} />\r\n )\r\n }\r\n if (detailNode.isNormal && detailNode.order !== group.order) {\r\n lines.push(\r\n <span key=\"normal\" style={{ color: palette.nodeStrokeNormal }}>{`◁ ${t('badge.normal')}`}</span>\r\n )\r\n }\r\n lines.push(\r\n <span key=\"idx\" dangerouslySetInnerHTML={{ __html: renderTex(`[G:H] = ${Math.round(group.order / detailNode.order)}`) }} />\r\n )\r\n if ((detailOrbit?.orbitSize ?? 1) > 1) {\r\n lines.push(\r\n <span key=\"orbit\" style={{ color: 'var(--text-muted)' }}>\r\n {t('lattice.orbitMembers', { n: String(detailOrbit!.orbitSize) })}\r\n {' · '}\r\n <span dangerouslySetInnerHTML={{ __html: renderTex(`|N_G(H)| = ${detailOrbit!.normalizerOrder}`) }} />\r\n </span>\r\n )\r\n }\r\n if (detailNode.label && detailNode.label !== `${detailNode.order}`) {\r\n lines.push(\r\n <span key=\"label\" dangerouslySetInnerHTML={{ __html: renderTex(texify(detailNode.label)) }} />\r\n )\r\n }\r\n if (detailTermIdx !== undefined && series) {\r\n lines.push(\r\n <span key=\"term\" style={{ color: seriesColor ?? undefined }}>{`N_${detailTermIdx} · ${t(`series.${series.type}`)}`}</span>\r\n )\r\n }\r\n const lineCount = lines.length\r\n const BUBBLE_H = BUBBLE_LINE_H * lineCount + BUBBLE_PAD_Y * 2\r\n // 位置策略:上方优先 → 不足则下方 → 上下都贴边则压紧到 viewBox 内\r\n const aboveY = pos.y - nRy - BUBBLE_GAP - BUBBLE_H\r\n const belowY = pos.y + nRy + BUBBLE_GAP\r\n let bubbleY = aboveY\r\n let pointer: 'down' | 'up' = 'down'\r\n if (aboveY < 0 || belowY + BUBBLE_H > layout.viewH) {\r\n // 至少一侧能放下时选空间大的那侧\r\n const aboveRoom = aboveY // 越负越差\r\n const belowRoom = layout.viewH - (belowY + BUBBLE_H) // 越负越差\r\n if (aboveRoom >= belowRoom) {\r\n bubbleY = Math.max(aboveY, 0)\r\n pointer = 'down'\r\n } else {\r\n bubbleY = Math.min(belowY, layout.viewH - BUBBLE_H)\r\n pointer = 'up'\r\n }\r\n }\r\n const idealX = pos.x - BUBBLE_W / 2\r\n const bubbleX = Math.min(Math.max(idealX, 0), Math.max(layout.viewW - BUBBLE_W, 0))\r\n const arrowAnchorX = Math.min(Math.max(pos.x, bubbleX + BUBBLE_PAD_X), bubbleX + BUBBLE_W - BUBBLE_PAD_X)\r\n const arrowTipY = pointer === 'down' ? bubbleY + BUBBLE_H : bubbleY\r\n const arrowBaseY = pointer === 'down' ? bubbleY : bubbleY + BUBBLE_H\r\n return (\r\n <g style={{ pointerEvents: 'none' }} data-testid=\"lattice-bubble\">\r\n <polygon\r\n points={`${arrowAnchorX - 6/eff},${arrowBaseY} ${arrowAnchorX + 6/eff},${arrowBaseY} ${arrowAnchorX},${arrowTipY}`}\r\n fill=\"var(--bg-panel)\"\r\n stroke=\"var(--border-primary)\"\r\n strokeWidth={1 / eff}\r\n />\r\n <foreignObject\r\n x={bubbleX}\r\n y={bubbleY}\r\n width={BUBBLE_W}\r\n height={BUBBLE_H}\r\n style={{ overflow: 'visible' }}\r\n >\r\n <div\r\n style={{\r\n width: '100%',\r\n height: '100%',\r\n padding: `${BUBBLE_PAD_Y}px ${BUBBLE_PAD_X}px`,\r\n border: '1px solid var(--border-primary)',\r\n borderRadius: `${6 / eff}px`,\r\n background: 'var(--bg-panel)',\r\n color: 'var(--text-primary)',\r\n fontSize: `${13 / eff}px`,\r\n lineHeight: 1.4,\r\n boxShadow: '0 2px 8px rgba(0,0,0,0.25)',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n gap: `${2 / eff}px`,\r\n }}\r\n >\r\n {lines.map((ln, idx) => (\r\n <span key={idx} style={{ display: 'inline-flex', alignItems: 'center', gap: `${8 / eff}px` }}>\r\n {ln}\r\n </span>\r\n ))}\r\n </div>\r\n </foreignObject>\r\n </g>\r\n )\r\n }, [detailNode, detailIdx, detailOrbit, detailTermIdx, detailSymbol, layout, eff, group, series, seriesColor, t, palette.nodeStrokeNormal])\r\n\r\n if (!group || !baseLattice || viewNodes.length === 0) {\r\n return (\r\n <div className=\"view-empty\">\r\n <p>{noGroupText ?? (group ? t('lattice.backendOnly') : t('canvas.noGroup'))}</p>\r\n </div>\r\n )\r\n }\r\n\r\n return (\r\n <div\r\n className=\"sublattice-view-wrap\"\r\n data-lattice-tier={tier}\r\n data-lattice-slot-width={Math.round(slotScreenWidth)}\r\n style={{ height: '100%', display: 'flex', flexDirection: 'column' }}\r\n >\r\n {/* 绘图区宿主:svg 绝对定位填满。若让 svg 参与常规流,它的 viewBox 宽高比会\r\n 以 min-content 高度向上撑破固定高度的窗口(Chrome 行为),故这里必须 absolute。 */}\r\n <div style={{ flex: 1, minHeight: 0, position: 'relative' }}>\r\n <svg\r\n ref={svgHostRef}\r\n viewBox={`0 0 ${layout.viewW} ${layout.viewH}`}\r\n className=\"view-svg\"\r\n style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', userSelect: 'none', overflow: 'visible' }}\r\n >\r\n <g transform={`translate(${ct.x}, ${ct.y}) scale(${ct.scale})`}>\r\n {edgeElements}\r\n {seriesLines && seriesLines.map((line, li) => (\r\n <line\r\n key={`series-line-${li}`}\r\n x1={line.from.x}\r\n y1={line.from.y}\r\n x2={line.to.x}\r\n y2={line.to.y}\r\n stroke={seriesColor!}\r\n strokeWidth={tier === 'full' ? 4 : Math.max(toWorld(4, eff, layout.nodeRx * 0.1), edgeWidth)}\r\n strokeLinecap=\"round\"\r\n opacity={0.85}\r\n />\r\n ))}\r\n {nodeElements}\r\n {bubble}\r\n </g>\r\n </svg>\r\n </div>\r\n {mergeUnavailable && (\r\n <div\r\n data-testid=\"lattice-merge-hint\"\r\n style={{ padding: '2px 10px', fontSize: 11, color: 'var(--accent-yellow-text)', flexShrink: 0 }}\r\n >\r\n {t('lattice.mergeTooLarge')}\r\n </div>\r\n )}\r\n {showSeriesPanel && series && <SeriesPanel group={group} series={series} color={seriesColor} theme={theme} />}\r\n </div>\r\n )\r\n}","/**\r\n * SceneWindow — @groupviz/react 通用窗口壳容器(FGVE「壳能力参数化」)。\r\n *\r\n * 定位:ViewWindow(主应用浮动窗壳)与「裸 Scene 直渲」之间的中间形态。壳只管\r\n * 窗口 chrome,children 渲任意 packaged Scene(消费端自持 Scene props,本组件\r\n * 零 Scene 耦合)。两个层次控制壳能力:\r\n *\r\n * shell: 'none' → 裸内容容器(等同 Frame 直嵌,不带任何 chrome)\r\n * 'chrome' → 标题栏 + 能力按钮 + 拖拽/resize + ⚙ View Config 面板 + persist\r\n * capabilities: chrome 形态下逐项露/藏内容;不传 = 全开,显式 false 关闭该项。\r\n *\r\n * 零 context / i18n / zod 依赖:主题用 theme prop(颜色自含 hex,不读 CSS 变量),\r\n * 按钮图标 + 英文 title(与主应用 FloatingViewWindow 一致),持久化 minimal\r\n * localStorage(try/catch 宽容,不引 utils/persistence 的 zod 校验链)。\r\n *\r\n * 约定:parent 需 position:relative;chrome 窗口 absolute 定位可拖可缩;shell:'none'\r\n * 时返回普通块级容器(不脱离文档流)。\r\n */\r\nimport { useCallback, useEffect, useState, type CSSProperties, type ReactNode } from 'react'\r\nimport type { Group } from '../../core/types'\r\n\r\nexport type SceneWindowTheme = 'dark' | 'light'\r\n\r\n/** 窗口级 config(行为开关;Scene 级参数由消费端以 Scene props 直传,不经此壳) */\r\nexport interface SceneWindowConfig {\r\n /** 📌 锁定窗口移动(拖拽禁用) */\r\n locked?: boolean\r\n /** 标题栏 info 区显示群符号/阶/名 */\r\n showInfo?: boolean\r\n /** 8 向 resize 手柄 */\r\n resizable?: boolean\r\n /** 定位用 fixed(视口固定)而非 absolute */\r\n viewportFixed?: boolean\r\n /** 标题栏整组隐藏(插图等专注阅读场景) */\r\n showControls?: boolean\r\n}\r\n\r\n/** chrome 内容裁剪位;缺省全开。false 关某项 */\r\nexport interface SceneWindowCaps {\r\n /** 标题栏本体(含 info 区) */\r\n titlebar?: boolean\r\n /** 标题栏拖拽移动(需 titlebar 且 locked=false) */\r\n drag?: boolean\r\n /** resize 手柄(8 向) */\r\n resize?: boolean\r\n /** 📌 锁定移动按钮 */\r\n lockMove?: boolean\r\n /** i 信息开关按钮 */\r\n toggleInfo?: boolean\r\n /** ⚙ View Config 面板(窗口 config 编辑) */\r\n params?: boolean\r\n /** × 关闭按钮(触发 onClose) */\r\n close?: boolean\r\n /** storageKey 持久化(位置/尺寸/config) */\r\n persist?: boolean\r\n}\r\n\r\ninterface SceneWindowProps {\r\n /** 标题栏主文案;缺省回退 group.symbol */\r\n title?: string\r\n /** 标题/信息兜底源 */\r\n group?: Group | null\r\n /** 窗口主题(背景/边框/文字配色);缺省 'dark' */\r\n theme?: SceneWindowTheme\r\n /** 'chrome' 浮动窗壳(缺省)/ 'none' 裸内容容器 */\r\n shell?: 'none' | 'chrome'\r\n /** chrome 内容裁剪;不传全开 */\r\n capabilities?: SceneWindowCaps\r\n /** 窗口 config(受控传入或非受控初值) */\r\n config?: SceneWindowConfig\r\n onConfigChange?: (c: SceneWindowConfig) => void\r\n /** 持久化键(cap.persist 且给键才读写 localStorage,键空间 gv-sw-*) */\r\n storageKey?: string\r\n defaultPosition?: { x: number; y: number }\r\n defaultSize?: { width: number; height: number }\r\n onClose?: () => void\r\n /** 任意 packaged Scene(或任意内容) */\r\n children: ReactNode\r\n}\r\n\r\nconst TBAR_H = 32\r\nconst MIN_W = 220\r\nconst MIN_H = 160\r\nconst PARAMS_W = 208\r\nconst PARAMS_GAP = 8\r\nlet _swZ = 5000\r\n\r\nconst DEFAULT_POS = { x: 12, y: 12 }\r\nconst DEFAULT_SIZE = { width: 440, height: 320 }\r\nconst DEFAULT_CFG: Required<SceneWindowConfig> = {\r\n locked: false, showInfo: false, resizable: true, viewportFixed: false, showControls: true,\r\n}\r\n\r\ntype ResizeDir = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw'\r\nconst RESIZE_CURSORS: Record<ResizeDir, string> = {\r\n n: 'ns-resize', s: 'ns-resize', e: 'ew-resize', w: 'ew-resize',\r\n ne: 'nesw-resize', sw: 'nesw-resize', nw: 'nwse-resize', se: 'nwse-resize',\r\n}\r\nconst RESIZE_DIRS: ResizeDir[] = ['n', 's', 'e', 'w', 'ne', 'nw', 'se', 'sw']\r\n\r\n// ── 主题色板(不读 CSS 变量,保证包消费端与主应用全局主题解耦) ──\r\nconst PALETTES: Record<SceneWindowTheme, {\r\n tbarBg: string; tbarBorder: string; tbarText: string; dim: string; contentBg: string;\r\n panelBg: string; panelBorder: string; panelText: string; accent: string;\r\n}> = {\r\n dark: {\r\n tbarBg: '#131c2b', tbarBorder: '#24324a', tbarText: '#94a3b8', dim: '#64748b',\r\n contentBg: '#0b1220', panelBg: '#111c2b', panelBorder: '#24324a', panelText: '#cbd5e1',\r\n accent: '#4ecdc4',\r\n },\r\n light: {\r\n tbarBg: '#eef2f7', tbarBorder: '#d0d9e4', tbarText: '#475569', dim: '#8fa0b3',\r\n contentBg: '#f8fafc', panelBg: '#ffffff', panelBorder: '#d0d9e4', panelText: '#334155',\r\n accent: '#0e7490',\r\n },\r\n}\r\n\r\n/** 打包键 → 规范解析(宽容:损坏/缺字段一律回退,不抛) */\r\nfunction loadSw<T>(key: string, schema: (raw: Record<string, unknown>) => T | null): T | null {\r\n try {\r\n const raw = localStorage.getItem(`gv-sw-${key}`)\r\n if (!raw) return null\r\n const parsed = JSON.parse(raw) as Record<string, unknown>\r\n return schema(parsed)\r\n } catch {\r\n return null\r\n }\r\n}\r\nfunction saveSw(key: string, data: unknown) {\r\n try {\r\n localStorage.setItem(`gv-sw-${key}`, JSON.stringify(data))\r\n } catch {\r\n /* 隐私模式/配额:静默 */\r\n }\r\n}\r\n\r\nfunction mergeCfg(base: SceneWindowConfig, extra?: SceneWindowConfig): SceneWindowConfig {\r\n return extra ? { ...base, ...extra } : base\r\n}\r\n\r\n/** 一次读持久化三件套(宽容:缺/坏字段回 undefined,不抛) */\r\nfunction readPersist(key?: string, enabled = true): { pos?: { x: number; y: number }; size?: { width: number; height: number }; cfg?: SceneWindowConfig } | null {\r\n if (!key || !enabled) return null\r\n return loadSw(key, raw => {\r\n const p = raw.pos as { x?: number; y?: number } | undefined\r\n const s = raw.size as { width?: number; height?: number } | undefined\r\n const rc = raw.config as Record<string, unknown> | undefined\r\n return {\r\n pos: p && typeof p.x === 'number' && typeof p.y === 'number' ? { x: p.x, y: p.y } : undefined,\r\n size: s && typeof s.width === 'number' && typeof s.height === 'number'\r\n ? { width: Math.max(MIN_W, s.width), height: Math.max(MIN_H, s.height) } : undefined,\r\n cfg: rc && typeof rc === 'object' ? (rc as SceneWindowConfig) : undefined,\r\n }\r\n })\r\n}\r\n\r\n/** 页面级辅助:stable 空对象引用 */\r\nconst EMPTY = {}\r\n\r\nexport function SceneWindow({\r\n title,\r\n group,\r\n theme = 'dark',\r\n shell = 'chrome',\r\n capabilities,\r\n config: configProp,\r\n onConfigChange,\r\n storageKey,\r\n defaultPosition,\r\n defaultSize,\r\n onClose,\r\n children,\r\n}: SceneWindowProps) {\r\n const P = PALETTES[theme]\r\n // ── 窗口 state(非受控):config + 几何(pos+size);persist 全在 lazy init 合并,effect 只写不读 ──\r\n const persistOn = !!storageKey && capabilities?.persist !== false\r\n const [cfg, setCfg] = useState<SceneWindowConfig>(() => {\r\n const c: SceneWindowConfig = { ...DEFAULT_CFG, ...(configProp ?? EMPTY) }\r\n const saved = readPersist(storageKey, persistOn)\r\n return saved?.cfg ? mergeCfg(c, saved.cfg) : c\r\n })\r\n const updateConfig = useCallback((patch: SceneWindowConfig) => {\r\n setCfg(prev => {\r\n const next = mergeCfg(prev, patch)\r\n onConfigChange?.(next)\r\n return next\r\n })\r\n }, [onConfigChange])\r\n\r\n const [geom, setGeom] = useState(() => {\r\n const saved = readPersist(storageKey, persistOn)\r\n return {\r\n pos: saved?.pos ?? defaultPosition ?? DEFAULT_POS,\r\n size: saved?.size ?? defaultSize ?? DEFAULT_SIZE,\r\n }\r\n })\r\n const { pos, size } = geom\r\n\r\n // 持久化写:几何 + config(cap.persist 且 storageKey)\r\n useEffect(() => {\r\n if (persistOn) saveSw(storageKey as string, { pos, size, config: cfg })\r\n }, [pos, size, cfg, storageKey, persistOn])\r\n\r\n // 置顶(mousedown 时 bring front)\r\n const [z, setZ] = useState(() => ++_swZ)\r\n const bringFront = useCallback(() => setZ(++_swZ), [])\r\n\r\n const [paramsOpen, setParamsOpen] = useState(false)\r\n\r\n // 拖拽(标题栏)\r\n const onDragStart = useCallback((e: React.MouseEvent) => {\r\n if (cfg.locked) return\r\n if ((e.target as HTMLElement).closest('button')) return\r\n e.preventDefault()\r\n bringFront()\r\n const start = { mx: e.clientX, my: e.clientY, ox: pos.x, oy: pos.y }\r\n const move = (ev: MouseEvent) => {\r\n setGeom(g => ({ ...g, pos: { x: start.ox + ev.clientX - start.mx, y: start.oy + ev.clientY - start.my } }))\r\n }\r\n const up = () => {\r\n window.removeEventListener('mousemove', move)\r\n window.removeEventListener('mouseup', up)\r\n }\r\n window.addEventListener('mousemove', move)\r\n window.addEventListener('mouseup', up)\r\n }, [cfg.locked, pos, bringFront])\r\n\r\n // resize(8 向手柄)\r\n const onResizeStart = useCallback((dir: ResizeDir) => (e: React.MouseEvent) => {\r\n e.preventDefault(); e.stopPropagation()\r\n bringFront()\r\n const start = { mx: e.clientX, my: e.clientY, ox: pos.x, oy: pos.y, ow: size.width, oh: size.height }\r\n const move = (ev: MouseEvent) => {\r\n const dx = ev.clientX - start.mx\r\n const dy = ev.clientY - start.my\r\n let { x, y, width, height } = { x: start.ox, y: start.oy, width: start.ow, height: start.oh }\r\n if (dir.includes('e')) width = Math.max(MIN_W, start.ow + dx)\r\n if (dir.includes('s')) height = Math.max(MIN_H, start.oh + dy)\r\n if (dir.includes('w')) { width = Math.max(MIN_W, start.ow - dx); x = start.ox + (start.ow - width) }\r\n if (dir.includes('n')) { height = Math.max(MIN_H, start.oh - dy); y = start.oy + (start.oh - height) }\r\n setGeom({ pos: { x, y }, size: { width, height } })\r\n }\r\n const up = () => {\r\n window.removeEventListener('mousemove', move)\r\n window.removeEventListener('mouseup', up)\r\n }\r\n window.addEventListener('mousemove', move)\r\n window.addEventListener('mouseup', up)\r\n }, [pos, size, bringFront])\r\n\r\n // ── shell:'none':裸内容容器(块级,不脱离文档流,无 chrome) ──\r\n if (shell === 'none') {\r\n return (\r\n <div data-testid=\"sw-none\" style={{ width: '100%', height: '100%', minHeight: 160, background: P.contentBg, overflow: 'hidden', position: 'relative' }}>\r\n {children}\r\n </div>\r\n )\r\n }\r\n\r\n // ── shell:'chrome' ──\r\n const caps = {\r\n titlebar: true, drag: true, resize: true, lockMove: true, toggleInfo: true,\r\n params: true, close: true, persist: true,\r\n ...(capabilities ?? EMPTY),\r\n } as Required<SceneWindowCaps>\r\n const showControls = cfg.showControls !== false\r\n const titleText = title ?? (group ? group.symbol : 'View')\r\n const infoText = cfg.showInfo && group\r\n ? `${group.symbol} · |G|=${group.order} · ${group.name ?? ''}`\r\n : ''\r\n const btnBase: CSSProperties = {\r\n background: 'none', border: 'none', color: P.dim, cursor: 'pointer',\r\n fontSize: 14, padding: '2px 5px', lineHeight: 1, borderRadius: 4,\r\n }\r\n const tglBtn = (on: boolean, color: string): CSSProperties => ({ ...btnBase, color: on ? color : P.dim })\r\n\r\n return (\r\n <div\r\n data-testid=\"sw-chrome\"\r\n style={{ position: cfg.viewportFixed ? 'fixed' : 'absolute', left: pos.x, top: pos.y, zIndex: z }}\r\n onMouseDown={bringFront}\r\n >\r\n {/* 窗身(overflow hidden 收内容;⚙ 面板在 wrapper 外侧不被裁) */}\r\n <div style={{ width: size.width, background: P.contentBg, border: `1px solid ${P.tbarBorder}`, borderRadius: 8, overflow: 'hidden', boxShadow: '0 10px 34px rgba(0,0,0,0.30)' }}>\r\n {/* titlebar */}\r\n {caps.titlebar && showControls && (\r\n <div\r\n style={{\r\n display: 'flex', alignItems: 'center', justifyContent: 'space-between',\r\n padding: '0 6px 0 10px', height: TBAR_H, background: P.tbarBg,\r\n borderBottom: `1px solid ${P.tbarBorder}`, cursor: caps.drag && !cfg.locked ? 'grab' : 'default',\r\n fontSize: 13, color: P.tbarText, userSelect: 'none', flexShrink: 0, gap: 4,\r\n }}\r\n onMouseDown={caps.drag ? onDragStart : undefined}\r\n >\r\n <span style={{ fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>\r\n {titleText}\r\n {infoText && <span style={{ fontWeight: 400, fontSize: 11, color: P.dim, marginLeft: 8 }}>{infoText}</span>}\r\n </span>\r\n <div style={{ display: 'flex', alignItems: 'center', gap: 2 }}>\r\n {caps.lockMove && (\r\n <button title=\"Lock move\" style={tglBtn(!!cfg.locked, '#f97316')}\r\n onClick={() => updateConfig({ locked: !cfg.locked })}>\r\n {cfg.locked ? '📌' : '📍'}\r\n </button>\r\n )}\r\n {caps.toggleInfo && (\r\n <button title=\"Toggle info\" style={tglBtn(!!cfg.showInfo, '#84cc16')}\r\n onClick={() => updateConfig({ showInfo: !cfg.showInfo })}>i</button>\r\n )}\r\n {caps.params && (\r\n <button title=\"Parameters\" style={tglBtn(paramsOpen, '#a78bfa')}\r\n onClick={() => { bringFront(); setParamsOpen(o => !o) }}>⚙</button>\r\n )}\r\n {caps.close && (\r\n <button title=\"Close\" style={btnBase}\r\n onClick={onClose}\r\n onMouseEnter={e => (e.currentTarget.style.color = '#f44')}\r\n onMouseLeave={e => (e.currentTarget.style.color = P.dim)}>×</button>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* content viewport */}\r\n <div style={{ position: 'relative', height: size.height - (caps.titlebar && showControls ? TBAR_H : 0), overflow: 'hidden', background: P.contentBg }}>\r\n {children}\r\n {/* resize handles */}\r\n {caps.resize && cfg.resizable !== false && RESIZE_DIRS.map(dir => {\r\n const s = 8\r\n const c = 20\r\n const base: CSSProperties = { position: 'absolute', zIndex: 10, cursor: RESIZE_CURSORS[dir], background: 'transparent' }\r\n const rect: CSSProperties = (() => {\r\n switch (dir) {\r\n case 'n': return { top: 0, left: s, right: s, height: s }\r\n case 's': return { bottom: 0, left: s, right: s, height: s }\r\n case 'e': return { right: 0, top: s, bottom: s, width: s }\r\n case 'w': return { left: 0, top: s, bottom: s, width: s }\r\n case 'ne': return { top: 0, right: 0, width: c, height: c }\r\n case 'nw': return { top: 0, left: 0, width: c, height: c }\r\n case 'se': return { bottom: 0, right: 0, width: c, height: c }\r\n case 'sw': return { bottom: 0, left: 0, width: c, height: c }\r\n }\r\n })()\r\n return <div key={dir} style={{ ...base, ...rect }} onMouseDown={onResizeStart(dir)} />\r\n })}\r\n </div>\r\n </div>{/* /窗身 */}\r\n\r\n {/* ⚙ View Config panel(窗口外侧,不遮内容) */}\r\n {paramsOpen && caps.params && (\r\n <div\r\n style={{\r\n position: cfg.viewportFixed ? 'fixed' : 'absolute',\r\n left: size.width + PARAMS_GAP, top: 0, width: PARAMS_W,\r\n maxHeight: size.height, overflowY: 'auto', zIndex: z + 1,\r\n background: P.panelBg, border: `1px solid ${P.panelBorder}`, borderRadius: 6,\r\n boxShadow: '0 8px 32px rgba(0,0,0,0.28)', padding: '8px 10px',\r\n fontSize: 12, color: P.panelText,\r\n }}\r\n onMouseDown={bringFront}\r\n >\r\n <div style={{ fontWeight: 600, marginBottom: 6 }}>View Config</div>\r\n {caps.lockMove && (\r\n <label style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 4 }}>\r\n <input type=\"checkbox\" checked={!!cfg.locked} onChange={e => updateConfig({ locked: e.target.checked })} style={{ accentColor: P.accent }} />\r\n Lock move\r\n </label>\r\n )}\r\n {caps.toggleInfo && (\r\n <label style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 4 }}>\r\n <input type=\"checkbox\" checked={!!cfg.showInfo} onChange={e => updateConfig({ showInfo: e.target.checked })} style={{ accentColor: P.accent }} />\r\n Show info\r\n </label>\r\n )}\r\n <label style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 4 }}>\r\n <input type=\"checkbox\" checked={!!cfg.viewportFixed} onChange={e => updateConfig({ viewportFixed: e.target.checked })} style={{ accentColor: P.accent }} />\r\n Fixed to viewport\r\n </label>\r\n <label style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 4 }}>\r\n <input type=\"checkbox\" checked={cfg.showControls !== false} onChange={e => updateConfig({ showControls: e.target.checked })} style={{ accentColor: P.accent }} />\r\n Show controls\r\n </label>\r\n <label style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 4 }}>\r\n <input type=\"checkbox\" checked={cfg.resizable !== false} onChange={e => updateConfig({ resizable: e.target.checked })} style={{ accentColor: P.accent }} />\r\n Resizable\r\n </label>\r\n {/* 说明:Scene 级参数不经本壳,由宿主以 Scene props 直传 */}\r\n <div style={{ marginTop: 6, fontSize: 10, color: P.dim, lineHeight: 1.5 }}>\r\n Scene props are controlled by the host (embed your own <Scene …/> as children).\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n )\r\n}\r\n\r\nexport type { SceneWindowProps }\r\n","import type { CSSProperties } from 'react'\nimport { elementOrder } from '../../core/algebra/elementOrder'\nimport type { Group, GroupElement } from '../../core/types'\n\n/**\n * SceneHoverBubble —— 悬停就地气泡(默认实现)。\n *\n * 配合 `useSceneState().hoverBubble` 使用;也可在自建宿主里独立渲染。\n * 配色读 `theme.css` 的自定义属性(经 `data-theme` 作用域),因此天然跟随视图主题,\n * 不写死颜色;未引入 `theme.css` 时由内联兜底色保证可读。\n *\n * 定位:`anchor` 是元素在容器内的屏幕坐标(Scene 的 `onHover` 第二参),\n * 气泡默认浮在锚点正上方居中。`anchor` 为空(如表格视图不提供锚点)时不渲染。\n */\nexport interface SceneHoverBubbleProps {\n element: GroupElement | null\n anchor?: { x: number; y: number } | null\n /** 缺省 `'dark'`(与 `theme.css` 默认块一致) */\n theme?: 'dark' | 'light'\n /** 传入则在气泡里补一行「阶 = n」(元素阶是排名第一的高频信息) */\n group?: Group | null\n /** 相对锚点的额外偏移;缺省 `{ x: 0, y: -14 }` */\n offset?: { x: number; y: number }\n}\n\nexport function SceneHoverBubble({\n element,\n anchor,\n theme = 'dark',\n group,\n offset,\n}: SceneHoverBubbleProps) {\n if (!element || !anchor) return null\n\n const dx = offset?.x ?? 0\n const dy = offset?.y ?? -14\n const order = group ? elementOrder(group, element) : null\n\n const box: CSSProperties = {\n position: 'absolute',\n left: anchor.x + dx,\n top: anchor.y + dy,\n transform: 'translate(-50%, -100%)',\n pointerEvents: 'none',\n zIndex: 20,\n padding: '5px 9px',\n borderRadius: 6,\n border: '1px solid var(--border-primary, #2d2d4a)',\n background: 'var(--bg-tooltip, rgba(21,21,37,0.95))',\n color: 'var(--text-primary, #e0e0e0)',\n fontSize: 12,\n lineHeight: 1.4,\n whiteSpace: 'nowrap',\n boxShadow: '0 6px 20px rgba(0,0,0,0.35)',\n }\n\n const dim: CSSProperties = { color: 'var(--text-dim, #888888)', fontSize: 10 }\n\n return (\n <div data-theme={theme} style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>\n <div data-testid=\"scene-hover-bubble\" style={box}>\n <div style={{ fontWeight: 600 }}>{element.label}</div>\n {(order !== null || element.id !== element.label) && (\n <div style={dim}>\n {element.id !== element.label && <span>{element.id}</span>}\n {order !== null && (\n <span>{element.id !== element.label ? ' · ' : ''}阶 {order}</span>\n )}\n </div>\n )}\n </div>\n </div>\n )\n}\n","import { createElement, useCallback, useEffect, useMemo, useRef, useState, type CSSProperties, type ReactNode } from 'react'\nimport type { CanvasTransform, Group, GroupElement, NodePosition } from '../core/types'\nimport { SceneHoverBubble } from '../components/Canvas/SceneHoverBubble'\n\n/**\n * useSceneState —— 受控 Scene 的「四件套」便利层。\n *\n * 背景:`SetView` / `CycleView` / `CayleyView` / `CosetStripScene` 都是纯受控内核,\n * 宿主必须自备 `selectedElements` + `canvasTransform` + `viewBoxSize`,再自己接\n * `onSelect` / `onHover` 并渲染 hover 气泡。一个「嵌一张图」的最小用例要写 ~80 行胶水\n * (ResizeObserver 量尺寸、滚轮缩放贴光标、拖拽平移、⊕/Ctrl 多选、悬停锚点气泡)。\n *\n * 本 hook 把这一层收进包里:返回 `hostProps` + `sceneProps` + `hoverBubble`,\n * 宿主只需\n *\n * ```tsx\n * const group = createGroupFromSymbol('S_{4}')\n * const s = useSceneState(group)\n * return (\n * <div {...s.hostProps}>\n * <SetView group={group} {...s.sceneProps} />\n * {s.hoverBubble}\n * </div>\n * )\n * ```\n *\n * 设计要点:\n * - **ref 只以 `hostProps.ref` 嵌套形式出现,绝不作为顶层返回字段**。React Compiler\n * 的 `react-hooks/refs` 规则会把「顶层返回了写 ref 的回调 / 含 RefObject」的 hook\n * 整体判为 ref 载体,此后宿主每一次 `s.xxx` 读取都会报「渲染期访问 ref」\n * (实测:`s.hostProps`、`s.viewBoxSize` 一并中招)。嵌套形式不触发该判定。\n * 代价是宿主**不要自己在 spread 之后再写 `ref`**(会顶掉内建 ref);\n * 需要 DOM 节点时用 `getHostElement()`;\n * - `hostProps` 用 **React 合成事件**(非原生监听)做拖拽平移 —— 与 Scene 内节点的\n * `stopPropagation()` 处于同一套合成冒泡序,拖节点时不会把画布一起拖走;\n * - 滚轮缩放走**原生 non-passive 监听**(React 的 root 级 wheel 是 passive,\n * `preventDefault` 无效),缩放锚定光标下的 viewBox 坐标;\n * - `selectedElements` 可受控(传 `options.selectedElements` + `onSelectionChange`)\n * 或非受控(内部自持);\n * - 节点位置可选共享:把 `getNodePosition` / `onNodePositionChange` 传给 `CycleView`\n * 即可多视图共用一套坐标(不传则 Scene 用自身局部态)。\n */\n\nconst DEFAULT_TRANSFORM: CanvasTransform = { x: 0, y: 0, scale: 1 }\nconst DEFAULT_VIEWBOX = { width: 800, height: 600 }\nconst DEFAULT_MIN_SCALE = 0.25\nconst DEFAULT_MAX_SCALE = 8\nconst NOOP = () => {}\n\nexport interface SceneStateOptions {\n /** 初始平移 / 缩放;缺省 `{ x:0, y:0, scale:1 }` */\n initialTransform?: CanvasTransform\n /** 锁定交互(透传给 Scene 的 `locked`;同时禁用本 hook 的平移缩放) */\n locked?: boolean\n /** 滚轮缩放开关;缺省 `true` */\n enableZoom?: boolean\n /** 拖拽平移开关;缺省 `true` */\n enablePan?: boolean\n /** 缩放下限;缺省 `0.25`(与主画布一致) */\n minScale?: number\n /** 缩放上限;缺省 `8` */\n maxScale?: number\n /** 受控选中集合(传入即受控,配合 `onSelectionChange`) */\n selectedElements?: Set<string>\n /** 选中集合变更回调(受控 / 非受控都会触发,便于宿主记录) */\n onSelectionChange?: (next: Set<string>) => void\n /** ResizeObserver 首帧前的兜底尺寸;缺省 `{ width:800, height:600 }` */\n fallbackViewBoxSize?: { width: number; height: number }\n /** 宿主容器附加样式(与内建样式合并,内建优先保证定位/尺寸) */\n hostStyle?: CSSProperties\n /** hover 气泡主题;缺省 `'dark'` */\n theme?: 'dark' | 'light'\n /** hover 气泡自定义渲染;返回 `null` 表示禁用内建气泡 */\n renderHoverBubble?: (el: GroupElement, anchor: { x: number; y: number } | null) => ReactNode\n}\n\n/** 可直接 spread 到四类 2D Scene 的公共受控 props。 */\nexport interface SceneStateProps {\n selectedElements: Set<string>\n canvasTransform: CanvasTransform\n viewBoxSize: { width: number; height: number }\n onSelect: (elId: string, additive: boolean) => void\n onHover: (el: GroupElement | null, anchor?: { x: number; y: number } | null) => void\n}\n\nexport interface SceneState {\n /** 容器实测尺寸(ResizeObserver;首帧为兜底值) */\n viewBoxSize: { width: number; height: number }\n /**\n * 宿主容器的 props —— **一次 spread 即可**:\n *\n * ```tsx\n * const s = useSceneState(group)\n * <div {...s.hostProps}><SetView group={group} {...s.sceneProps} />{s.hoverBubble}</div>\n * ```\n *\n * 内含 `ref`(回调 ref)、内建样式(定位/尺寸/`touchAction`/光标)与拖拽平移事件。\n *\n * ⚠️ 别在 spread 之后再写 `ref`:那会顶掉内建 ref,尺寸测量与悬浮气泡换算会静默失效。\n * 需要 DOM 节点请用 `getHostElement()`。\n *\n * 设计说明:ref 只以**嵌套**形式出现在 `hostProps` 里,绝不作为顶层字段暴露。\n * React Compiler 的 `react-hooks/refs` 规则会把「顶层返回了写 ref 的回调」的 hook\n * 整体判为 ref 载体,此后宿主每次 `s.xxx` 读取都会报「渲染期访问 ref」;\n * 嵌套形式不触发该判定(实测)。\n */\n hostProps: {\n ref: (el: HTMLDivElement | null) => void\n style: CSSProperties\n onMouseDown: (e: React.MouseEvent) => void\n onMouseMove: (e: React.MouseEvent) => void\n onMouseUp: () => void\n onMouseLeave: () => void\n }\n /** 需要 DOM 节点时用(如导出 SVG):取宿主容器元素 */\n getHostElement: () => HTMLDivElement | null\n canvasTransform: CanvasTransform\n setCanvasTransform: (t: CanvasTransform) => void\n selectedElements: Set<string>\n setSelectedElements: (next: Set<string> | ((prev: Set<string>) => Set<string>)) => void\n /** 选中语义:`additive`(⊕/Ctrl/⌘)→ 切换成员;否则 → 单选替换 */\n select: (elId: string, additive?: boolean) => void\n clearSelection: () => void\n /** 当前悬停元素(`onHover` 自动维护) */\n hovered: GroupElement | null\n /** 悬停锚点(viewBox 坐标系下映射到容器内的屏幕坐标) */\n hoverAnchor: { x: number; y: number } | null\n /** 内建 hover 气泡节点(可直接 `{s.hoverBubble}`;想自己画就用 `renderHoverBubble`) */\n hoverBubble: ReactNode\n /** 直接 spread 给 SetView / CycleView / CayleyView / CosetStripScene */\n sceneProps: SceneStateProps\n /** 复位平移缩放 */\n resetTransform: () => void\n /** 以容器中心为锚缩放(按钮用,`factor > 1` 放大) */\n zoomBy: (factor: number) => void\n /** 是否锁定(= `options.locked`) */\n locked: boolean\n /** 共享节点位置:接 `CycleView.getNodePosition` */\n getNodePosition: (elId: string) => NodePosition | undefined\n /** 共享节点位置:接 `CycleView.onNodePositionChange` */\n onNodePositionChange: (elId: string, x: number, y: number) => void\n /** 清空共享节点位置 */\n resetNodePositions: () => void\n}\n\nexport function useSceneState(group?: Group | null, options: SceneStateOptions = {}): SceneState {\n const {\n initialTransform,\n locked = false,\n enableZoom = true,\n enablePan = true,\n minScale = DEFAULT_MIN_SCALE,\n maxScale = DEFAULT_MAX_SCALE,\n selectedElements: controlledSelection,\n onSelectionChange,\n fallbackViewBoxSize,\n hostStyle,\n theme = 'dark',\n renderHoverBubble,\n } = options\n\n const hostRef = useRef<HTMLDivElement | null>(null)\n /** 对外暴露回调 ref:不在渲染期写 ref,也不把 RefObject 塞进返回体 */\n const setHostRef = useCallback((el: HTMLDivElement | null) => { hostRef.current = el }, [])\n const getHostElement = useCallback(() => hostRef.current, [])\n\n // ── 尺寸:ResizeObserver 实测容器 ──\n const [viewBoxSize, setViewBoxSize] = useState(fallbackViewBoxSize ?? DEFAULT_VIEWBOX)\n useEffect(() => {\n const el = hostRef.current\n if (!el) return\n const measure = () => {\n const rect = el.getBoundingClientRect()\n const width = Math.max(1, Math.round(rect.width))\n const height = Math.max(1, Math.round(rect.height))\n setViewBoxSize(prev => (prev.width === width && prev.height === height ? prev : { width, height }))\n }\n measure()\n if (typeof ResizeObserver === 'undefined') {\n globalThis.addEventListener('resize', measure)\n return () => globalThis.removeEventListener('resize', measure)\n }\n const ro = new ResizeObserver(measure)\n ro.observe(el)\n return () => ro.disconnect()\n }, [])\n\n // ── 平移 / 缩放 ──\n const [canvasTransform, setCanvasTransformState] = useState<CanvasTransform>(initialTransform ?? DEFAULT_TRANSFORM)\n // transformRef 是「权威值」:只在事件回调里同步写(渲染期写 ref 会触发\n // react-hooks/refs)。这样滚轮/拖拽读到的永远是最后一次已应用的值,无陈旧窗口。\n const transformRef = useRef(canvasTransform)\n\n const setCanvasTransform = useCallback((t: CanvasTransform) => {\n transformRef.current = t\n setCanvasTransformState(t)\n }, [])\n\n const resetTransform = useCallback(\n () => setCanvasTransform(initialTransform ?? DEFAULT_TRANSFORM),\n [setCanvasTransform, initialTransform],\n )\n\n // 光标处的 viewBox 坐标(反向映射,缩放锚点用)\n const cursorToViewBox = useCallback((clientX: number, clientY: number) => {\n const el = hostRef.current\n const rect = el?.getBoundingClientRect()\n if (!rect) return { x: 0, y: 0 }\n // 指针坐标缺失 / 非有限(合成事件未带 clientX 等)→ 退回容器中心,\n // 免得 NaN 顺着 anchor 污染 canvasTransform(一旦变 NaN 整张图消失且无法自愈)。\n const cx = Number.isFinite(clientX) && Number.isFinite(clientY)\n ? clientX\n : rect.left + rect.width / 2\n const cy = Number.isFinite(clientX) && Number.isFinite(clientY)\n ? clientY\n : rect.top + rect.height / 2\n const svg = el?.querySelector('svg')\n const vb = svg?.viewBox?.baseVal\n const vw = vb && vb.width > 0 ? vb.width : viewBoxSize.width\n const vh = vb && vb.height > 0 ? vb.height : viewBoxSize.height\n const s = Math.min(rect.width / vw, rect.height / vh) || 1\n const offX = (rect.width - vw * s) / 2\n const offY = (rect.height - vh * s) / 2\n const t = transformRef.current\n const px = (cx - rect.left - offX) / s\n const py = (cy - rect.top - offY) / s\n return { x: (px - t.x) / t.scale, y: (py - t.y) / t.scale }\n }, [viewBoxSize])\n\n const zoomAt = useCallback((factor: number, anchor: { x: number; y: number }) => {\n const t = transformRef.current\n // 锚点非有限 → 放弃本次缩放(宁可不动,也不要把 transform 写成 NaN)\n if (!Number.isFinite(anchor.x) || !Number.isFinite(anchor.y)) return\n const next = Math.min(maxScale, Math.max(minScale, t.scale * factor))\n if (next === t.scale) return\n const k = next / t.scale\n setCanvasTransform({\n x: anchor.x - (anchor.x - t.x) * k,\n y: anchor.y - (anchor.y - t.y) * k,\n scale: next,\n })\n }, [setCanvasTransform, minScale, maxScale])\n\n // 滚轮:原生 non-passive(React root 级 wheel 为 passive,preventDefault 无效)\n useEffect(() => {\n const el = hostRef.current\n if (!el || locked || !enableZoom) return\n const onWheel = (e: WheelEvent) => {\n e.preventDefault()\n zoomAt(e.deltaY > 0 ? 0.9 : 1.1, cursorToViewBox(e.clientX, e.clientY))\n }\n el.addEventListener('wheel', onWheel, { passive: false })\n return () => el.removeEventListener('wheel', onWheel)\n }, [locked, enableZoom, zoomAt, cursorToViewBox])\n\n const zoomBy = useCallback((factor: number) => {\n zoomAt(factor, {\n x: (viewBoxSize.width / 2 - transformRef.current.x) / transformRef.current.scale,\n y: (viewBoxSize.height / 2 - transformRef.current.y) / transformRef.current.scale,\n })\n }, [zoomAt, viewBoxSize])\n\n // 拖拽平移(React 合成事件:Scene 内节点 stopPropagation 时不会触发此处)\n const panRef = useRef<{ active: boolean; startX: number; startY: number; ox: number; oy: number }>({\n active: false, startX: 0, startY: 0, ox: 0, oy: 0,\n })\n const [panning, setPanning] = useState(false)\n const panEnabled = enablePan && !locked\n\n const endPan = useCallback(() => {\n if (!panRef.current.active) return\n panRef.current.active = false\n setPanning(false)\n }, [])\n\n const onMouseDown = useCallback((e: React.MouseEvent) => {\n if (!panEnabled || e.button !== 0) return\n panRef.current = {\n active: true, startX: e.clientX, startY: e.clientY,\n ox: transformRef.current.x, oy: transformRef.current.y,\n }\n setPanning(true)\n }, [panEnabled])\n\n const onMouseMove = useCallback((e: React.MouseEvent) => {\n if (!panRef.current.active) return\n const p = panRef.current\n setCanvasTransform({\n x: p.ox + (e.clientX - p.startX),\n y: p.oy + (e.clientY - p.startY),\n scale: transformRef.current.scale,\n })\n }, [setCanvasTransform])\n\n useEffect(() => {\n if (!panning) return\n globalThis.addEventListener('mouseup', endPan)\n return () => globalThis.removeEventListener('mouseup', endPan)\n }, [panning, endPan])\n\n const hostProps = useMemo(() => ({\n ref: setHostRef,\n style: {\n position: 'relative' as const,\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n touchAction: 'none' as const,\n cursor: panEnabled ? (panning ? 'grabbing' : 'grab') : 'default',\n ...hostStyle,\n },\n onMouseDown,\n onMouseMove,\n onMouseUp: endPan,\n onMouseLeave: endPan,\n }), [setHostRef, hostStyle, panEnabled, panning, onMouseDown, onMouseMove, endPan])\n\n // ── 选中 ──\n const [internalSelection, setInternalSelection] = useState<Set<string>>(() => new Set<string>())\n const selectedElements = controlledSelection ?? internalSelection\n\n const commitSelection = useCallback((next: Set<string>) => {\n if (!controlledSelection) setInternalSelection(next)\n onSelectionChange?.(next)\n }, [controlledSelection, onSelectionChange])\n\n const setSelectedElements = useCallback((next: Set<string> | ((prev: Set<string>) => Set<string>)) => {\n const resolved = typeof next === 'function'\n ? next(controlledSelection ?? internalSelection)\n : next\n commitSelection(resolved)\n }, [controlledSelection, internalSelection, commitSelection])\n\n const select = useCallback((elId: string, additive = false) => {\n const current = controlledSelection ?? internalSelection\n if (additive) {\n const next = new Set(current)\n if (next.has(elId)) next.delete(elId)\n else next.add(elId)\n commitSelection(next)\n } else {\n commitSelection(new Set([elId]))\n }\n }, [controlledSelection, internalSelection, commitSelection])\n\n const clearSelection = useCallback(() => commitSelection(new Set<string>()), [commitSelection])\n\n // ── 悬停 ──\n const [hovered, setHovered] = useState<GroupElement | null>(null)\n const [hoverAnchor, setHoverAnchor] = useState<{ x: number; y: number } | null>(null)\n\n const onHover = useCallback((el: GroupElement | null, anchor?: { x: number; y: number } | null) => {\n setHovered(el)\n if (!el || !anchor) {\n setHoverAnchor(null)\n return\n }\n // Scene 给的 anchor 已是 viewport 内屏幕坐标则直接用;否则按 viewBox 坐标换算。\n // 约定:Scene 传的是屏幕坐标(见 CayleyView 文档),此处直接透传。\n setHoverAnchor(anchor)\n }, [])\n\n const hoverBubble = useMemo<ReactNode>(() => {\n if (!hovered) return null\n if (renderHoverBubble) return renderHoverBubble(hovered, hoverAnchor)\n return createElement(SceneHoverBubble, {\n element: hovered,\n anchor: hoverAnchor,\n theme,\n group: group ?? null,\n })\n }, [hovered, hoverAnchor, renderHoverBubble, theme, group])\n\n // ── 共享节点位置 ──\n const [nodePositions, setNodePositions] = useState<Map<string, NodePosition>>(() => new Map())\n const getNodePosition = useCallback((elId: string) => nodePositions.get(elId), [nodePositions])\n const onNodePositionChange = useCallback((elId: string, x: number, y: number) => {\n setNodePositions(prev => {\n const next = new Map(prev)\n next.set(elId, { x, y })\n return next\n })\n }, [])\n const resetNodePositions = useCallback(() => setNodePositions(new Map()), [])\n\n // 换群 → 清掉上一群的会话态(悬停 / 选中 / 节点位置),避免残留 id 命中新群。\n // 用 React 官方的「渲染期校正 state」模式(Storing information from previous renders)\n // 而非 effect:effect 版本要多提交一次渲染,且那一帧仍带着旧群的残留 id。\n const [sessionGroup, setSessionGroup] = useState(group)\n if (sessionGroup !== group) {\n setSessionGroup(group)\n setHovered(null)\n setHoverAnchor(null)\n setNodePositions(new Map())\n if (!controlledSelection) setInternalSelection(new Set<string>())\n }\n\n const sceneProps = useMemo<SceneStateProps>(() => ({\n selectedElements,\n canvasTransform,\n viewBoxSize,\n onSelect: select,\n onHover,\n }), [selectedElements, canvasTransform, viewBoxSize, select, onHover])\n\n return {\n hostProps,\n viewBoxSize,\n getHostElement,\n canvasTransform,\n setCanvasTransform,\n selectedElements,\n setSelectedElements,\n select,\n clearSelection,\n hovered,\n hoverAnchor,\n hoverBubble,\n sceneProps,\n resetTransform,\n zoomBy,\n locked,\n getNodePosition,\n onNodePositionChange,\n resetNodePositions,\n }\n}\n\n/** 无群 / 无操作时的稳定引用(供宿主做默认值,避免每次新建对象触发重渲染)。 */\nexport const SCENE_STATE_NOOP = NOOP\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/Canvas/SceneThemeRoot.tsx","../../../src/utils/texify.ts","../../../src/components/Canvas/SetView.tsx","../../../src/components/Canvas/CycleView.tsx","../../../src/utils/elementRef.ts","../../../src/context/cayleyActions.ts","../../../src/components/Canvas/CayleyView.tsx","../../../src/i18n/translations.ts","../../../src/i18n/I18nContext.tsx","../../../src/i18n/useTranslation.ts","../../../src/components/Canvas/CosetStripScene.tsx","../../../src/utils/download.ts","../../../src/components/Canvas/TableView.tsx","../../../src/components/Canvas/ActionScene.tsx","../../../src/components/Canvas/HomomorphismScene.tsx","../../../src/components/Canvas/SymmetryViewScene.tsx","../../../src/theme/ThemeContext.tsx","../../../src/theme/useTheme.ts","../../../src/utils/cayley3dControls.ts","../../../src/components/Canvas/Cayley3DScene.tsx","../../../src/components/Canvas/SublatticeScene.tsx","../../../src/components/Canvas/SceneWindow.tsx","../../../src/components/Canvas/SceneHoverBubble.tsx","../../../src/hooks/useSceneState.ts"],"sourcesContent":["import type { CSSProperties, ReactNode } from 'react'\n\n/**\n * SceneThemeRoot —— 视图主题作用域(FGVE「主题统一」)。\n *\n * 问题:主应用把主题做成**全局 CSS 变量**(`src/index.css` 的 `:root` /\n * `[data-theme=\"light\"]`);`@groupviz/react` 里 3D 系 Scene 各自带 `theme` prop,\n * 而全部 2D Scene 没有——外部嵌入想「单独把某张图切成浅色」只能靠外层 div 隐式挂\n * `data-theme`,且各视图行为不一致(`dark` / `theme` / 无)。\n *\n * 方案:2D Scene 统一新增 `theme?: 'dark' | 'light'`,内部用本组件包一层。\n * **缺省不传 → 直接渲染 children(零额外 DOM)**,完全保留「跟随外层主题」的既有行为,\n * 因此主应用与既有宿主不受影响;显式传值时才注入 `data-theme` 作用域,\n * 让 `theme.css` 里的浅/深色变量块在该子树内生效。\n */\nexport type SceneTheme = 'dark' | 'light'\n\nexport interface SceneThemeRootProps {\n /** 缺省 `undefined`(不注入作用域,继承外层主题) */\n theme?: SceneTheme\n children: ReactNode\n /** 附加样式(与内建 `width/height:100%` 合并,内建在前) */\n style?: CSSProperties\n className?: string\n}\n\nexport function SceneThemeRoot({ theme, children, style, className }: SceneThemeRootProps) {\n if (!theme) return <>{children}</>\n return (\n <div\n data-theme={theme}\n className={className}\n style={{\n width: '100%',\n height: '100%',\n background: 'var(--bg-canvas, #0a0a14)',\n ...style,\n }}\n >\n {children}\n </div>\n )\n}\n","import katex from 'katex'\n\nconst UNICODE_SUB: Record<string, string> = {\n '₀': '0', '₁': '1', '₂': '2', '₃': '3', '₄': '4',\n '₅': '5', '₆': '6', '₇': '7', '₈': '8', '₉': '9',\n 'ₐ': 'a', 'ₑ': 'e', 'ₒ': 'o', 'ₓ': 'x',\n 'ₙ': 'n', 'ₖ': 'k', 'ₗ': 'l', 'ₘ': 'm',\n}\n\nconst UNICODE_SUPER: Record<string, string> = {\n '⁰': '0', '¹': '1', '²': '2', '³': '3', '⁴': '4',\n '⁵': '5', '⁶': '6', '⁷': '7', '⁸': '8', '⁹': '9',\n '⁺': '+', '⁻': '-',\n}\n\nconst GREEK_MAP: Record<string, string> = {\n 'α': '\\\\alpha', 'β': '\\\\beta', 'γ': '\\\\gamma', 'δ': '\\\\delta',\n 'ε': '\\\\varepsilon', 'ζ': '\\\\zeta', 'η': '\\\\eta', 'θ': '\\\\theta',\n 'ι': '\\\\iota', 'κ': '\\\\kappa', 'λ': '\\\\lambda', 'μ': '\\\\mu',\n 'ν': '\\\\nu', 'ξ': '\\\\xi', 'π': '\\\\pi', 'ρ': '\\\\rho',\n 'σ': '\\\\sigma', 'τ': '\\\\tau', 'υ': '\\\\upsilon', 'φ': '\\\\phi',\n 'χ': '\\\\chi', 'ψ': '\\\\psi', 'ω': '\\\\omega',\n 'Α': 'A', 'Β': 'B', 'Γ': '\\\\Gamma', 'Δ': '\\\\Delta',\n 'Ε': 'E', 'Ζ': 'Z', 'Η': 'H', 'Θ': '\\\\Theta',\n 'Ι': 'I', 'Κ': 'K', 'Λ': '\\\\Lambda', 'Μ': 'M',\n 'Ν': 'N', 'Ξ': '\\\\Xi', 'Π': '\\\\Pi', 'Ρ': 'P',\n 'Σ': '\\\\Sigma', 'Τ': 'T', 'Υ': '\\\\Upsilon', 'Φ': '\\\\Phi',\n 'Χ': 'X', 'Ψ': '\\\\Psi', 'Ω': '\\\\Omega',\n}\n\nconst SPECIAL_MAP: Record<string, string> = {\n '×': '\\\\times',\n '≅': '\\\\cong',\n '→': '\\\\to',\n '∈': '\\\\in',\n '⊲': '\\\\triangleleft',\n 'ℤ': '\\\\mathbb{Z}',\n '⟨': '\\\\langle',\n '⟩': '\\\\rangle',\n '⁻': '^{-1}',\n}\n\nexport function texify(text: string): string {\n let result = ''\n\n for (let i = 0; i < text.length; i++) {\n const ch = text[i]\n const nextCh = i + 1 < text.length ? text[i + 1] : ''\n\n if (SPECIAL_MAP[ch]) {\n const tex = SPECIAL_MAP[ch]\n result += tex\n if (isBareCommand(tex) && isAlpha(nextCh)) {\n result += ' '\n }\n continue\n }\n\n if (GREEK_MAP[ch]) {\n const tex = GREEK_MAP[ch]\n result += tex\n if (isBareCommand(tex) && isAlpha(nextCh)) {\n result += ' '\n }\n continue\n }\n\n if (UNICODE_SUB[ch]) {\n result += '_{' + UNICODE_SUB[ch]\n let j = i + 1\n while (j < text.length && UNICODE_SUB[text[j]]) {\n result += UNICODE_SUB[text[j]]\n j++\n }\n result += '}'\n i = j - 1\n continue\n }\n\n if (UNICODE_SUPER[ch]) {\n result += '^{' + UNICODE_SUPER[ch]\n let j = i + 1\n while (j < text.length && UNICODE_SUPER[text[j]]) {\n result += UNICODE_SUPER[text[j]]\n j++\n }\n result += '}'\n i = j - 1\n continue\n }\n\n result += ch\n }\n\n return result\n}\n\nfunction isBareCommand(tex: string): boolean {\n if (!tex.startsWith('\\\\')) return false\n if (tex.length < 2) return false\n for (let i = 1; i < tex.length; i++) {\n const c = tex[i]\n if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) return false\n }\n return true\n}\n\nfunction isAlpha(ch: string): boolean {\n if (!ch) return false\n return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')\n}\n\nexport function renderTex(math: string, displayMode = false): string {\n try {\n return katex.renderToString(math, {\n displayMode,\n throwOnError: false,\n trust: false,\n strict: false,\n })\n } catch {\n return `<span class=\"tex-error\">${math}</span>`\n }\n}\n","import { useMemo } from 'react'\nimport { SceneThemeRoot, type SceneTheme } from './SceneThemeRoot'\nimport { texify, renderTex } from '../../utils/texify'\nimport type { Group } from '../../core/types'\nimport type { InternalEdgeData } from '../../core/types'\n\nexport interface SetViewProps {\n group: Group | null\n selectedElements: Set<string>\n canvasTransform: { x: number; y: number; scale: number }\n viewBoxSize: { width: number; height: number }\n subsets?: Array<{ elementIds: string[]; color: string }>\n selfInverseElementId?: string | null\n cosetElementMap?: Map<string, number>\n cosetHighlightSet?: Set<number>\n cosetColors?: string[]\n onSelect?: (elId: string, additive: boolean) => void\n onHover?: (el: Group['elements'][number] | null, anchor?: { x: number; y: number } | null) => void\n noGroupText?: string\n nodeRadius?: number\n gap?: number\n columns?: number\n showLabels?: boolean\n /** 节点标签自适应阈值:`group.order > 该值` 时仅选中节点显示常驻标签;缺省 60(主画布规则) */\n largeGroupThreshold?: number\n /** 视图主题作用域(`'dark' | 'light'`)。缺省不注入、跟随外层主题;显式传值时在本子树内\n * 应用 `theme.css` 对应变量块(需宿主已 `import '@groupviz/react/theme.css'`) */\n theme?: SceneTheme\n}\n\nexport function SetView(props: SetViewProps) {\n return (\n <SceneThemeRoot theme={props.theme}>\n <SetViewBody {...props} />\n </SceneThemeRoot>\n )\n}\n\nconst INNER_NODE_COLORS = [\n '#ff6b6b','#4ecdc4','#ffd93d','#a78bfa','#f97316','#06b6d4',\n '#84cc16','#f43f5e','#38bdf8','#a855f7','#14b8a6','#eab308',\n '#6366f1','#ec4899','#0ea5e9','#22c55e',\n]\n\nfunction renderCompoundNode(\n el: { cosetMemberLabels?: string[]; cosetInternalEdges?: InternalEdgeData[]; cosetInternalLayout?: { x: number; y: number }[] },\n outerR: number,\n isSelected: boolean,\n fillColor: string,\n strokeColor: string,\n strokeWidth: number,\n showInternalEdges: boolean = true,\n) {\n const members = el.cosetMemberLabels!\n const maxShow = 12\n const showCount = Math.min(members.length, maxShow)\n const innerR = Math.min(10, Math.max(4, Math.floor(outerR / (Math.max(3, Math.sqrt(showCount)) * 1.8))))\n const layoutScale = outerR * 0.72\n\n const hasLayout = el.cosetInternalLayout && el.cosetInternalLayout.length >= showCount\n const innerPos = (idx: number) => {\n if (hasLayout) {\n const p = el.cosetInternalLayout![idx]\n return { x: p.x * layoutScale, y: p.y * layoutScale }\n }\n const angle = (idx / showCount) * 2 * Math.PI - Math.PI / 2\n return {\n x: Math.cos(angle) * (outerR * 0.55),\n y: Math.sin(angle) * (outerR * 0.55),\n }\n }\n\n const circles = []\n for (let i = 0; i < showCount; i++) {\n const pos = innerPos(i)\n circles.push(\n <circle\n key={i}\n cx={pos.x}\n cy={pos.y}\n r={innerR}\n fill={INNER_NODE_COLORS[i % INNER_NODE_COLORS.length]}\n stroke=\"var(--node-stroke)\"\n strokeWidth={0.8}\n />\n )\n }\n\n const internalEdges = showInternalEdges ? el.cosetInternalEdges : undefined\n const edgeElements: React.ReactNode[] = []\n if (internalEdges && internalEdges.length > 0) {\n for (let i = 0; i < internalEdges.length; i++) {\n const edge = internalEdges[i]\n if (edge.fromInnerIdx >= showCount || edge.toInnerIdx >= showCount) continue\n const from = innerPos(edge.fromInnerIdx)\n const to = innerPos(edge.toInnerIdx)\n const dx = to.x - from.x\n const dy = to.y - from.y\n const dist = Math.sqrt(dx * dx + dy * dy)\n if (dist < 0.1) continue\n const ux = dx / dist\n const uy = dy / dist\n const sx = from.x + ux * innerR\n const sy = from.y + uy * innerR\n const ex = to.x - ux * innerR\n const ey = to.y - uy * innerR\n const midX = (sx + ex) / 2\n const midY = (sy + ey) / 2\n\n const edgeTitle = edge.actionLabel || edge.actionElementId || ''\n const titleEl = edgeTitle ? <title>{edgeTitle}</title> : null\n if (edge.isBidirectional) {\n edgeElements.push(\n <g key={`edge-${i}`}>\n <line\n x1={sx} y1={sy} x2={ex} y2={ey}\n stroke={edge.color}\n strokeWidth={1.5}\n strokeOpacity={0.75}\n strokeLinecap=\"round\"\n >{titleEl}</line>\n <line\n x1={sx} y1={sy} x2={ex} y2={ey}\n stroke=\"transparent\"\n strokeWidth={8}\n strokeLinecap=\"round\"\n style={{ pointerEvents: 'stroke' }}\n >{titleEl}</line>\n </g>\n )\n } else {\n const curveOffset = 2.5\n const nx = -uy * curveOffset\n const ny = ux * curveOffset\n const c1x = midX + nx\n const c1y = midY + ny\n const arrowSize = 2.5\n edgeElements.push(\n <g key={`edge-${i}`}>\n <path\n d={`M${sx},${sy} Q${c1x},${c1y} ${ex},${ey}`}\n stroke={edge.color}\n strokeWidth={1.5}\n strokeOpacity={0.75}\n fill=\"none\"\n >{titleEl}</path>\n <path\n d={`M${sx},${sy} Q${c1x},${c1y} ${ex},${ey}`}\n stroke=\"transparent\"\n strokeWidth={8}\n fill=\"none\"\n style={{ pointerEvents: 'stroke' }}\n >{titleEl}</path>\n </g>\n )\n const ax = ex - c1x\n const ay = ey - c1y\n const alen = Math.sqrt(ax * ax + ay * ay) || 1\n const aux = ax / alen\n const auy = ay / alen\n edgeElements.push(\n <polygon\n key={`arrow-${i}`}\n points={`${ex},${ey} ${ex - aux * arrowSize + auy * arrowSize * 0.5},${ey - auy * arrowSize - aux * arrowSize * 0.5} ${ex - aux * arrowSize - auy * arrowSize * 0.5},${ey - auy * arrowSize + aux * arrowSize * 0.5}`}\n fill={edge.color}\n stroke={edge.color}\n strokeWidth={0.5}\n />\n )\n }\n }\n }\n\n return (\n <>\n <circle\n r={outerR}\n fill={fillColor}\n stroke={strokeColor}\n strokeWidth={strokeWidth}\n strokeDasharray={isSelected ? undefined : \"4 2\"}\n filter=\"url(#node-shadow)\"\n />\n {edgeElements}\n {circles}\n {members.length > maxShow && (\n <text\n x={0} y={outerR - 2}\n textAnchor=\"middle\"\n fill=\"var(--text-secondary)\"\n fontSize={10}\n >\n +{members.length - maxShow}\n </text>\n )}\n </>\n )\n}\n\nfunction SetViewBody({\n group,\n selectedElements,\n canvasTransform,\n viewBoxSize,\n subsets,\n selfInverseElementId,\n cosetElementMap,\n cosetHighlightSet,\n cosetColors,\n onSelect,\n onHover,\n noGroupText,\n nodeRadius: nodeRadiusOverride,\n gap: gapOverride,\n columns: columnsOverride,\n showLabels: showLabelsOverride,\n largeGroupThreshold = 60,\n}: SetViewProps) {\n type SubsetView = { elementIds: string[]; color: string }\n const subsetDetailMap = useMemo(() => {\n const m = new Map<string, SubsetView>()\n subsets?.forEach(s => s.elementIds.forEach(id => { if (!m.has(id)) m.set(id, s) }))\n return m\n }, [subsets])\n\n // KaTeX 标签 HTML 开销大:每群只渲染一次(与 CayleyView 的 labelHtmlCache 一致)\n const labelHtmlCache = useMemo(() => {\n const m = new Map<string, string>()\n group?.elements.forEach(el => m.set(el.id, renderTex(texify(el.label))))\n return m\n }, [group])\n\n const cosetPalette = cosetColors ?? []\n\n if (!group) {\n return (\n <div className=\"view-empty\">\n <p>{noGroupText ?? ''}</p>\n </div>\n )\n }\n\n const isLarge = group.order > largeGroupThreshold\n const hasCompoundNodes = group.elements.some(el => el.cosetMemberLabels && el.cosetMemberLabels.length > 0)\n const nodeRadius = nodeRadiusOverride ?? (hasCompoundNodes ? 72 : 26)\n const gap = gapOverride ?? (hasCompoundNodes ? 12 : 8)\n const cellSize = nodeRadius * 2 + gap\n const cols = columnsOverride\n ? columnsOverride > 0 ? columnsOverride : Math.ceil(Math.sqrt(group.order))\n : hasCompoundNodes\n ? Math.min(group.order, Math.max(1, Math.floor(viewBoxSize.width / cellSize)))\n : Math.ceil(Math.sqrt(group.order))\n const rows = group.order / cols\n const totalWidth = cols * cellSize\n const totalHeight = rows * cellSize\n const startX = Math.max(nodeRadius, (viewBoxSize.width - totalWidth) / 2 + cellSize / 2)\n const startY = Math.max(nodeRadius, (viewBoxSize.height - totalHeight) / 2 + cellSize / 2)\n\n const getPos = (_elId: string, index: number) => {\n const col = index % cols\n const row = Math.floor(index / cols)\n return {\n x: startX + col * cellSize,\n y: startY + row * cellSize\n }\n }\n\n // Viewport culling for large groups — skip off-screen nodes\n const isNodeOnScreen = (px: number, py: number) => {\n if (!isLarge) return true\n const sx = px * canvasTransform.scale + canvasTransform.x\n const sy = py * canvasTransform.scale + canvasTransform.y\n const m = nodeRadius * canvasTransform.scale * 1.5\n return sx + m > 0 && sx - m < viewBoxSize.width &&\n sy + m > 0 && sy - m < viewBoxSize.height\n }\n\n return (\n <svg viewBox={`0 0 ${viewBoxSize.width} ${viewBoxSize.height}`} className=\"view-svg\" style={{ userSelect: 'none' }}>\n {!isLarge && (\n <defs>\n <filter id=\"node-shadow\" x=\"-30%\" y=\"-30%\" width=\"160%\" height=\"160%\">\n <feDropShadow dx=\"0\" dy=\"2\" stdDeviation=\"3\" floodColor=\"#000000\" floodOpacity=\"0.25\" />\n </filter>\n </defs>\n )}\n <g transform={`translate(${canvasTransform.x}, ${canvasTransform.y}) scale(${canvasTransform.scale})`}>\n {group.elements.map((el, i) => {\n const pos = getPos(el.id, i)\n if (!isNodeOnScreen(pos.x, pos.y)) return null\n const isSelected = selectedElements.has(el.id)\n const parentSubset = subsetDetailMap.get(el.id)\n const cosetIdx = cosetElementMap?.get(el.id)\n const isInHighlightedCoset = cosetIdx !== undefined && (cosetHighlightSet?.has(cosetIdx) ?? false)\n \n let fillColor = 'var(--node-fill)'\n let strokeColor = 'var(--node-stroke)'\n let strokeWidth = 2.5\n \n if (isSelected) {\n fillColor = 'var(--node-fill-selected)'\n strokeColor = '#ffd93d'\n strokeWidth = 3\n } else if (isInHighlightedCoset && cosetIdx !== undefined && cosetPalette[cosetIdx]) {\n fillColor = cosetPalette[cosetIdx] + '33'\n strokeColor = cosetPalette[cosetIdx]\n strokeWidth = 3\n } else if (parentSubset) {\n fillColor = parentSubset.color + '33'\n strokeColor = parentSubset.color\n strokeWidth = 2.5\n }\n \n const isCompound = !!(el.cosetMemberLabels && el.cosetMemberLabels.length > 0)\n \n return (\n <g\n key={el.id}\n transform={`translate(${pos.x}, ${pos.y})`}\n onClick={(e) => {\n e.stopPropagation()\n onSelect?.(el.id, e.ctrlKey || e.metaKey)\n }}\n onMouseEnter={() => onHover?.(el, { x: pos.x * canvasTransform.scale + canvasTransform.x, y: pos.y * canvasTransform.scale + canvasTransform.y })}\n onMouseLeave={() => onHover?.(null, null)}\n style={{ cursor: 'pointer' }}\n >\n {isCompound ? (\n renderCompoundNode(el, nodeRadius, isSelected, fillColor, strokeColor, strokeWidth, true)\n ) : (\n <>\n <circle\n r={nodeRadius}\n fill={fillColor}\n stroke={strokeColor}\n strokeWidth={strokeWidth}\n filter={isLarge ? undefined : \"url(#node-shadow)\"}\n />\n {isInHighlightedCoset && cosetIdx !== undefined && cosetPalette[cosetIdx] && (\n <circle\n r={nodeRadius}\n fill={`${cosetPalette[cosetIdx]}22`}\n stroke=\"none\"\n />\n )}\n {parentSubset && (\n <circle\n r={nodeRadius}\n fill={`${parentSubset.color}22`}\n stroke=\"none\"\n />\n )}\n{showLabelsOverride !== false && (!isLarge || isSelected || selectedElements.size === 0) && (\n <foreignObject\n x={-nodeRadius}\n y={-16}\n width={nodeRadius * 2}\n height={32}\n style={{ pointerEvents: 'none', userSelect: 'none' }}\n >\n <div\n style={{\n display: 'flex', alignItems: 'center', justifyContent: 'center',\n width: '100%', height: '100%', color: 'var(--node-text)', fontSize: isLarge ? '10px' : '15px'\n }}\n dangerouslySetInnerHTML={{\n __html: labelHtmlCache.get(el.id) ?? ''\n }}\n />\n </foreignObject>\n )}\n </>\n )}\n {isInHighlightedCoset && cosetIdx !== undefined && cosetPalette[cosetIdx] && isCompound && (\n <circle\n r={nodeRadius + 2}\n fill={`${cosetPalette[cosetIdx]}22`}\n stroke=\"none\"\n />\n )}\n {parentSubset && isCompound && (\n <circle\n r={nodeRadius + 2}\n fill={`${parentSubset.color}22`}\n stroke=\"none\"\n />\n )}\n {selfInverseElementId === el.id && (\n <g>\n <circle r={nodeRadius + 6} fill=\"none\" stroke=\"#ffd93d\" strokeWidth={2.5} strokeDasharray=\"6 3\" opacity={0.85}>\n <animate attributeName=\"stroke-dashoffset\" from=\"0\" to=\"-18\" dur=\"0.8s\" repeatCount=\"indefinite\" />\n </circle>\n <path\n d={`M ${nodeRadius + 3},-8 L ${nodeRadius + 14},-5 L ${nodeRadius + 10},-1`}\n fill=\"#ffd93d\"\n opacity={0.85}\n />\n </g>\n )}\n </g>\n )\n })}\n </g>\n </svg>\n )\n}\n","import { useCallback, useMemo, useState } from 'react'\nimport { SceneThemeRoot, type SceneTheme } from './SceneThemeRoot'\nimport { cycleGraphLayout, circleLayoutRadius } from '../../core/algebra/forceLayout'\nimport { texify, renderTex } from '../../utils/texify'\nimport type { CanvasTransform, Group, GroupElement, NodePosition } from '../../core/types'\n\nexport interface CycleViewProps {\n group: Group | null\n selectedElements: Set<string>\n canvasTransform: CanvasTransform\n viewBoxSize: { width: number; height: number }\n /** 缺省 false(显示全部循环子群);true 时仅显示极大循环并启用 planar 布局 */\n showMaximalCycles?: boolean\n /** 节点半径;缺省 24 */\n nodeRadius?: number\n /** 是否显示节点标签;缺省 true(>60 阶自适应) */\n showLabels?: boolean\n /** 是否显示每个循环的 ⟨g⟩ ≅ Z_n 标注;缺省 true */\n showCycleLabels?: boolean\n /** 缺省 false;true 时禁用节点拖拽(供 ViewWindow 锁定状态使用,点击选中仍保留) */\n locked?: boolean\n /** 子集着色(子集→元素映射);缺省空 */\n subsets?: Array<{ elementIds: string[]; color: string }>\n selfInverseElementId?: string | null\n cosetElementMap?: Map<string, number>\n cosetHighlightSet?: Set<number>\n cosetColors?: string[]\n /** 外部持久化节点位置(主画布共享位置);缺省使用本地拖拽态 */\n getNodePosition?: (elId: string) => NodePosition | undefined\n /** 拖拽回写节点位置;缺省写入本地拖拽态 */\n onNodePositionChange?: (elId: string, x: number, y: number) => void\n onSelect?: (elId: string, additive: boolean) => void\n onHover?: (el: GroupElement | null, anchor?: { x: number; y: number } | null) => void\n noGroupText?: string\n /** 节点标签自适应阈值:`group.order > 该值` 时仅选中节点显示常驻标签;缺省 60(主画布规则) */\n largeGroupThreshold?: number\n /** 视图主题作用域(`'dark' | 'light'`)。缺省不注入、跟随外层主题;显式传值时在本子树内\n * 应用 `theme.css` 对应变量块(需宿主已 `import '@groupviz/react/theme.css'`) */\n theme?: SceneTheme\n}\n\nexport function CycleView(props: CycleViewProps) {\n return (\n <SceneThemeRoot theme={props.theme}>\n <CycleViewBody {...props} />\n </SceneThemeRoot>\n )\n}\n\ninterface CycleEntry {\n generatorId: string\n generatorLabel: string\n elements: { id: string; label: string }[]\n order: number\n}\n\n// 每实例唯一前缀:同一文档内多个窗口 + 主画布的 <defs> filter id 不冲突\nlet _cycleViewInst = 0\n\nconst CYCLE_COLORS = ['#ff6b6b', '#4ecdc4', '#ffd93d', '#6bcb77', '#9b59b6', '#3498db', '#e67e22']\n\nfunction CycleViewBody({\n group,\n selectedElements,\n canvasTransform,\n viewBoxSize,\n showMaximalCycles = true,\n nodeRadius = 24,\n showLabels = true,\n showCycleLabels = true,\n locked = false,\n subsets,\n selfInverseElementId,\n cosetElementMap,\n cosetHighlightSet,\n cosetColors,\n getNodePosition,\n onNodePositionChange,\n onSelect,\n onHover,\n noGroupText,\n largeGroupThreshold = 60,\n}: CycleViewProps) {\n // 惰性初始化的每实例唯一前缀(useState 初始化器每实例只执行一次)\n const [filterPrefix] = useState(() => `cyv${++_cycleViewInst}`)\n\n // 本地拖拽覆盖位置(ViewWindow 无外部存储时使用)\n const posKey = group ? `${group.symbol}|${group.order}|${showMaximalCycles}` : ''\n const [dragState, setDragState] = useState<{ key: string; map: Map<string, NodePosition> }>({\n key: posKey,\n map: new Map(),\n })\n if (dragState.key !== posKey) {\n setDragState({ key: posKey, map: new Map() })\n }\n const localDragPositions = useMemo(\n () => (dragState.key === posKey ? dragState.map : new Map<string, NodePosition>()),\n [dragState, posKey],\n )\n const setLocalDragPosition = useCallback((elId: string, pos: NodePosition) => {\n setDragState(prev => {\n if (prev.key !== posKey) return prev\n const map = new Map(prev.map)\n map.set(elId, pos)\n return { key: prev.key, map }\n })\n }, [posKey])\n\n const cycles = useMemo<CycleEntry[]>(() => {\n if (!group) return []\n\n const allCycles: CycleEntry[] = []\n const visitedKeys = new Set<string>()\n\n for (const el of group.elements) {\n const subgroup: { id: string; label: string }[] = []\n const seen = new Set<string>()\n let current = el\n\n while (!seen.has(current.id)) {\n seen.add(current.id)\n subgroup.push({ id: current.id, label: current.label })\n current = group.multiply(current, el)\n }\n\n if (subgroup.length > 1) {\n const key = subgroup.map(e => e.id).sort().join(',')\n if (!visitedKeys.has(key)) {\n visitedKeys.add(key)\n allCycles.push({\n generatorId: el.id,\n generatorLabel: el.label,\n elements: subgroup,\n order: subgroup.length,\n })\n }\n }\n }\n\n if (!showMaximalCycles) {\n return allCycles.sort((a, b) => a.order - b.order)\n }\n\n const maximalCycles = allCycles.filter(cycle => {\n const cycleSet = new Set(cycle.elements.map(e => e.id))\n return !allCycles.some(other => {\n if (other.generatorId === cycle.generatorId) return false\n const otherSet = new Set(other.elements.map(e => e.id))\n return [...cycleSet].every(id => otherSet.has(id))\n })\n })\n\n return maximalCycles.sort((a, b) => a.order - b.order)\n }, [group, showMaximalCycles])\n\n const planarPositions = useMemo(() => {\n if (!group || !showMaximalCycles || cycles.length === 0) return null\n return cycleGraphLayout(\n group.elements,\n cycles.map(c => ({ elementIds: c.elements.map(e => e.id) })),\n viewBoxSize.width,\n viewBoxSize.height,\n group.identity.id,\n )\n }, [group, showMaximalCycles, cycles, viewBoxSize.width, viewBoxSize.height])\n\n const subsetDetailMap = useMemo(() => {\n const m = new Map<string, { elementIds: string[]; color: string }>()\n subsets?.forEach(s => s.elementIds.forEach(id => { if (!m.has(id)) m.set(id, s) }))\n return m\n }, [subsets])\n\n const cosetPalette = cosetColors ?? []\n\n const labelHtmlCache = useMemo(() => {\n const m = new Map<string, string>()\n group?.elements.forEach(el => m.set(el.id, renderTex(texify(el.label))))\n return m\n }, [group])\n\n if (!group) {\n return (\n <div className=\"view-empty\">\n <p>{noGroupText ?? ''}</p>\n </div>\n )\n }\n\n const isLarge = group.order > largeGroupThreshold\n const isNodeOnScreen = (px: number, py: number) => {\n if (!isLarge) return true\n const sx = px * canvasTransform.scale + canvasTransform.x\n const sy = py * canvasTransform.scale + canvasTransform.y\n const m = nodeRadius * canvasTransform.scale * 1.5\n return sx + m > 0 && sx - m < viewBoxSize.width &&\n sy + m > 0 && sy - m < viewBoxSize.height\n }\n\n const cx = viewBoxSize.width / 2\n const cy = viewBoxSize.height / 2\n const graphRadius = circleLayoutRadius(viewBoxSize.width, viewBoxSize.height, group.order, nodeRadius, {\n widthFactor: 0.32,\n base: 160,\n growth: 16,\n })\n\n const getPos = (elId: string): NodePosition => {\n const external = getNodePosition?.(elId)\n if (external) return external\n\n const local = localDragPositions.get(elId)\n if (local) return local\n\n if (planarPositions) {\n const p = planarPositions.get(elId)\n if (p) return p\n }\n\n const idx = group.elements.findIndex(e => e.id === elId)\n const angle = (idx * 2 * Math.PI / group.order) - Math.PI / 2\n return {\n x: cx + graphRadius * Math.cos(angle),\n y: cy + graphRadius * Math.sin(angle),\n }\n }\n\n return (\n <svg viewBox={`0 0 ${viewBoxSize.width} ${viewBoxSize.height}`} className=\"view-svg\" style={{ userSelect: 'none' }}>\n {!isLarge && (\n <defs>\n <filter id={`${filterPrefix}-node-shadow`} x=\"-30%\" y=\"-30%\" width=\"160%\" height=\"160%\">\n <feDropShadow dx=\"0\" dy=\"2\" stdDeviation=\"3\" floodColor=\"#000000\" floodOpacity=\"0.25\" />\n </filter>\n </defs>\n )}\n <g transform={`translate(${canvasTransform.x}, ${canvasTransform.y}) scale(${canvasTransform.scale})`}>\n {cycles.map((cycle, cycleIdx) => {\n const positions = cycle.elements.map(el => getPos(el.id))\n if (positions.length < 2) return null\n const pathD = positions.map((p, i) =>\n i === 0 ? `M ${p.x} ${p.y}` : `L ${p.x} ${p.y}`\n ).join(' ') + ' Z'\n\n const isHighlighted =\n selectedElements.size > 0 && cycle.elements.some(el => selectedElements.has(el.id))\n const cycleColor = CYCLE_COLORS[cycleIdx % CYCLE_COLORS.length]\n\n if (showMaximalCycles) {\n // GE 风格:细实线,无填充、无虚线、无 ⟨g⟩≅Z_n 标注;2 阶循环画成线段\n // 高亮模式(窗口点击元素后显示它所在的循环):彩色填充 + 加粗 + ⟨g⟩≅Z_n 标注\n if (positions.length === 2) {\n return (\n <line\n key={cycleIdx}\n x1={positions[0].x}\n y1={positions[0].y}\n x2={positions[1].x}\n y2={positions[1].y}\n stroke={isHighlighted ? cycleColor : 'var(--text-muted)'}\n strokeWidth={isHighlighted ? 4 : 1.5}\n strokeLinecap=\"round\"\n />\n )\n }\n const midX = positions.reduce((s, p) => s + p.x, 0) / positions.length\n const midY = positions.reduce((s, p) => s + p.y, 0) / positions.length\n return (\n <g key={cycleIdx}>\n <path\n d={pathD}\n fill={isHighlighted ? cycleColor : 'none'}\n fillOpacity={isHighlighted ? 0.18 : undefined}\n stroke={isHighlighted ? cycleColor : 'var(--text-muted)'}\n strokeWidth={isHighlighted ? 4 : 1.5}\n strokeLinejoin=\"round\"\n />\n {isHighlighted && showCycleLabels && (\n <text\n x={midX}\n y={midY - 12}\n textAnchor=\"middle\"\n fill={cycleColor}\n fontSize={10}\n fontFamily=\"serif\"\n >\n {'⟨'}{cycle.generatorLabel}{'⟩ ≅ Z'}{cycle.order}\n </text>\n )}\n </g>\n )\n }\n\n // 非极大模式:保留彩色虚线 + 循环标注(诊断对比用)\n if (!showCycleLabels) return null\n const color = CYCLE_COLORS[cycleIdx % CYCLE_COLORS.length]\n const pcx = positions.reduce((sum, p) => sum + p.x, 0) / positions.length\n const pcy = positions.reduce((sum, p) => sum + p.y, 0) / positions.length\n return (\n <g key={cycleIdx}>\n <path\n d={pathD}\n fill=\"none\"\n stroke={color}\n strokeWidth={2}\n strokeDasharray=\"6\"\n opacity={0.5}\n />\n <circle cx={pcx} cy={pcy} r={8} fill={color} opacity={0.3} />\n <text x={pcx} y={pcy - 12} textAnchor=\"middle\" fill={color} fontSize={10} fontFamily=\"serif\">\n {'⟨'}{cycle.generatorLabel}{'⟩ ≅ Z'}{cycle.order}\n </text>\n </g>\n )\n })}\n\n {group.elements.map((el) => {\n const pos = getPos(el.id)\n if (!isNodeOnScreen(pos.x, pos.y)) return null\n const isSelected = selectedElements.has(el.id)\n const parentSubset = subsetDetailMap.get(el.id)\n const cosetIdx = cosetElementMap?.get(el.id)\n const isInHighlightedCoset = cosetIdx !== undefined && (cosetHighlightSet?.has(cosetIdx) ?? false)\n\n let fillColor = 'var(--node-fill)'\n let strokeColor = 'var(--node-stroke)'\n let strokeWidth = 2.5\n\n if (isSelected) {\n fillColor = 'var(--node-fill-selected)'\n strokeColor = '#ffd93d'\n strokeWidth = 3\n } else if (isInHighlightedCoset && cosetIdx !== undefined && cosetPalette[cosetIdx]) {\n fillColor = cosetPalette[cosetIdx] + '33'\n strokeColor = cosetPalette[cosetIdx]\n strokeWidth = 3\n } else if (parentSubset) {\n fillColor = parentSubset.color + '33'\n strokeColor = parentSubset.color\n strokeWidth = 2.5\n }\n\n return (\n <g\n key={el.id}\n transform={`translate(${pos.x}, ${pos.y})`}\n onClick={(e) => {\n e.stopPropagation()\n onSelect?.(el.id, e.ctrlKey || e.metaKey)\n }}\n onMouseDown={(e) => {\n if (locked) return\n if (e.button !== 0) return\n e.stopPropagation()\n const svg = e.currentTarget.closest('svg')\n if (!svg) return\n const svgRect = svg.getBoundingClientRect()\n if (svgRect.width === 0 || svgRect.height === 0) return\n const scaleX = viewBoxSize.width / svgRect.width\n const scaleY = viewBoxSize.height / svgRect.height\n\n const startX = (e.clientX - svgRect.left) * scaleX\n const startY = (e.clientY - svgRect.top) * scaleY\n const startPos = getPos(el.id)\n\n const handleMove = (moveEvent: MouseEvent) => {\n const currentX = (moveEvent.clientX - svgRect.left) * scaleX\n const currentY = (moveEvent.clientY - svgRect.top) * scaleY\n const newX = startPos.x + (currentX - startX) / canvasTransform.scale\n const newY = startPos.y + (currentY - startY) / canvasTransform.scale\n if (onNodePositionChange) onNodePositionChange(el.id, newX, newY)\n else setLocalDragPosition(el.id, { x: newX, y: newY })\n }\n\n const handleUp = () => {\n window.removeEventListener('mousemove', handleMove)\n window.removeEventListener('mouseup', handleUp)\n }\n\n window.addEventListener('mousemove', handleMove)\n window.addEventListener('mouseup', handleUp)\n }}\n onMouseEnter={() => onHover?.(el, { x: pos.x * canvasTransform.scale + canvasTransform.x, y: pos.y * canvasTransform.scale + canvasTransform.y })}\n onMouseLeave={() => onHover?.(null, null)}\n style={{ cursor: 'grab' }}\n >\n <circle\n r={nodeRadius}\n fill={fillColor}\n stroke={strokeColor}\n strokeWidth={strokeWidth}\n filter={isLarge ? undefined : `url(#${filterPrefix}-node-shadow)`}\n />\n {parentSubset && (\n <circle\n r={nodeRadius}\n fill={`${parentSubset.color}22`}\n stroke=\"none\"\n />\n )}\n {isInHighlightedCoset && cosetIdx !== undefined && cosetPalette[cosetIdx] && (\n <circle\n r={nodeRadius}\n fill={`${cosetPalette[cosetIdx]}22`}\n stroke=\"none\"\n />\n )}\n {showLabels && (!isLarge || isSelected || selectedElements.size === 0) && (\n <foreignObject\n x={-nodeRadius}\n y={-15}\n width={nodeRadius * 2}\n height={30}\n style={{ pointerEvents: 'none', userSelect: 'none' }}\n >\n <div\n style={{\n display: 'flex', alignItems: 'center', justifyContent: 'center',\n width: '100%', height: '100%', color: 'var(--node-text)', fontSize: isLarge ? '10px' : '14px'\n }}\n dangerouslySetInnerHTML={{\n __html: labelHtmlCache.get(el.id) ?? ''\n }}\n />\n </foreignObject>\n )}\n {selfInverseElementId === el.id && (\n <g>\n <circle r={nodeRadius + 6} fill=\"none\" stroke=\"#ffd93d\" strokeWidth={2.5} strokeDasharray=\"6 3\" opacity={0.85}>\n <animate attributeName=\"stroke-dashoffset\" from=\"0\" to=\"-18\" dur=\"0.8s\" repeatCount=\"indefinite\" />\n </circle>\n <path\n d={`M ${nodeRadius + 3},-8 L ${nodeRadius + 14},-5 L ${nodeRadius + 10},-1`}\n fill=\"#ffd93d\"\n opacity={0.85}\n />\n </g>\n )}\n </g>\n )\n })}\n </g>\n </svg>\n )\n}\n","import type { Group, GroupElement } from '../core/types'\nimport { resolveElement } from '../core/algebra/elementRef'\n\n/**\n * 元素引用解析的「告警版」——把此前的**静默失败**变成一次可见的 `console.warn`。\n *\n * 用于所有「宿主经 props 传元素引用」的入口(`actionElementId` / `actions[].elementId` /\n * 陪集 H 列表 / `subsets[].elementIds`):解析不到时不再假装无事发生,而是:\n * 1. 返回 `null`,让组件走「忽略该项」的既有降级路径(渲染不炸,与反馈要求的 warn+忽略一致);\n * 2. 按 `上下文 + 群 + 引用` 去重后 `console.warn` 一次(避免每帧刷屏)。\n *\n * 需要判断「有没有解析到」但不想告警时,直接用 core 的 `resolveElement`。\n */\nconst warned = new Set<string>()\n\n/** 清空去重缓存(测试用;宿主一般不需要调用)。 */\nexport function clearElementRefWarnCache(): void {\n warned.clear()\n}\n\nexport function resolveElementWarn(\n group: Group | null | undefined,\n ref: string | null | undefined,\n context: string,\n): GroupElement | null {\n const el = resolveElement(group, ref)\n if (el) return el\n // 群本身缺席(尚未载入 / 已卸载)或引用为空属正常态,不是错误,不告警\n if (!group || ref == null || ref === '') return null\n const key = `${context}|${group.symbol}|${ref}`\n if (!warned.has(key)) {\n warned.add(key)\n console.warn(\n `[groupviz] ${context}: 元素引用 ${JSON.stringify(ref)} 在群 ${group?.symbol ?? '?'} 中解析不到` +\n `(已试 id / label / value / 循环记号四种写法),该项已忽略。`\n )\n }\n return null\n}\n\n/**\n * 批量解析元素引用(`subsets[].elementIds` / 陪集 H 这类数组入参)。\n * 保留顺序、去重、丢掉未命中项,并逐项走一次去重告警。\n */\nexport function resolveElementIdsWarn(\n group: Group | null | undefined,\n refs: readonly string[] | null | undefined,\n context: string,\n): string[] {\n if (!refs) return []\n const out: string[] = []\n const seen = new Set<string>()\n for (const ref of refs) {\n const el = resolveElementWarn(group, ref, context)\n if (!el || seen.has(el.id)) continue\n seen.add(el.id)\n out.push(el.id)\n }\n return out\n}\n","import type { Group, ViewMode, CayleyAction, Layout3D } from '../core/types'\r\nimport { COLOR_PALETTE, getDefaultLayout3D, getAvailableShapes3D, getDefaultShape2D, getAvailableShapesForView, isQuotientGroup, type CayleyShape2D } from '../core/types'\r\nimport type { CayleyActionParam } from '../core/types/viewConfig'\r\nimport { resolveElementWarn } from '../utils/elementRef'\r\n\r\nexport function getInitialCayleyActions(group: Group): CayleyAction[] {\r\n return group.generators.map((gen, i) => {\r\n const targetEl = gen.apply(group.identity)\r\n return {\r\n elementId: targetEl?.id || group.elements[0]?.id || group.identity.id,\r\n enabled: true,\r\n color: COLOR_PALETTE[i % COLOR_PALETTE.length]\r\n }\r\n })\r\n}\r\n\r\n/**\r\n * 归一化凯莱视图作用边参数:解析并过滤群中不存在的元素引用,补全 enabled(默认 true)与\r\n * color(默认 COLOR_PALETTE 按序)。actions 未提供时返回群生成元集合。\r\n * ViewWindow 参数面板与 CayleyView 渲染共用,保证两边对「当前边集合」的判定一致。\r\n *\r\n * `elementId` **接受元素引用**(`id` / `label` / `value` 串,见 `core.resolveElement`):\r\n * 传人类记号 `(234)` 不再被静默丢弃;确实解析不到时告警一次再忽略(不再无声无息)。\r\n */\r\nexport function normalizeCayleyActions(group: Group, actions?: CayleyActionParam[]): CayleyAction[] {\r\n if (!actions) return getInitialCayleyActions(group)\r\n const out: CayleyAction[] = []\r\n const seen = new Set<string>()\r\n for (const a of actions) {\r\n const el = resolveElementWarn(group, a.elementId, 'CayleyView.actions[].elementId')\r\n if (!el || seen.has(el.id)) continue\r\n seen.add(el.id)\r\n out.push({\r\n elementId: el.id,\r\n enabled: a.enabled !== false,\r\n color: a.color ?? COLOR_PALETTE[out.length % COLOR_PALETTE.length],\r\n })\r\n }\r\n return out\r\n}\r\n\r\nexport interface CayleyShapeConfig {\r\n defaultShape3D: Layout3D\r\n availableShapes3D: Layout3D[]\r\n defaultShape2D: CayleyShape2D\r\n availableShapes2D: CayleyShape2D[]\r\n}\r\n\r\nexport function getCayleyShapeConfig(group: Group): CayleyShapeConfig {\r\n if (isQuotientGroup(group)) {\r\n return {\r\n defaultShape3D: 'cone' as Layout3D,\r\n availableShapes3D: [],\r\n defaultShape2D: 'circular',\r\n availableShapes2D: ['circular'] as CayleyShape2D[],\r\n }\r\n }\r\n const defaultShape = getDefaultLayout3D(group)\r\n const shapes3D = getAvailableShapes3D(group)\r\n const shapes2D = getAvailableShapesForView(group, 'cayley') as CayleyShape2D[]\r\n const default2D = getDefaultShape2D(group)\r\n\r\n return {\r\n defaultShape3D: defaultShape,\r\n availableShapes3D: shapes3D,\r\n defaultShape2D: shapes2D.includes(default2D) ? default2D : (shapes2D[0] || 'circular'),\r\n availableShapes2D: shapes2D,\r\n }\r\n}\r\n\r\nexport function getSpecialCayleyActions(group: Group, shape: Layout3D): CayleyAction[] | null {\r\n const sym = group.symbol\r\n\r\n if (sym === 'S_{4}') {\r\n if (shape === 'rhombicuboctahedron') {\r\n return [\r\n { elementId: '4,1,2,3', enabled: true, color: COLOR_PALETTE[0] },\r\n { elementId: '3,1,2,4', enabled: true, color: COLOR_PALETTE[1] },\r\n ]\r\n } else if (shape === 'truncatedOctahedron2') {\r\n return [\r\n { elementId: '2,3,4,1', enabled: true, color: COLOR_PALETTE[0] },\r\n { elementId: '2,1,3,4', enabled: true, color: COLOR_PALETTE[1] },\r\n ]\r\n } else if (shape === 'truncatedCube') {\r\n return [\r\n { elementId: '1,4,2,3', enabled: true, color: COLOR_PALETTE[0] },\r\n { elementId: '2,1,3,4', enabled: true, color: COLOR_PALETTE[1] },\r\n ]\r\n } else if (shape === 'truncatedOctahedron3') {\r\n return [\r\n { elementId: '2,1,3,4', enabled: true, color: COLOR_PALETTE[0] },\r\n { elementId: '1,3,2,4', enabled: true, color: COLOR_PALETTE[1] },\r\n { elementId: '1,2,4,3', enabled: true, color: COLOR_PALETTE[2] },\r\n ]\r\n }\r\n }\r\n\r\n if (sym === 'A_{5}') {\r\n if (shape === 'truncatedIcosahedron') {\r\n return [\r\n { elementId: '2,3,4,5,1', enabled: true, color: COLOR_PALETTE[0] },\r\n { elementId: '2,1,4,3,5', enabled: true, color: COLOR_PALETTE[1] },\r\n ]\r\n } else if (shape === 'truncatedDodecahedron') {\r\n return [\r\n { elementId: '2,3,1,4,5', enabled: true, color: COLOR_PALETTE[0] },\r\n { elementId: '1,5,4,3,2', enabled: true, color: COLOR_PALETTE[1] },\r\n ]\r\n }\r\n }\r\n\r\n return null\r\n}\r\n\r\nexport function toggleCayleyActionReducer(prev: CayleyAction[], elementId: string): CayleyAction[] {\r\n const idx = prev.findIndex(a => a.elementId === elementId)\r\n if (idx === -1) {\r\n const colorIdx = prev.length\r\n return [...prev, { elementId, enabled: true, color: COLOR_PALETTE[colorIdx % COLOR_PALETTE.length] }]\r\n }\r\n return prev.map((a, i) => i === idx ? { ...a, enabled: !a.enabled } : a)\r\n}\r\n\r\nexport function addAllCayleyActionsHelper(\r\n group: Group,\r\n currentView: ViewMode,\r\n cayleyShape3D: Layout3D,\r\n existingActions: CayleyAction[]\r\n): CayleyAction[] {\r\n const isQuotientGroup = group.symbol.includes('/N')\r\n const canonical3D = (() => {\r\n const sym = group.symbol\r\n if (currentView !== '3d') return new Set<string>()\r\n if (sym === 'S_{4}' || sym === 'S4' || sym === 'S₄') {\r\n if (cayleyShape3D === 'rhombicuboctahedron') return new Set(['4,1,2,3', '3,1,2,4'])\r\n if (cayleyShape3D === 'truncatedOctahedron2') return new Set(['2,3,4,1', '2,1,3,4'])\r\n if (cayleyShape3D === 'truncatedCube') return new Set(['1,4,2,3', '2,1,3,4'])\r\n if (cayleyShape3D === 'truncatedOctahedron3') return new Set(['2,1,3,4', '1,3,2,4', '1,2,4,3'])\r\n }\r\n if (sym === 'A_{5}' || sym === 'A5' || sym === 'A₅') {\r\n if (cayleyShape3D === 'truncatedIcosahedron') return new Set(['2,3,4,5,1', '2,1,4,3,5'])\r\n if (cayleyShape3D === 'truncatedDodecahedron') return new Set(['2,3,1,4,5', '1,5,4,3,2'])\r\n }\r\n return new Set<string>()\r\n })()\r\n\r\n if (isQuotientGroup) {\r\n // For quotient groups, only expose generator actions so the Cayley graph\r\n // shows the quotient structure (edges between cosets), not internal\r\n // subgroup edges rendered inside compound nodes.\r\n return group.generators.map((gen, i) => {\r\n const targetEl = gen.apply(group.identity)\r\n const elementId = targetEl?.id || group.elements[0].id\r\n const existing = existingActions.find(a => a.elementId === elementId)\r\n return {\r\n elementId,\r\n enabled: existing?.enabled ?? true,\r\n color: existing?.color ?? COLOR_PALETTE[i % COLOR_PALETTE.length]\r\n }\r\n })\r\n }\r\n\r\n return group.elements.map((el, i) => {\r\n const existing = existingActions.find(a => a.elementId === el.id)\r\n const defaultEnabled = currentView === '3d'\r\n ? canonical3D.has(el.id)\r\n : group.generators.some(g => g.apply(group.identity).id === el.id)\r\n return {\r\n elementId: el.id,\r\n enabled: existing?.enabled ?? defaultEnabled,\r\n color: existing?.color ?? COLOR_PALETTE[i % COLOR_PALETTE.length]\r\n }\r\n })\r\n}\r\n","import { useCallback, useMemo, useState } from 'react'\nimport { SceneThemeRoot, type SceneTheme } from './SceneThemeRoot'\nimport { computeCayleyActionEdges, cayleyCircleLayout, circleLayoutRadius } from '../../core/algebra/forceLayout'\nimport { getSemidirectProductMeta, semidirectFactorMap, semidirectFixedPoints } from '../../core/algebra/semidirectDecompositions'\nimport { computeShape2DPositions } from '../../core/algebra/shapeLayouts'\nimport { texify, renderTex } from '../../utils/texify'\nimport { getDefaultShape2D } from '../../core/types'\nimport type { CanvasTransform, CayleyEdgeData, CayleyShape2D, Group, GroupElement, MultiplyType, NodePosition } from '../../core/types'\nimport type { CayleyActionParam } from '../../core/types/viewConfig'\n// 纯函数模块(无 react 依赖),FGVE 打包期随视图层迁入 core\nimport { normalizeCayleyActions } from '../../context/cayleyActions'\n\nexport interface CayleyViewProps {\n group: Group | null\n selectedElements: Set<string>\n canvasTransform: CanvasTransform\n viewBoxSize: { width: number; height: number }\n /** 缺省 getDefaultShape2D(group) */\n shape2D?: CayleyShape2D\n /** 缺省 'right'(右乘 a·c) */\n multiplyType?: MultiplyType\n /** 缺省 = 群生成元集合;条目缺省 enabled=true、color=COLOR_PALETTE 按序 */\n actions?: CayleyActionParam[]\n /** 缺省 28(与主视图非复合节点一致) */\n nodeRadius?: number\n /** 缺省 true;>60 阶沿用主视图自适应规则(选中后仅选中节点显示标签)。嵌入小窗(ViewWindow)传 false 彻底不显示节点标签、读元素靠悬停就地气泡 */\n showLabels?: boolean\n /** 缺省 false;true 时禁用节点拖拽(供 ViewWindow 锁定状态使用,点击选中仍保留) */\n locked?: boolean\n onSelect?: (elId: string, additive: boolean) => void\n /**\n * 悬停回调:第一个参数是元素,第二个是节点在 viewport 内的屏幕锚点\n * (viewBox 坐标经 canvasTransform 映射,供上层渲染\"就地气泡\"tooltip)。\n */\n onHover?: (el: GroupElement | null, anchor?: { x: number; y: number } | null) => void\n /** 当前悬停元素 id;用于在该节点外圈绘制高亮环(让\"悬停→信息\"在视觉上立得住) */\n hoveredElementId?: string | null\n noGroupText?: string\n /** 节点标签自适应阈值:`group.order > 该值` 时仅选中节点显示常驻标签;缺省 60(主画布规则) */\n largeGroupThreshold?: number\n /** 视图主题作用域(`'dark' | 'light'`)。缺省不注入、跟随外层主题;显式传值时在本子树内\n * 应用 `theme.css` 对应变量块(需宿主已 `import '@groupviz/react/theme.css'`) */\n theme?: SceneTheme\n}\n\nexport function CayleyView(props: CayleyViewProps) {\n return (\n <SceneThemeRoot theme={props.theme}>\n <CayleyViewBody {...props} />\n </SceneThemeRoot>\n )\n}\n\n/**\n * 归一化见 context/cayleyActions.ts 的 normalizeCayleyActions(渲染层与参数面板共用)。\n */\n\n// 每实例唯一前缀:同一文档内多个窗口 + 主画布的 <defs> marker/filter id 不冲突\nlet _cayleyViewInst = 0\n\nfunction renderEdgePath(\n edge: CayleyEdgeData,\n nodePositionsCache: Map<string, NodePosition>,\n nodeRadius: number,\n enabledActionIndexMap: Map<string, number>,\n isHighlighted: boolean,\n markerPrefix: string,\n) {\n const fromPos = nodePositionsCache.get(edge.fromId)\n const toPos = nodePositionsCache.get(edge.toId)\n if (!fromPos || !toPos) return null\n\n const dx = toPos.x - fromPos.x\n const dy = toPos.y - fromPos.y\n const dist = Math.sqrt(dx * dx + dy * dy)\n if (dist < 1) return null\n\n const baseColor = edge.color\n const color = isHighlighted ? baseColor : `${baseColor}99`\n\n if (edge.isSelfLoop) {\n const scx = fromPos.x\n const scy = fromPos.y - nodeRadius - 20\n return (\n <g key={`${edge.fromId}-${edge.actionElementId}`}>\n <ellipse cx={scx} cy={scy} rx={14} ry={12} fill=\"none\" stroke={color} strokeWidth={isHighlighted ? 3.5 : 2.5} />\n <polygon points={`${scx - 5},${scy - 2} ${scx + 5},${scy - 2} ${scx},${scy - 14}`} fill={baseColor} />\n </g>\n )\n }\n\n const midX = (fromPos.x + toPos.x) / 2\n const midY = (fromPos.y + toPos.y) / 2\n const nx = -dy / dist\n const ny = dx / dist\n\n const curvature = Math.min(dist * 0.08, 18)\n const ctrlX = midX + nx * curvature\n const ctrlY = midY + ny * curvature\n\n const startX = fromPos.x + (dx / dist) * nodeRadius\n const startY = fromPos.y + (dy / dist) * nodeRadius\n const endX = toPos.x - (dx / dist) * nodeRadius\n const endY = toPos.y - (dy / dist) * nodeRadius\n\n const actionIdx = enabledActionIndexMap.get(edge.actionElementId)\n const markerId = actionIdx !== undefined ? `${markerPrefix}-arrow-${actionIdx}` : undefined\n\n return (\n <path\n key={`${edge.fromId}-${edge.toId}-${edge.actionElementId}`}\n d={`M ${startX} ${startY} Q ${ctrlX} ${ctrlY} ${endX} ${endY}`}\n stroke={color}\n strokeWidth={isHighlighted ? 3.5 : 2.5}\n fill=\"none\"\n markerEnd={edge.isBidirectional || !markerId ? undefined : `url(#${markerId})`}\n opacity={0.9}\n />\n )\n}\n\nfunction CayleyViewBody({\n group,\n selectedElements,\n canvasTransform,\n viewBoxSize,\n shape2D: shapeProp,\n multiplyType: multiplyProp,\n actions: actionsProp,\n nodeRadius: nodeRadiusProp,\n showLabels: showLabelsProp,\n locked = false,\n onSelect,\n onHover,\n hoveredElementId,\n noGroupText,\n largeGroupThreshold = 60,\n}: CayleyViewProps) {\n // 惰性初始化的每实例唯一前缀(useState 初始化器每实例只执行一次)\n const [markerPrefix] = useState(() => `cv${++_cayleyViewInst}`)\n\n const n = group?.order ?? 0\n const shape: CayleyShape2D = group ? (shapeProp ?? getDefaultShape2D(group)) : 'circular'\n const multiplyType: MultiplyType = multiplyProp ?? 'right'\n const nodeRadius = nodeRadiusProp ?? 28\n const isLargeGraph = n > largeGroupThreshold\n\n const effectiveActions = useMemo(\n () => (group ? normalizeCayleyActions(group, actionsProp) : []),\n [group, actionsProp],\n )\n\n // 拖拽覆盖位置为窗口本地会话态;群/形状变化时重置(key 校验在渲染期完成,\n // 避免 key 变化后的一帧读到旧群的坐标)\n const posKey = group ? `${group.symbol}|${group.order}|${shape}` : ''\n const [dragState, setDragState] = useState<{ key: string; map: Map<string, NodePosition> }>({\n key: posKey,\n map: new Map(),\n })\n if (dragState.key !== posKey) {\n setDragState({ key: posKey, map: new Map() })\n }\n const dragPositions = useMemo(\n () => (dragState.key === posKey ? dragState.map : new Map<string, NodePosition>()),\n [dragState, posKey],\n )\n\n const setDragPositionsEntry = useCallback(\n (elId: string, pos: NodePosition) => {\n setDragState(prev => {\n if (prev.key !== posKey) return prev\n const map = new Map(prev.map)\n map.set(elId, pos)\n return { key: prev.key, map }\n })\n },\n [posKey],\n )\n\n const cx = viewBoxSize.width / 2\n const cy = viewBoxSize.height / 2\n // 半径同时受容器宽/高约束:嵌入方给的 viewBox 可能宽扁(如 900×360),\n // 只按宽度取半径会让圆环上下两端节点出画布(见 feedback/issue-circular-radius-overflow.md)\n const graphRadius = circleLayoutRadius(viewBoxSize.width, viewBoxSize.height, n, nodeRadius)\n\n const gridPositions = useMemo(() => {\n if (!group) return null\n return computeShape2DPositions(group, shape, viewBoxSize.width, viewBoxSize.height)\n }, [group, shape, viewBoxSize.width, viewBoxSize.height])\n\n const circLayout = useMemo(() => {\n if (!group || n === 0) return new Map<string, NodePosition>()\n return cayleyCircleLayout(group, cx, cy, graphRadius)\n }, [group, cx, cy, graphRadius, n])\n\n // rewiring 形状:半直积 φ-不动点青色高亮(与主视图同源纯计算)\n const sdMeta = useMemo(() => (group ? getSemidirectProductMeta(group) : null), [group])\n const sdFixedMap = useMemo(() => {\n const m = new Map<string, boolean>()\n if (!group || !sdMeta) return m\n const factorMap = semidirectFactorMap(group, sdMeta)\n if (!factorMap) return m\n return semidirectFixedPoints(group, sdMeta, factorMap)\n }, [group, sdMeta])\n\n const enabledActions = useMemo(() => effectiveActions.filter(a => a.enabled), [effectiveActions])\n const enabledActionIndexMap = useMemo(() => {\n const m = new Map<string, number>()\n enabledActions.forEach((a, idx) => m.set(a.elementId, idx))\n return m\n }, [enabledActions])\n\n const edges = useMemo(\n () => (group ? computeCayleyActionEdges(group, effectiveActions, multiplyType) : []),\n [group, effectiveActions, multiplyType],\n )\n\n const getNodePos = useCallback(\n (elId: string): NodePosition => {\n let defPos: NodePosition\n if (gridPositions) {\n const gp = gridPositions.get(elId)\n if (!gp) return { x: cx, y: cy }\n defPos = gp\n } else {\n const pos = circLayout.get(elId)\n if (!pos) return { x: cx, y: cy }\n defPos = pos\n }\n const saved = dragPositions.get(elId)\n if (saved && (Math.abs(saved.x - defPos.x) > 1 || Math.abs(saved.y - defPos.y) > 1)) {\n return saved\n }\n return defPos\n },\n [gridPositions, circLayout, dragPositions, cx, cy],\n )\n\n const nodePositionsCache = useMemo(() => {\n const cache = new Map<string, NodePosition>()\n if (!group) return cache\n group.elements.forEach(el => cache.set(el.id, getNodePos(el.id)))\n return cache\n }, [group, getNodePos])\n\n // KaTeX 标签 HTML 开销大:每群只渲染一次\n const labelHtmlCache = useMemo(() => {\n const m = new Map<string, string>()\n if (!group) return m\n group.elements.forEach(el => m.set(el.id, renderTex(texify(el.label))))\n return m\n }, [group])\n\n const selectedCount = useMemo(() => selectedElements.size, [selectedElements])\n\n const edgeElements = useMemo(() => {\n if (!group) return null\n return edges.map(edge =>\n renderEdgePath(edge, nodePositionsCache, nodeRadius, enabledActionIndexMap, false, markerPrefix),\n )\n }, [edges, nodePositionsCache, enabledActionIndexMap, nodeRadius, group, markerPrefix])\n\n // 选中相关边全色加粗重绘于基础边之上\n const highlightedEdges = useMemo(() => {\n if (!group || selectedElements.size === 0) return null\n return edges\n .filter(edge => selectedElements.has(edge.fromId) || selectedElements.has(edge.toId))\n .map(edge =>\n renderEdgePath(edge, nodePositionsCache, nodeRadius, enabledActionIndexMap, true, markerPrefix),\n )\n }, [edges, selectedElements, nodePositionsCache, enabledActionIndexMap, nodeRadius, group, markerPrefix])\n\n const nodeElements = useMemo(() => {\n if (!group) return null\n return group.elements.map(el => {\n const pos = nodePositionsCache.get(el.id) || { x: cx, y: cy }\n const sx = pos.x * canvasTransform.scale + canvasTransform.x\n const sy = pos.y * canvasTransform.scale + canvasTransform.y\n const cullMargin = nodeRadius * canvasTransform.scale * 1.5\n const onScreen =\n !isLargeGraph ||\n (sx + cullMargin > 0 &&\n sx - cullMargin < viewBoxSize.width &&\n sy + cullMargin > 0 &&\n sy - cullMargin < viewBoxSize.height)\n if (!onScreen) return null\n const isSdFixed = shape === 'rewiring' && !!sdMeta && sdFixedMap.get(el.id) === true\n\n let fillColor = 'var(--node-fill)'\n let strokeColor = 'var(--node-stroke)'\n let strokeWidth = 2.5\n if (isSdFixed) {\n fillColor = 'var(--accent-teal)22'\n strokeColor = 'var(--accent-teal)'\n strokeWidth = 3\n }\n\n return (\n <g\n key={el.id}\n transform={`translate(${pos.x}, ${pos.y})`}\n onClick={e => {\n e.stopPropagation()\n onSelect?.(el.id, e.ctrlKey || e.metaKey)\n }}\n onMouseDown={e => {\n if (locked) return\n if (e.button !== 0) return\n e.stopPropagation()\n const svg = e.currentTarget.closest('svg')\n if (!svg) return\n const svgRect = svg.getBoundingClientRect()\n if (svgRect.width === 0 || svgRect.height === 0) return\n const scaleX = viewBoxSize.width / svgRect.width\n const scaleY = viewBoxSize.height / svgRect.height\n const startX = (e.clientX - svgRect.left) * scaleX\n const startY = (e.clientY - svgRect.top) * scaleY\n const startPos = getNodePos(el.id)\n\n let pendingPos: NodePosition | null = null\n const rafId = { current: 0 }\n const commit = () => {\n if (pendingPos) setDragPositionsEntry(el.id, pendingPos)\n }\n const handleMove = (moveEvent: MouseEvent) => {\n const currentX = (moveEvent.clientX - svgRect.left) * scaleX\n const currentY = (moveEvent.clientY - svgRect.top) * scaleY\n pendingPos = {\n x: startPos.x + (currentX - startX) / canvasTransform.scale,\n y: startPos.y + (currentY - startY) / canvasTransform.scale,\n }\n // rAF 节流:每帧至多一次位置写入\n if (rafId.current === 0) {\n rafId.current = requestAnimationFrame(() => {\n rafId.current = 0\n commit()\n })\n }\n }\n const handleUp = () => {\n window.removeEventListener('mousemove', handleMove)\n window.removeEventListener('mouseup', handleUp)\n if (rafId.current !== 0) {\n cancelAnimationFrame(rafId.current)\n rafId.current = 0\n }\n commit()\n }\n window.addEventListener('mousemove', handleMove)\n window.addEventListener('mouseup', handleUp)\n }}\n onMouseEnter={() => onHover?.(el, { x: sx, y: sy })}\n onMouseLeave={() => onHover?.(null, null)}\n style={{ cursor: 'grab' }}\n >\n <circle\n r={nodeRadius}\n fill={fillColor}\n stroke={strokeColor}\n strokeWidth={strokeWidth}\n filter={isLargeGraph ? undefined : `url(#${markerPrefix}-node-shadow)`}\n />\n {/* 悬停高亮环:让\"我悬停的就是这个节点\"一眼可见,配合就地气泡形成\"节点环+元素名\"双重反馈 */}\n {el.id === hoveredElementId && (\n <circle\n r={nodeRadius + 5}\n fill=\"none\"\n stroke=\"#4ecdc4\"\n strokeWidth={3.5}\n opacity={0.95}\n style={{ filter: 'drop-shadow(0 0 4px rgba(78,205,196,0.7))' }}\n />\n )}\n {showLabelsProp !== false && (!isLargeGraph || selectedCount === 0) && (\n <foreignObject\n x={-nodeRadius}\n y={-16}\n width={nodeRadius * 2}\n height={32}\n style={{ pointerEvents: 'none', userSelect: 'none' }}\n >\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '100%',\n height: '100%',\n color: isSdFixed ? 'var(--accent-teal)' : 'var(--node-text)',\n fontSize: isLargeGraph ? '10px' : '15px',\n fontWeight: isSdFixed ? 700 : 400,\n }}\n dangerouslySetInnerHTML={{ __html: labelHtmlCache.get(el.id) ?? '' }}\n />\n </foreignObject>\n )}\n </g>\n )\n })\n }, [\n group, nodePositionsCache, selectedCount, sdMeta, sdFixedMap, nodeRadius, isLargeGraph,\n canvasTransform, viewBoxSize, cx, cy, labelHtmlCache, shape, getNodePos, onSelect, onHover,\n markerPrefix, showLabelsProp, setDragPositionsEntry, locked, hoveredElementId,\n ])\n\n // 选中金圈 overlay(大群时附带选中节点标签),绘制于节点之上\n const selectionOverlay = useMemo(() => {\n if (!group || selectedElements.size === 0) return null\n return [...selectedElements].map(id => {\n const pos = nodePositionsCache.get(id) || { x: cx, y: cy }\n const sx = pos.x * canvasTransform.scale + canvasTransform.x\n const sy = pos.y * canvasTransform.scale + canvasTransform.y\n const cullMargin = nodeRadius * canvasTransform.scale * 1.5\n if (\n isLargeGraph &&\n !(sx + cullMargin > 0 && sx - cullMargin < viewBoxSize.width && sy + cullMargin > 0 && sy - cullMargin < viewBoxSize.height)\n ) {\n return null\n }\n return (\n <g key={`selected-${id}`} transform={`translate(${pos.x}, ${pos.y})`}>\n <circle r={nodeRadius + 3} fill=\"none\" stroke=\"#ffd93d\" strokeWidth={3} opacity={0.95} />\n {isLargeGraph && (\n <foreignObject x={-nodeRadius} y={-16} width={nodeRadius * 2} height={32} style={{ pointerEvents: 'none', userSelect: 'none' }}>\n <div\n style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', width: '100%', height: '100%', color: 'var(--node-text)', fontSize: '10px' }}\n dangerouslySetInnerHTML={{ __html: labelHtmlCache.get(id) ?? '' }}\n />\n </foreignObject>\n )}\n </g>\n )\n })\n }, [group, selectedElements, nodePositionsCache, nodeRadius, canvasTransform, viewBoxSize, isLargeGraph, cx, cy, labelHtmlCache])\n\n if (!group) {\n return (\n <div className=\"view-empty\">\n <p>{noGroupText ?? ''}</p>\n </div>\n )\n }\n\n return (\n <svg viewBox={`0 0 ${viewBoxSize.width} ${viewBoxSize.height}`} className=\"view-svg\" style={{ userSelect: 'none' }}>\n <defs>\n <filter id={`${markerPrefix}-node-shadow`} x=\"-30%\" y=\"-30%\" width=\"160%\" height=\"160%\">\n <feDropShadow dx=\"0\" dy=\"2\" stdDeviation=\"3\" floodColor=\"#000000\" floodOpacity=\"0.25\" />\n </filter>\n {enabledActions.map((action, idx) => (\n <marker\n key={idx}\n id={`${markerPrefix}-arrow-${idx}`}\n markerWidth={10}\n markerHeight={10}\n refX={9}\n refY={3}\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path d=\"M0,0 L0,6 L9,3 z\" fill={action.color} />\n </marker>\n ))}\n </defs>\n\n <g transform={`translate(${canvasTransform.x}, ${canvasTransform.y}) scale(${canvasTransform.scale})`}>\n {edgeElements}\n {highlightedEdges}\n\n {nodeElements}\n {selectionOverlay}\n </g>\n </svg>\n )\n}\n","export type Lang = 'zh' | 'en'\n\ntype TranslationMap = Record<string, string>\n\nconst zh: TranslationMap = {\n /* App */\n 'app.title': 'GroupViz - 群论可视化',\n 'app.header': 'GroupViz - 群论可视化',\n 'ui.openToolbar': '打开工具栏',\n 'ui.openInfo': '打开信息面板',\n 'ui.computing': '计算中',\n 'theme.viewWindowDark': '视图窗口切换为浅色',\n 'theme.viewWindowLight': '视图窗口切换为深色',\n\n /* Welcome Page */\n 'welcome.subtitle': '群论可视化平台',\n 'welcome.version': 'v2.1.4',\n 'welcome.tagline': '探索抽象代数的对称之美 — 交互式群论可视化与学习工具',\n 'welcome.enter': '进入应用',\n 'welcome.section.done': '已实现',\n 'welcome.section.soon': '即将推出',\n 'welcome.item.subgroups': '子群与陪集',\n 'welcome.item.cayley': 'Cayley 图',\n 'welcome.item.table': '乘法表',\n 'welcome.item.build': '群构建系统',\n 'welcome.item.homomorphism': '同态映射',\n 'welcome.item.presentation': '群展示',\n 'welcome.soon.education': '教育模式',\n 'welcome.soon.freegroup': '自由群',\n 'welcome.soon.dlc': 'DLC(空间群/点群)',\n 'welcome.feature.subgroups': '子群与陪集',\n 'welcome.feature.cayley': 'Cayley图',\n 'welcome.feature.multigroup': '多群支持',\n 'welcome.feature.table': '乘法表',\n 'welcome.feature.3d': '3D可视化',\n 'welcome.feature.symmetry': '对称性视图',\n\n /* Left Panel — Accordion Titles */\n 'panel.createGroup': '创建群',\n 'panel.viewMode': '视图模式',\n 'panel.cayleySettings': '凯莱图设置',\n 'panel.operations': '操作与子集',\n 'panel.basicGroup': '基本群',\n 'panel.importGroup': '记号导入群',\n\n /* Left Panel — Group Types */\n 'group.cyclic': '循环群',\n 'group.cyclic.full': '循环群 Z_n',\n 'group.symmetric': '对称群',\n 'group.symmetric.full': '对称群 S_n',\n 'group.dihedral': '二面体群',\n 'group.dihedral.full': '二面体群 D_n',\n 'group.alternating': '交错群',\n 'group.alternating.full': '交错群 A_n',\n 'group.special': '特殊群',\n 'group.klein': 'Klein四元群',\n 'group.quaternion': '四元数群',\n 'group.gl2p2': 'GL(2,2) ≅ S₃,6 阶',\n 'group.gl2p3': 'GL(2,3),48 阶,|SL(2,3)| = 24',\n 'group.direct.z4z2': '直积群',\n 'group.direct.z2cubed': '初等阿贝尔群',\n 'group.direct.z3z3': '直积群',\n 'group.direct.z6z2': '直积群',\n 'group.type': '类型',\n 'group.order': '阶',\n 'panel.createByType': '按群类型创建',\n 'panel.createByOrder': '按阶创建',\n 'panel.order.semidirectHint': '符号中 \":\" 表示半直积(如 Z₃:C₄ = Dic₃)',\n\n /* Left Panel — View Modes */\n 'view.set': '集合视图',\n 'view.set.desc': '元素列表',\n 'view.cayley': '凯莱图',\n 'view.cayley.desc': '2D图',\n 'view.cycle': '循环图',\n 'view.cycle.desc': '循环结构',\n 'view.table': '乘法表',\n 'view.table.desc': 'Cayley表',\n 'view.3d': '3D凯莱图',\n 'view.3d.desc': '三维图',\n 'view.symmetry': '对称性视图',\n 'view.symmetry.desc': '多面体',\n 'view.sublattice': '子群格',\n 'view.sublattice.desc': '子群层次',\n 'view.homomorphism': '同态映射',\n 'view.homomorphism.desc': '群同态',\n 'view.cosetstrip': '陪集条带',\n 'view.cosetstrip.desc': '陪集分解',\n 'view.action': '轨道视图',\n 'view.action.desc': '群作用',\n 'view.sylow': 'Sylow',\n 'view.sylow.desc': 'p-元素与 Sylow p-子群',\n 'view.tree': '树视图',\n 'view.prestable': '展示乘法表',\n 'view.heatmap': '热力图',\n 'view.heatmap.desc': '乘法结果染色',\n\n /* Free Group Tree / Presentation Table views */\n 'prestable.noPresentation': '当前群没有可用的群展示(⟨… | …⟩)。请先在左侧「群展示」面板创建,或选择较小的群。',\n\n /* Left Panel — Buttons & Labels */\n 'panel.create': '创建 {label}',\n 'panel.multiView': '多视图模式',\n 'panel.floatView': '+ {label}',\n 'panel.showMaximalCycles': '仅显示极大循环',\n 'panel.showHeatmap': '热力图模式',\n 'panel.showAction': '显示元素操作',\n 'panel.speed': '速度',\n 'panel.solidShape': '几何体',\n 'panel.solidCube': '正方体',\n 'panel.solidOcta': '正八面体',\n 'panel.solidIcosa': '正二十面体',\n 'panel.solidDodeca': '正十二面体',\n 'panel.multiplyType': '乘法类型',\n 'panel.multiplyRight': '右乘 a·c',\n 'panel.multiplyLeft': '左乘 c·a',\n 'panel.shape': '图形状',\n 'panel.shape.circular': '圆形',\n 'panel.shape.cone': '圆锥',\n 'panel.shape.grid': '网格',\n 'panel.shape.rewiring': '重布线',\n 'panel.shape.concentric': '共轭类同心环',\n 'panel.shape.dualRing': '双环(旋转/反射)',\n 'panel.shape.cylinder': '交错同心圆',\n 'panel.shape.torus': '甜甜圈(环上挂副本)',\n 'panel.shape.ringGrid': '环网格(环×网格)',\n 'panel.shape.cosetStrip': '陪集条带',\n 'panel.shape.archimedean': '阿基米德螺旋',\n 'panel.shape.spiral': '螺旋',\n 'panel.shape.coil': '线圈',\n 'panel.shape.projection3D': '3D平面投影',\n 'panel.shape.pythagoreanSquare': '勾股正方形',\n 'panel.forceLayout': '力导向布局',\n 'panel.elementActions': '群元素作用 ({n}/{m})',\n 'panel.selectAll': '全选',\n 'panel.clear': '清除',\n 'panel.resetPositions': '重置位置',\n 'panel.decomposeSD': '半直积分解',\n 'panel.decomposeSDDisabled': '请先选择群',\n 'panel.subsetManagement': '子集管理',\n 'panel.saveAsSubset': '存为子集 ({n})',\n 'panel.clearAllSubsets': '清除所有子集',\n 'panel.showCosets': '显示陪集',\n 'panel.generateSubgroup': '生成子群 ⟨E⟩',\n 'panel.normalizer': '正规化子 N_G(E)',\n 'panel.centralizer': '中心化子 C_G(E)',\n 'panel.hideCosets': '隐藏陪集',\n 'panel.showAllCosets': '显示全部陪集',\n 'panel.showSelected': '显示选中陪集',\n 'panel.cosetType': '陪集类型',\n 'panel.indices': '指数: {index}',\n 'panel.cosetCount': '共 {count} 个陪集',\n 'panel.inverse': '求逆元',\n 'panel.clearCanvas': '清空画布',\n 'panel.exportPng': '导出 PNG',\n 'panel.exportSvg': '导出 SVG',\n 'panel.exportGif': '导出 GIF',\n 'panel.gifOption': 'GIF 旋转时长',\n 'panel.gif3s': '约 3 秒',\n 'panel.gif5Cycles': '5 个旋转周期',\n 'panel.exportView': '导出视图',\n 'panel.exporting': '导出中...',\n 'panel.selectElementFirst': '请先在画布上选中一个元素',\n 'panel.series': '子群列',\n\n /* Left Panel — Badges */\n 'badge.normal': '正规',\n 'badge.subgroup': '子群',\n 'badge.center': '中心',\n\n /* Right Panel */\n 'right.elementProps': '元素属性',\n 'right.currentElement': '当前元素',\n 'right.inverse': '逆元',\n 'right.id': 'ID',\n 'right.selectHint': '在画布上选择元素查看属性',\n 'right.groupInfo': '群信息',\n 'right.groupName': '群名',\n 'right.symbol': '符号',\n 'right.order': '阶',\n 'right.generators': '生成元',\n 'right.abelian': '阿贝尔',\n 'right.isomorphic': '同构于',\n 'right.isomorphicClick': '点击加载该同构群',\n 'right.yes': '是',\n 'right.no': '否',\n 'right.properties': '群性质',\n 'right.propertyTrue': '是',\n 'right.propertyFalse': '否',\n 'right.propertyUnavailable': '该群不支持性质分析',\n 'right.solvable': '可解',\n 'right.nilpotent': '幂零',\n 'right.perfect': '完美',\n 'right.derivedSeries': '导列',\n 'right.structure': '结构',\n 'right.structure.direct': '直积',\n 'right.structure.semidirect': '半直积',\n 'right.structure.indecomposable': '不可分解',\n 'right.structure.unknown': '未知',\n 'right.center': '中心 Z(G)',\n 'right.noGroup': '请先选择一个群',\n 'right.simpleGroup': '单群 Simple Group',\n 'right.subgroups': '子群 ({n})',\n 'right.noSubgroups': '无子群',\n 'right.loadingBackend': '正在从后端计算群结构...',\n 'right.conjugacyClasses': '共轭类 ({n})',\n 'right.noClasses': '无共轭类',\n 'right.elementList': '元素列表 ({n})',\n 'right.homomorphism': '群同态',\n 'right.homo.kernel': '核 Ker',\n 'right.homo.image': '像 Im',\n 'right.homo.quotient': '商群 G/Ker',\n 'right.homo.noActive': '暂无激活的同态映射',\n 'right.automorphismMapping': '自同构映射',\n 'right.automorphismFixed': '个不动点',\n\n /* Subgroup Lattice */\n 'lattice.trivial': '平凡群',\n 'lattice.subgroup': '子群',\n 'lattice.sylow': 'Sylow {p}-子群',\n 'lattice.labelDetail': '标签细节',\n 'lattice.label.auto': '自动',\n 'lattice.label.full': '完整名片',\n 'lattice.label.compact': '胶囊',\n 'lattice.label.dots': '圆点',\n 'lattice.mergeConjugates': '合并共轭子群',\n 'lattice.mergeHint': '同一共轭轨道的子群合成一个节点,角标 ×n = |G : N_G(H)|',\n 'lattice.nodeSize': '名片大小',\n 'lattice.showSeriesPanel': '子群列面板',\n 'lattice.orbitMembers': '{n} 个共轭子群',\n 'lattice.captionHint': '悬停或点击子群节点查看结构、指数与正规化子',\n 'lattice.mergeTooLarge': '子群数超过合并上限,已回退为未合并的子群格',\n 'lattice.backendOnly': '子群格需后端计算(超过 60 阶的群),请在主工作台中查看',\n\n /* Subgroup Series */\n 'series.off': '关闭',\n 'series.derived': '导列',\n 'series.upperCentral': '上中心列',\n 'series.lowerCentral': '下中心列',\n 'series.composition': '合成列',\n 'series.chain': '合成列链',\n 'series.alternativeChains': '共 {n} 条合成列',\n 'series.factors': '合成因子',\n 'series.jordanHolder': 'Jordan–Hölder:因子多重集唯一',\n 'series.solvable': '可解',\n 'series.nilpotent': '幂零',\n 'series.tooLarge': '群阶超过 240,跳过本地系列计算',\n 'series.loading': '后端(GAP)计算系列中…',\n 'series.truncated': '合成列超过 20 条,仅展示前 20 条',\n\n /* Cayley 3D Legend */\n 'cayley3d.multiplyRight': '右乘',\n 'cayley3d.multiplyLeft': '左乘',\n 'cayley3d.autoRotate': '自动旋转',\n 'cayley3d.resetView': '复位视图',\n\n /* Symmetry View */\n 'symmetry.reset': '复位中...',\n 'symmetry.rotating': '旋转中...',\n 'symmetry.clickHint': '点击元素查看其在几何体上的对称作用',\n 'symmetry.selectHint': '在画布上选中元素以查看其在几何体上的作用',\n 'symmetry.demoOff': '元素操作演示已关闭',\n 'symmetry.unsupported': '此群类型暂不支持对称性视图',\n 'symmetry.supported': '支持的群:循环群 C_n · 二面体群 D_n · A_4 · S_4 · A_5 · V_4',\n 'symmetry.toCube': '→ 正方体',\n 'symmetry.toOctahedron': '→ 正八面体',\n 'symmetry.toIcosahedron': '→ 正二十面体',\n 'symmetry.toDodecahedron': '→ 正十二面体',\n\n /* Symmetry Geometry Descriptions (形状名,群符号已在场景标题行单独显示) */\n 'symmetry.geo.cyclicText': '{n}阶旋转对称',\n 'symmetry.geo.dihedralText': '正{n}边形',\n 'symmetry.geo.tetrahedron': '正四面体',\n 'symmetry.geo.cube': '正方体',\n 'symmetry.geo.octahedron': '正八面体',\n 'symmetry.geo.icosahedron': '正二十面体',\n 'symmetry.geo.dodecahedron': '正十二面体',\n 'symmetry.geo.rectangle': '长方形',\n\n /* Canvas Common */\n 'canvas.noGroup': '请先选择一个群',\n 'canvas.noGroupCreate': '请先创建或选择一个群',\n 'canvas.orderTooLarge': '群阶数太大 (|G| = {n})',\n 'canvas.show': '显示',\n 'canvas.hintBox': '提示信息',\n 'canvas.history': '操作历史',\n 'canvas.cosetStripNoSubgroup': '请选择一个子群以查看陪集',\n 'canvas.cosetStripNoCosets': '在右侧面板点击一个子群以查看陪集',\n 'canvas.cosetStripCayley': '子群凯莱图 ⟨H⟩',\n 'canvas.tableSampled': '大群仅显示采样行列',\n\n /* TableView */\n 'table.footer1': '列 × 行 = 结果',\n 'table.footer2': '颜色对应结果元素',\n 'table.strategy.subgroup': '子群展示',\n 'table.strategy.random': '随机展示',\n 'table.strategy.full': '全量展示',\n 'table.subgroupCaption': '子群 {label}(|H| = {order})',\n 'table.randomCaption': '随机采样 {n} 个元素',\n 'table.heatmapAggCaption': '完整乘法表 |G| = {n},热力图缩略 {res}×{res}(众数色块)',\n 'table.fullConfirmTitle': '全量展示确认',\n 'table.fullConfirmMsg': '该群阶数 |G| = {n},全量展示将进入全屏模式并可能占用较多内存。确定继续吗?',\n 'table.confirmOk': '确定',\n 'table.confirmCancel': '取消',\n 'table.fullTitle': '{symbol} — 完整乘法表(|G| = {n})',\n 'table.fullExit': '退出全屏',\n 'table.fullExport': '导出 SVG',\n 'table.fullZoomIn': '放大',\n 'table.fullZoomOut': '缩小',\n 'table.fullZoomReset': '重置缩放',\n 'table.zoomSlider': '缩放滑块',\n 'table.fullPlaceholderMsg': '全量乘法表 |G| = {n} 较大,已切换至全屏模式',\n 'table.fullEnter': '进入全屏',\n\n /* Hint Messages */\n 'cayley.action.enabled': '已启用',\n 'cayley.action.disabled': '已禁用',\n 'cayley.action.byElement': '按元素',\n 'hint.cayleyActionNonGenerator': '本应用的凯莱边由任意元素作用定义(不限于生成元)',\n 'hint.groupSelected': '已选择群 {name}(阶 = {order})',\n 'hint.groupCleared': '已清空当前群',\n 'hint.cayley': '凯莱图 — 拖拽节点可移动 | {count} 个边作用元素 | {type}',\n 'hint.cayley3d': '3D凯莱图 — 拖拽旋转,滚轮缩放 | {count} 个边 | 形状: {shape}',\n 'hint.symmetry': '对称性视图 — 展示群的几何对称对象 | 拖拽旋转,滚轮缩放',\n 'hint.sublattice': '子群格 — 点击子群节点选中对应元素 | 拖拽平移,滚轮缩放',\n 'hint.cycle': '循环图 — 每个多边形是一个循环子群 ⟨g⟩ ≅ Z<sub>n</sub>',\n 'hint.tree': '树视图 — 展示 ⟨S|R⟩ 的退化树(商群凯莱图的 BFS 生成树):实线=生成树边(按生成元着色);粘合边不绘制,顶部栏显示粘合边计数 | 滚轮缩放、拖拽平移、双击复位、点击节点显示词',\n 'hint.prestable': '展示乘法表 — 行 × 列 = 结果,点击格子选中元素',\n 'hint.switchedTo': '已切换到 {viewLabel}',\n 'hint.elementSelected': '已选择: {label}',\n 'hint.layoutDone': '布局优化完成',\n 'hint.layoutComputing': '正在计算布局...',\n 'hint.cayleyMultiply': 'Cayley图乘法类型: {label}',\n 'hint.cayleyCleared': 'Cayley图已清除所有边',\n 'hint.cayleyShape': '3D凯莱图形状: {shape}',\n 'hint.subsetSaved': '已存储子集: {label}({n} 个元素)',\n 'hint.symmetryAction': '显示元素操作: {label}',\n 'hint.multiViewOn': '视图多开已开启 — 点击视图按钮打开悬浮窗',\n 'hint.multiViewOff': '视图多开已关闭 — 所有悬浮视图已关闭',\n 'hint.cosetShow': '陪集模式 — 选中元素的陪集高亮 | 子群: {label} (阶={order})',\n 'hint.cosetHide': '陪集模式已关闭',\n 'hint.cosetType': '陪集类型: {label}',\n 'hint.cosetAll': '显示全部陪集 — 验证拉格朗日定理: |G| = |H| × [G:H]',\n 'hint.cosetSelect': '选中元素以显示对应陪集',\n 'hint.layoutFailed': '布局优化失败,请重试',\n 'hint.quotientCreated': '已创建商群 {symbol}(阶 = {order})',\n 'hint.quotientCreatedIso': '已创建商群 {symbol}(阶 = {order})— 同构于 {isoSymbol}',\n 'hint.automorphismComputed': '已计算自同构群 Aut({symbol})(阶 = {order})',\n 'hint.automorphismComputedIso': '已计算自同构群 Aut({symbol})(阶 = {order})— 同构于 {isoSymbol}',\n\n /* Operation History */\n 'op.loadGroup': '加载群 {name} (阶={order})',\n 'op.switchView': '切换视图: {view}',\n 'op.layout': '布局优化: {view}',\n 'op.checkSubset': '检验子集: {label}',\n 'op.inverseRequest': '请选择一个元素求逆元',\n 'op.inverseDone': '求逆元: ({label})^{-1} = {result}',\n 'op.clearCanvas': '清空画布',\n 'op.generateSubgroup': '生成子群 (待实现)',\n 'op.setCayleyMultiply': '设置Cayley乘法: {label}',\n 'op.clearCayley': '清除Cayley图边',\n 'op.setShape': '设置3D形状: {shape}',\n 'op.saveSubset': '存为子集: {label} ({n} 个元素)',\n 'op.removeSubset': '删除子集',\n 'op.clearSubsets': '清除所有子集',\n 'op.multiViewOn': '开启视图多开',\n 'op.multiViewOff': '关闭视图多开',\n 'op.openFloatView': '打开悬浮视图: {viewLabel}',\n 'op.cosetShow': '显示陪集: {label}',\n 'op.cosetHide': '隐藏陪集',\n 'op.cosetType': '切换陪集类型: {label}',\n 'op.cosetAll': '显示全部陪集',\n 'op.cosetSelect': '按选中元素显示陪集',\n 'op.createQuotient': '创建商群 {parent}(阶 = {order})',\n 'op.removeQuotient': '删除商群',\n 'op.computedAutomorphism': '计算自同构群 Aut({symbol})(阶 = {order})',\n 'op.removeAutomorphism': '删除自同构群',\n\n /* Subset Results */\n 'subset.plain': '普通子集',\n 'subset.subgroup': '子群',\n 'subset.normalSubgroup': '正规子群',\n\n /* Coset */\n 'coset.left': '左陪集',\n 'coset.right': '右陪集',\n\n /* Language Toggle */\n 'lang.zh': '简体中文',\n 'lang.en': 'English',\n\n /* Direct Product */\n 'dp.title': '直积',\n 'dp.mode': '创建方式',\n 'dp.mode.cayley': '凯莱图',\n 'dp.mode.table': '乘法表',\n 'dp.mode.direct': '直接创建',\n 'dp.sourceGroup': 'G',\n 'dp.targetGroup': 'H',\n 'dp.selectGroup': '选择群...',\n 'dp.importGroup': '导入群',\n 'dp.createDirectProduct': '创建直积 G×H',\n 'dp.storeGroup': '储存直积群',\n 'dp.groupList': '直积群列表',\n 'dp.noGroups': '暂无直积群',\n 'dp.enterMode': '进入直积视图',\n 'dp.exitMode': '退出直积视图',\n 'dp.workspace': '直积工作区',\n 'dp.dragHint': '将一个群拖放到另一个群的节点上以创建直积',\n 'dp.tableDragHint': '将 H 的元素拖放到 G 来执行直积',\n 'dp.creating': '创建直积群...',\n 'dp.created': '已创建直积群: {symbol} (阶={order})',\n 'dp.selectBoth': '请先导入 G 和 H',\n 'dp.animation': '直积动画演示中...',\n 'dp.orderTooLarge': '直积群阶数过大 ({n})',\n 'dp.directHint': '选择两个群类型来创建直积群',\n 'dp.paramN': '参数 n',\n 'dp.paramM': '参数 m',\n 'dp.create': '创建 {a} × {b}',\n 'dp.storeHint': '已储存直积群: {symbol}',\n 'dp.removeHint': '已移除直积群: {symbol}',\n 'dp.exportGif': '导出 GIF',\n 'dp.exporting': '导出中...',\n 'dp.exportCayleyHint': '导出动图: 外环 = {tgt} (H), 内部嵌套 = {src} (G) → 直积群',\n\n /* Semidirect Product */\n 'sd.title': '半直积',\n 'sd.enterMode': '进入半直积模式',\n 'sd.exitMode': '退出半直积模式',\n 'sd.normalSubgroup': '正规子群 N',\n 'sd.actingGroup': '作用群 H',\n 'sd.importAsN': '导入当前群为 N',\n 'sd.importAsH': '导入当前群为 H',\n 'sd.computeAut': '计算 Aut(N)',\n 'sd.autComputed': 'Aut(N) 已计算,共 {n} 个自同构',\n 'sd.autTooLarge': 'Aut(N) 太大,无法计算',\n 'sd.phiMapping': 'φ: H → Aut(N) 生成元映射',\n 'sd.expandPhi': '扩张 φ 到全体',\n 'sd.phiValid': 'φ 是同态',\n 'sd.phiInvalid': 'φ 不满足同态条件',\n 'sd.create': '创建半直积 N ⋊_φ H',\n 'sd.storeGroup': '储存半直积群',\n 'sd.groupList': '半直积群列表',\n 'sd.noGroups': '暂无半直积群',\n 'sd.selectGroup': '选择群...',\n 'sd.selectBoth': '请先选择 N 和 H',\n 'sd.selectNFirst': '请先选择正规子群 N',\n 'sd.selectBothInPanel': '请在左侧面板选择 N 和 H',\n 'sd.mapAllGens': '请为所有生成元设置映射',\n 'sd.extendFailed': 'φ 扩张失败',\n 'sd.orderTooLarge': '半直积群阶数过大 ({n})',\n 'sd.createFailed': '半直积群创建失败',\n 'sd.storeHint': '已储存半直积群: {symbol}',\n 'sd.removeHint': '已移除半直积群: {symbol}',\n 'sd.created': '已创建半直积群: {symbol} (阶={order})',\n 'sd.decomposeHint': '已导入半直积分解: {symbol},N/H 与 φ 已就绪',\n 'sd.decomposeTitle': '半直积分解',\n 'sd.decomposeCount': '找到 {n} 个半直积分解,已自动载入第 1 个',\n 'sd.decomposeSES': '分裂短正合列',\n 'sd.decomposeVerified': '已验证(重建群同构)',\n 'sd.decomposeUnverified': '未验证(重建群结构不符)',\n 'sd.decomposeSelect': '点击载入该分解',\n 'sd.noDecomposition': '群 {symbol} 没有半直积分解(无正规子群 N 与互补子群 H 满足 N∩H={e})',\n 'sd.dragHint': '拖拽中心 + 以构建半直积',\n 'sd.clickCreate': '配置好 φ 后点击下方按钮创建',\n 'sd.finish': '完成',\n 'sd.phase1': '第一步:从作用群 H 的凯莱图开始(骨架)',\n 'sd.phase2': '第二步:结点膨胀,嵌入按 φ(h) 重布线的副本',\n 'sd.phase3': '第三步:用 H 的箭头连接各副本的对应结点',\n 'sd.phase4': '第四步:半直积群完成',\n 'sd.autoPlay': '自动播放',\n 'sd.phaseTitle': '半直积动画',\n 'sd.dropToCreate': '松开以创建 N ⋊_φ H',\n 'pres.title': '群展示',\n 'pres.placeholder': '输入群展示…(例:⟨a, b | a², b³, (ab)³⟩ 或 ⟨a | a^4⟩)',\n 'pres.presets': '预设展示',\n 'pres.create': '创建群',\n 'pres.clear': '清除',\n 'pres.preview': '预览',\n 'pres.groups': '已创建的展示群',\n 'pres.noGroups': '暂无展示群',\n 'pres.created': '已创建群:{symbol}(阶={order})',\n 'pres.createdIso': '已创建群:{symbol}(阶={order},同构于 {iso})',\n 'pres.error.parse': '语法错误:{msg}',\n 'pres.error.parseText': '展示无效:请检查生成元与关系词',\n 'pres.error.infinite': '该展示定义的是无限群',\n 'pres.error.overflow': '群过大或陪集枚举超限',\n 'pres.error.unconnected': '生成元作用不连通(生成元未生成整个群)',\n 'pres.error.empty': '请输入群展示',\n 'pres.storeHint': '已储存展示群:{symbol}',\n 'pres.removeHint': '已移除展示群:{symbol}',\n 'pres.loadHint': '已加载展示群:{symbol}(阶={order})',\n 'pres.views': '展示视图',\n 'pres.create.tabDirect': '直接创建',\n 'pres.create.tabVisual': '可视化创建',\n 'pres.clearGroup': '清空当前群(回到模板树)',\n 'pres.visual.template': '生成元模板',\n 'importGroup.placeholder': '输入群记号,如 PSL(2,7)、C_3×D_4 或 SmallGroup(16,13)',\n 'importGroup.samples': '示例',\n 'importGroup.order': '阶',\n 'importGroup.orderUnknown': '阶未知',\n 'importGroup.pathLocal': '本地直接创建',\n 'importGroup.pathBackend': '后端 GAP 导入',\n 'importGroup.import': '导入群',\n 'importGroup.loading': '导入中…',\n 'importGroup.error.empty': '请输入群记号',\n 'importGroup.error.semidirect': '半直积记号需要自同态 φ,请改用 SmallGroup(n,i) 记号',\n 'importGroup.error.unknown': '无法识别的群记号',\n 'importGroup.error.noRoute': '该记号既不能本地创建也没有可用的 GAP 路径',\n 'importGroup.error.backend': '后端未运行或 GAP 不可用,请先启动后端服务',\n 'importGroup.error.fetch': '导入失败:{msg}',\n 'pres.visual.relation': '输入一条关系(f = e 或 f1 = f2)',\n 'pres.visual.relationPlaceholder': '例 a^3=e 或 ab=ba',\n 'pres.visual.add': '确定',\n 'pres.visual.list': '已添加关系',\n 'pres.visual.finish': '结束并创建群 → 查看退化树',\n 'pres.visual.invalid': '关系格式需为 f=e 或 f1=f2(词由生成元组成,支持 ^n 与 ⁻¹)',\n 'pres.visual.infinite': '当前关系集为无限群,无法创建',\n 'pres.visual.order': '|G| = {n}',\n 'right.presentation': '群展示',\n\n /* Homomorphism */\n 'homo.title': '群同态',\n 'homo.source': '定义域 G',\n 'homo.target': '陪域 H',\n 'homo.savedList': '已保存同态 ({n})',\n 'homo.activate': '激活',\n 'homo.autoMap': '自动映射',\n 'homo.trivial': '平凡映射',\n 'homo.projection': '自然投影',\n 'homo.dpProjection': '直积投影 ({factor})',\n 'homo.generatorHint': '在画布上拖拽元素来定义生成元映射',\n 'homo.fullPreview': '完整预览 ({m}/{n})',\n 'homo.verify': '验证同态',\n 'homo.clear': '清除',\n 'homo.create': '保存同态',\n 'homo.openView': '打开同态视图',\n 'homo.viewSection': '同态视图',\n 'homo.valid': '同态成立',\n 'homo.invalid': '不满足同态条件',\n 'homo.kernel': '核 Ker',\n 'homo.image': '像 Im',\n 'homo.injective': '单射',\n 'homo.notInjective': '非单射',\n 'homo.surjective': '满射',\n 'homo.notSurjective': '非满射',\n 'homo.isomorphism': '同构',\n 'homo.firstIso': '第一同构定理',\n 'homo.theoremMode': '定理模式 →',\n 'homo.firstIso.needValid': '需要一个有效的同态映射',\n 'homo.firstIso.needValidHint': '请先验证同态映射',\n 'homo.firstIso.phase0': 'f: G \\\\to H',\n 'homo.firstIso.phase1': 'K = \\\\ker f \\\\subsetneq G',\n 'homo.firstIso.phase2': '\\\\pi: G \\\\to G/K',\n 'homo.firstIso.phase3': 'G/K \\\\cong \\\\operatorname{Im} f',\n 'homo.firstIso.phase0Desc': '同态 f 将 G 中的运算保持地映到 H',\n 'homo.firstIso.phase1Desc': '核 K 是所有映到单位元的元素,且 K 是正规子群',\n 'homo.firstIso.phase2Desc': '自然投影 π 把 G 压成商群 G/K,陪集按纤维着色',\n 'homo.firstIso.phase3Desc': '第一同构定理:G/K ≅ Im f,由 f 诱导的商群同构',\n 'homo.selectSourceFirst': '请先选择定义域群',\n 'homo.interactiveHint': '拖拽元素来定义映射',\n 'homo.created': '已创建同态: {source} → {target}',\n 'homo.verified': '同态验证通过: {source} → {target}',\n 'homo.saved': '同态已保存',\n 'homo.trivialApplied': '已应用平凡映射',\n 'homo.projectionApplied': '已应用自然投影',\n 'homo.projectionFailed': '投影映射失败: 没有正规子群',\n 'homo.inclusionApplied': '已应用包含映射',\n 'homo.inclusionFailed': '包含映射失败',\n 'homo.dpProjectionApplied': '已应用直积投影 ({factor})',\n 'homo.dpProjectionFailed': '直积投影失败',\n\n /* Quotient */\n 'quotient.title': '商群',\n 'quotient.boundHint': '选择一个正规子群来构建商群 G/N',\n 'quotient.create': '创建商群',\n 'quotient.load': '加载',\n 'quotient.noQuotient': '暂无商群',\n\n /* Automorphism */\n 'automorphism.title': '自同构群',\n 'automorphism.boundHint': '计算当前群的自同构群 Aut(G)',\n 'automorphism.compute': '计算 Aut(G)',\n 'automorphism.load': '加载',\n 'automorphism.noAutomorphism': '暂无自同构群',\n\n /* Group Action */\n 'action.title': '群作用',\n 'action.kind.conjugation': '共轭作用',\n 'action.kind.custom': '自定义作用',\n 'action.kind.sylow': 'Sylow {p}-子群共轭作用',\n 'action.kind.regular': '左平移作用(正则表示)',\n 'action.kind.coset': '陪集作用',\n 'action.create.conjugation': '共轭作用',\n 'action.create.custom': '自定义作用',\n 'action.create.regular': '左平移(Cayley)',\n 'action.create.coset': '陪集作用',\n 'action.create.sylow': 'Sylow p-作用',\n 'action.setSize': '集合大小 |X|',\n 'action.startEdit': '开始编辑',\n 'action.editHint': '点击元素选择起点,箭头跟随鼠标移动,点击目标元素部署(选中生成元后直接绑定);点击起点自身 = 固定点(自环);点击已部署箭头删除;点击空白取消',\n 'action.genSelectHint': '拖动生成元到虚线箭头上,或点击生成元选中后点击虚线完成绑定',\n 'action.dropHint': '松开以绑定',\n 'action.cycleCandidates': '候选循环:',\n 'action.cycleUnit': '循环',\n 'action.editingSource': '选择 {x} 的去向',\n 'action.finish': '完成并验证',\n 'action.clear': '清除',\n 'action.exit': '退出编辑',\n 'action.valid': '同态成立,作用合法',\n 'action.invalid': '不满足同态条件,作用不合法',\n 'action.draftRestored': '已恢复上次保存的自定义作用草稿',\n 'action.saved': '自定义群作用已保存到列表',\n 'action.activated': '已恢复群作用',\n 'action.savedList': '已保存的群作用',\n 'action.activate': '激活',\n 'action.created': '已创建{kind}',\n 'action.violation': 'Φ({g}·{a}) ≠ Φ({g})∘Φ({a})(在 {x} 处)',\n 'action.orbitCount': '轨道数: {n}',\n 'action.fixedPoints': '稳定元: {n}',\n 'action.sumCheck': 'Σ|Orb| = |X|: {sum} = {n}',\n 'action.ost': '|Orb(x)|·|Stab(x)| = {orbit}·{stab} = {product} = |G|',\n 'action.stabilizer': 'Stab({x})',\n 'action.orbitStab': '|Orb({x})| = {orbit},|Stab({x})| = {stab}',\n 'action.noAction': '在左侧面板创建群作用',\n 'action.error.range': '箭头 {from}→{to} 超出集合范围',\n 'action.error.unbound': '存在未绑定的箭头',\n 'action.error.duplicate-source': '生成元 {gen} 重复指定了源 {from}',\n 'action.error.conflict-target': '生成元 {gen} 的目标 {to} 被多个源指向',\n 'action.error.missing-target': '目标 {to} 需要去向:{gen} 未定义它的像',\n 'action.error.unknown-generator': '未知生成元: {gen}',\n 'action.error.homomorphism': '不满足同态:Φ({g}·{gen}) ≠ Φ({g})∘Φ({gen})(在 {x} 处),请修正箭头',\n 'action.viewBlurb': '每个圆圈 = 一个轨道(共轭作用时即共轭类);弧线 = 生成元的作用,颜色对应生成元',\n 'action.showing': '正在显示元素 ',\n 'action.conjSuffix': ' 的共轭作用:x ↦ g·x·g⁻¹',\n 'action.arrowSuffix': ' 的全部作用箭头',\n 'action.orbitGroup': '轨道 · {size} 元素',\n 'action.viewTitle.conjugation': '共轭作用:G 作用于自身,g·x = g·x·g⁻¹(轨道 = 共轭类)',\n 'action.viewTitle.custom': '自定义作用:G 作用于集合 X',\n 'action.viewTitle.sylow': 'Sylow {p}-子群:G 共轭作用于 Syl_p(G)(轨道 = 全部 Sylow p-子群,|Syl_p(G)| = n_p)',\n 'action.viewTitle.regular': '左平移作用(正则表示):G 作用于自身,g·x = g·x;轨道唯一且自由 ⇒ Cayley 定理:G ≅ Sym(G) 的子群',\n 'action.viewTitle.coset': '陪集作用:G 作用于左陪集 G/H,g·(xH) = (gx)H;传递作用,Stab(xH) = xHx⁻¹(共轭于 H)',\n 'action.coset.selectSubgroup': '选择子群 H(陪集作用用)…',\n 'action.coset.noSubgroups': '群过大(>60),未枚举子群',\n 'action.math.regular': '正则表示:G ≅ Sym(G) 嵌入',\n 'action.math.regularNote': 'Stab(x) = {e}(自由)',\n 'action.math.cosetStab': 'Stab(xH) = xHx⁻¹',\n 'action.math.cosetStabNote': '≅ H',\n 'action.math.cosetTransitive': '传递作用(唯一轨道)',\n 'action.math.fixedCenter': '固定点 = 中心 Z(G)',\n 'action.math.burnside': 'Burnside:|X/G| = (1/|G|)·Σ|Fix(g)|',\n 'action.edgeBlurb': '弧线 = 生成元的作用:x → g·x,颜色对应生成元(图例)',\n 'action.hoverElEdges': '金色弧线 = {el} 的全部作用:对每个 x 画出 x → g·x',\n 'action.hoverGenEdges': '高亮弧线 = 生成元 {gen} 的作用',\n 'action.selHint': '选中元素 x:轨道与稳定化子信息见右侧面板',\n 'action.stabilizerFor': '元素 {el} 的稳定子 G_x',\n 'action.closeStab': '关闭',\n 'right.actionInfo': '群作用信息',\n\n /* Sylow View */\n 'sylowView.selectP': '素数 p',\n 'sylowView.pElements': 'p-元素',\n 'sylowView.pSubgroups': 'p-子群',\n 'sylowView.sylowSubgroups': 'Sylow p-子群',\n 'sylowView.otherPSubgroups': '其他 p-子群',\n 'sylowView.none': '无 p-子群(p 不整除 |G|)',\n 'sylowView.legendSelected': '选中子群元素',\n 'sylowView.legendP': 'p-元素(阶为 p 的幂)',\n 'sylowView.legendOther': '其他元素',\n 'sylowView.legendEdges': '边 = 生成元作用(颜色对应)',\n 'sylowView.edgeAction': '边作用',\n 'sylowView.edgeActionDefault': '群生成元',\n 'sylowView.edgeHint': '点击子群,边切换为该子群生成元作用', 'sylowView.twoSelectHint': 'Ctrl/⌘ 或 ⊕ 点击第二个子群 → 共轭视图(Sylow 第二定理)', 'sylowView.addSecond': '⊕ 加入为第二个子群(复选)',\n 'sylowView.conjLabel': '共轭',\n 'sylowView.noConjugator': '未找到共轭元',\n 'sylowView.legendP2': 'P(上半)',\n 'sylowView.legendQ2': 'Q(下半)',\n 'sylowView.legendI2': 'P∩Q(中间)',\n 'sylowView.legendConj': '箭头 = 共轭 x ↦ gxg⁻¹',\n 'sylowView.collapseList': '收起子群列表',\n 'sylowView.expandList': '展开子群列表',\n\n /* Theme Toggle */\n 'theme.dark': '深色模式',\n 'theme.light': '浅色模式',\n 'theme.switchToLight': '切换浅色模式',\n 'theme.switchToDark': '切换深色模式',\n}\n\nconst en: TranslationMap = {\n /* App */\n 'app.title': 'GroupViz - Group Theory Visualization',\n 'app.header': 'GroupViz - Group Theory Visualization',\n 'ui.openToolbar': 'Open Toolbar',\n 'ui.openInfo': 'Open Info Panel',\n 'ui.computing': 'Computing',\n 'theme.viewWindowDark': 'View windows: switch to light',\n 'theme.viewWindowLight': 'View windows: switch to dark',\n\n /* Welcome Page */\n 'welcome.subtitle': 'Group Theory Visualization Platform',\n 'welcome.version': 'v2.1.4',\n 'welcome.tagline': 'Explore the beauty of symmetry in abstract algebra — Interactive group theory visualization & learning tool',\n 'welcome.enter': 'Enter',\n 'welcome.section.done': 'Implemented',\n 'welcome.section.soon': 'Coming Soon',\n 'welcome.item.subgroups': 'Subgroups & Cosets',\n 'welcome.item.cayley': 'Cayley Graph',\n 'welcome.item.table': 'Multiplication Table',\n 'welcome.item.build': 'Group Construction',\n 'welcome.item.homomorphism': 'Homomorphisms',\n 'welcome.item.presentation': 'Group Presentations',\n 'welcome.soon.education': 'Education Mode',\n 'welcome.soon.freegroup': 'Free Groups',\n 'welcome.soon.dlc': 'DLC (Space/Point Groups)',\n 'welcome.feature.subgroups': 'Subgroups & Cosets',\n 'welcome.feature.cayley': 'Cayley Graph',\n 'welcome.feature.multigroup': 'Multi-Group Support',\n 'welcome.feature.table': 'Multiplication Table',\n 'welcome.feature.3d': '3D Visualization',\n 'welcome.feature.symmetry': 'Symmetry View',\n\n /* Left Panel — Accordion Titles */\n 'panel.createGroup': 'Create Group',\n 'panel.viewMode': 'View Mode',\n 'panel.cayleySettings': 'Cayley Settings',\n 'panel.operations': 'Operations & Subsets',\n 'panel.basicGroup': 'Basic Groups',\n 'panel.importGroup': 'Import by Notation',\n\n /* Left Panel — Group Types */\n 'group.cyclic': 'Cyclic',\n 'group.cyclic.full': 'Cyclic Group Z_n',\n 'group.symmetric': 'Symmetric',\n 'group.symmetric.full': 'Symmetric Group S_n',\n 'group.dihedral': 'Dihedral',\n 'group.dihedral.full': 'Dihedral Group D_n',\n 'group.alternating': 'Alternating',\n 'group.alternating.full': 'Alternating Group A_n',\n 'group.special': 'Special',\n 'group.klein': 'Klein Four-Group',\n 'group.quaternion': 'Quaternion Group',\n 'group.gl2p2': 'GL(2,2) ≅ S₃, order 6',\n 'group.gl2p3': 'GL(2,3), order 48, |SL(2,3)| = 24',\n 'group.direct.z4z2': 'Direct Product',\n 'group.direct.z2cubed': 'Elementary Abelian Group',\n 'group.direct.z3z3': 'Direct Product',\n 'group.direct.z6z2': 'Direct Product',\n 'group.type': 'Type',\n 'group.order': 'Order',\n 'panel.createByType': 'By Group Type',\n 'panel.createByOrder': 'By Order',\n 'panel.order.semidirectHint': '\" : \" in a symbol denotes a semidirect product (e.g. Z₃:C₄ = Dic₃)',\n\n /* Left Panel — View Modes */\n 'view.set': 'Set View',\n 'view.set.desc': 'Element List',\n 'view.cayley': 'Cayley Graph',\n 'view.cayley.desc': '2D Graph',\n 'view.cycle': 'Cycle Graph',\n 'view.cycle.desc': 'Cycle Structure',\n 'view.table': 'Multiplication Table',\n 'view.table.desc': 'Cayley Table',\n 'view.3d': '3D Cayley Graph',\n 'view.3d.desc': '3D Graph',\n 'view.symmetry': 'Symmetry View',\n 'view.symmetry.desc': 'Polyhedra',\n 'view.sublattice': 'Subgroup Lattice',\n 'view.sublattice.desc': 'Subgroup Hierarchy',\n 'view.homomorphism': 'Homomorphism',\n 'view.homomorphism.desc': 'Group Homomorphisms',\n 'view.cosetstrip': 'Coset Strip',\n 'view.cosetstrip.desc': 'Coset Decomposition',\n 'view.action': 'Orbit View',\n 'view.action.desc': 'Group Action',\n 'view.sylow': 'Sylow',\n 'view.sylow.desc': 'p-elements & Sylow p-subgroups',\n 'view.tree': 'Group Tree',\n 'view.prestable': 'Presentation Table',\n 'view.heatmap': 'Heatmap',\n 'view.heatmap.desc': 'Multiplication color map',\n\n /* Free Group Tree / Presentation Table views */\n 'prestable.noPresentation': 'No group presentation ⟨… | …⟩ is available for the current group. Create one in the left \"Group Presentation\" panel, or pick a smaller group.',\n\n /* Left Panel — Buttons & Labels */\n 'panel.create': 'Create {label}',\n 'panel.multiView': 'Multi-View Mode',\n 'panel.floatView': '+ {label}',\n 'panel.showMaximalCycles': 'Show Maximal Cycles Only',\n 'panel.showHeatmap': 'Heatmap mode',\n 'panel.showAction': 'Show Element Action',\n 'panel.speed': 'Speed',\n 'panel.solidShape': 'Solid shape',\n 'panel.solidCube': 'Cube',\n 'panel.solidOcta': 'Octahedron',\n 'panel.solidIcosa': 'Icosahedron',\n 'panel.solidDodeca': 'Dodecahedron',\n 'panel.multiplyType': 'Multiply Type',\n 'panel.multiplyRight': 'Right a·c',\n 'panel.multiplyLeft': 'Left c·a',\n 'panel.shape': 'Shape',\n 'panel.shape.circular': 'Circular',\n 'panel.shape.cone': 'Cone',\n 'panel.shape.grid': 'Grid',\n 'panel.shape.rewiring': 'Rewiring',\n 'panel.shape.concentric': 'Concentric (Conjugacy)',\n 'panel.shape.dualRing': 'Dual Ring (Rotation/Reflection)',\n 'panel.shape.cylinder': 'Interleaved Concentric Circles',\n 'panel.shape.torus': 'Torus (Copies on Ring)',\n 'panel.shape.ringGrid': 'Ring Grid (Ring × Grid)',\n 'panel.shape.cosetStrip': 'Coset Strip',\n 'panel.shape.archimedean': 'Archimedean Spiral',\n 'panel.shape.spiral': 'Spiral',\n 'panel.shape.coil': 'Coil',\n 'panel.shape.projection3D': '3D Planar Projection',\n 'panel.shape.pythagoreanSquare': 'Pythagorean Square',\n 'panel.forceLayout': 'Force-Directed Layout',\n 'panel.elementActions': 'Group Actions ({n}/{m})',\n 'panel.selectAll': 'Select All',\n 'panel.clear': 'Clear',\n 'panel.resetPositions': 'Reset Positions',\n 'panel.decomposeSD': 'Semidirect Decomposition',\n 'panel.decomposeSDDisabled': 'Please select a group first',\n 'panel.subsetManagement': 'Subset Management',\n 'panel.saveAsSubset': 'Save as Subset ({n})',\n 'panel.clearAllSubsets': 'Clear All Subsets',\n 'panel.showCosets': 'Show Cosets',\n 'panel.generateSubgroup': 'Generate Subgroup ⟨E⟩',\n 'panel.normalizer': 'Normalizer N_G(E)',\n 'panel.centralizer': 'Centralizer C_G(E)',\n 'panel.hideCosets': 'Hide Cosets',\n 'panel.showAllCosets': 'Show All Cosets',\n 'panel.showSelected': 'Show Selected',\n 'panel.cosetType': 'Coset Type',\n 'panel.indices': 'Index: {index}',\n 'panel.cosetCount': '{count} cosets total',\n 'panel.inverse': 'Inverse',\n 'panel.clearCanvas': 'Clear Canvas',\n 'panel.exportPng': 'Export PNG',\n 'panel.exportSvg': 'Export SVG',\n 'panel.exportGif': 'Export GIF',\n 'panel.gifOption': 'GIF rotation length',\n 'panel.gif3s': '~3 seconds',\n 'panel.gif5Cycles': '5 rotation cycles',\n 'panel.exportView': 'Export View',\n 'panel.exporting': 'Exporting...',\n 'panel.selectElementFirst': 'Please select an element on the canvas first',\n 'panel.series': 'Subgroup Series',\n\n /* Left Panel — Badges */\n 'badge.normal': 'Normal',\n 'badge.subgroup': 'Subgroup',\n 'badge.center': 'Center',\n\n /* Right Panel */\n 'right.elementProps': 'Element Properties',\n 'right.currentElement': 'Current Element',\n 'right.inverse': 'Inverse',\n 'right.id': 'ID',\n 'right.selectHint': 'Select an element on the canvas to view properties',\n 'right.groupInfo': 'Group Info',\n 'right.groupName': 'Name',\n 'right.symbol': 'Symbol',\n 'right.order': 'Order',\n 'right.generators': 'Generators',\n 'right.abelian': 'Abelian',\n 'right.isomorphic': 'Isomorphic to',\n 'right.isomorphicClick': 'Click to load the isomorphic group',\n 'right.yes': 'Yes',\n 'right.no': 'No',\n 'right.properties': 'Group Properties',\n 'right.propertyTrue': 'Yes',\n 'right.propertyFalse': 'No',\n 'right.propertyUnavailable': 'Property analysis not supported for this group',\n 'right.solvable': 'Solvable',\n 'right.nilpotent': 'Nilpotent',\n 'right.perfect': 'Perfect',\n 'right.derivedSeries': 'Derived Series',\n 'right.structure': 'Structure',\n 'right.structure.direct': 'Direct product',\n 'right.structure.semidirect': 'Semidirect product',\n 'right.structure.indecomposable': 'Indecomposable',\n 'right.structure.unknown': 'Unknown',\n 'right.center': 'Center Z(G)',\n 'right.noGroup': 'Please select a group first',\n 'right.simpleGroup': 'Simple Group',\n 'right.subgroups': 'Subgroups ({n})',\n 'right.noSubgroups': 'No subgroups',\n 'right.loadingBackend': 'Computing via backend...',\n 'right.conjugacyClasses': 'Conjugacy Classes ({n})',\n 'right.noClasses': 'No classes',\n 'right.elementList': 'Element List ({n})',\n 'right.homomorphism': 'Homomorphism',\n 'right.homo.kernel': 'Kernel Ker',\n 'right.homo.image': 'Image Im',\n 'right.homo.quotient': 'Quotient G/Ker',\n 'right.homo.noActive': 'No active homomorphism',\n 'right.automorphismMapping': 'Automorphism Mapping',\n 'right.automorphismFixed': 'fixed points',\n\n /* Subgroup Lattice */\n 'lattice.trivial': 'Trivial',\n 'lattice.subgroup': 'Subgroup',\n 'lattice.sylow': 'Sylow {p}',\n 'lattice.labelDetail': 'Label detail',\n 'lattice.label.auto': 'Auto',\n 'lattice.label.full': 'Full cards',\n 'lattice.label.compact': 'Pills',\n 'lattice.label.dots': 'Dots',\n 'lattice.mergeConjugates': 'Merge conjugate subgroups',\n 'lattice.mergeHint': 'One node per conjugacy orbit; the ×n badge is |G : N_G(H)|',\n 'lattice.nodeSize': 'Card size',\n 'lattice.showSeriesPanel': 'Series panel',\n 'lattice.orbitMembers': '{n} conjugate subgroups',\n 'lattice.captionHint': 'Hover or click a node for structure, index and normalizer',\n 'lattice.mergeTooLarge': 'Too many subgroups to merge; showing the unmerged lattice',\n 'lattice.backendOnly': 'Subgroup lattices beyond order 60 need the backend; open this group in the main workspace',\n\n /* Subgroup Series */\n 'series.off': 'Off',\n 'series.derived': 'Derived',\n 'series.upperCentral': 'Upper Central',\n 'series.lowerCentral': 'Lower Central',\n 'series.composition': 'Composition',\n 'series.chain': 'Chain',\n 'series.alternativeChains': '{n} composition chains',\n 'series.factors': 'Composition factors',\n 'series.jordanHolder': 'Jordan–Hölder: unique factor multiset',\n 'series.solvable': 'Solvable',\n 'series.nilpotent': 'Nilpotent',\n 'series.tooLarge': 'Order exceeds 240; local series computation skipped',\n 'series.loading': 'Computing series via backend (GAP)…',\n 'series.truncated': 'More than 20 chains; showing first 20',\n\n /* Cayley 3D Legend */\n 'cayley3d.multiplyRight': 'Right Multiply',\n 'cayley3d.multiplyLeft': 'Left Multiply',\n 'cayley3d.autoRotate': 'Auto Rotate',\n 'cayley3d.resetView': 'Reset View',\n 'cayley.action.enabled': 'Enabled',\n 'cayley.action.disabled': 'Disabled',\n 'cayley.action.byElement': 'by element',\n 'hint.cayleyActionNonGenerator': 'Cayley edges in this app are defined by arbitrary element actions (not limited to generators)',\n\n /* Symmetry View */\n 'symmetry.reset': 'Resetting...',\n 'symmetry.rotating': 'Rotating...',\n 'symmetry.clickHint': 'Click an element to see its symmetry action on the polyhedron',\n 'symmetry.selectHint': 'Select an element on canvas to see its effect on the geometry',\n 'symmetry.demoOff': 'Element action demo turned off',\n 'symmetry.unsupported': 'This group type does not support symmetry view yet',\n 'symmetry.supported': 'Supported groups: Cyclic C_n · Dihedral D_n · A_4 · S_4 · A_5 · V_4',\n 'symmetry.toCube': '→ Cube',\n 'symmetry.toOctahedron': '→ Octahedron',\n 'symmetry.toIcosahedron': '→ Icosahedron',\n 'symmetry.toDodecahedron': '→ Dodecahedron',\n\n /* Symmetry Geometry Descriptions (shape names; group symbol is shown in the scene title line) */\n 'symmetry.geo.cyclicText': '{n}-fold rotational symmetry',\n 'symmetry.geo.dihedralText': 'Regular {n}-gon',\n 'symmetry.geo.tetrahedron': 'Regular Tetrahedron',\n 'symmetry.geo.cube': 'Cube',\n 'symmetry.geo.octahedron': 'Regular Octahedron',\n 'symmetry.geo.icosahedron': 'Regular Icosahedron',\n 'symmetry.geo.dodecahedron': 'Regular Dodecahedron',\n 'symmetry.geo.rectangle': 'Rectangle',\n\n /* Canvas Common */\n 'canvas.noGroup': 'Please select a group first',\n 'canvas.noGroupCreate': 'Please create or select a group first',\n 'canvas.orderTooLarge': 'Group order is too large (|G| = {n})',\n 'canvas.show': 'Show',\n 'canvas.hintBox': 'Hints',\n 'canvas.history': 'History',\n 'canvas.cosetStripNoSubgroup': 'Select a subgroup to view cosets',\n 'canvas.cosetStripNoCosets': 'Click a subgroup in the right panel to view cosets',\n 'canvas.cosetStripCayley': 'Subgroup Cayley graph ⟨H⟩',\n 'canvas.tableSampled': 'Showing sampled rows and columns for large groups.',\n\n /* TableView */\n 'table.footer1': 'Column × Row = Result',\n 'table.footer2': 'Color corresponds to the result element',\n 'table.strategy.subgroup': 'Subgroup',\n 'table.strategy.random': 'Random',\n 'table.strategy.full': 'Full',\n 'table.subgroupCaption': 'Subgroup {label} (|H| = {order})',\n 'table.randomCaption': 'Random sample of {n} elements',\n 'table.heatmapAggCaption': 'Full table |G| = {n}, heatmap thumbnail {res}×{res} (mode blocks)',\n 'table.fullConfirmTitle': 'Confirm full table',\n 'table.fullConfirmMsg': 'This group has order |G| = {n}. Showing the full table enters fullscreen mode and may use noticeable memory. Continue?',\n 'table.confirmOk': 'OK',\n 'table.confirmCancel': 'Cancel',\n 'table.fullTitle': '{symbol} — Full multiplication table (|G| = {n})',\n 'table.fullExit': 'Exit fullscreen',\n 'table.fullExport': 'Export SVG',\n 'table.fullZoomIn': 'Zoom in',\n 'table.fullZoomOut': 'Zoom out',\n 'table.fullZoomReset': 'Reset zoom',\n 'table.zoomSlider': 'Zoom slider',\n 'table.fullPlaceholderMsg': 'The full table |G| = {n} is large; fullscreen mode has been applied',\n 'table.fullEnter': 'Enter fullscreen',\n\n /* Hint Messages */\n 'hint.groupSelected': 'Selected {name} (order = {order})',\n 'hint.groupCleared': 'Current group cleared',\n 'hint.cayley': 'Cayley Graph — Drag nodes to move | {count} active actions | {type}',\n 'hint.cayley3d': '3D Cayley Graph — Drag to rotate, scroll to zoom | {count} edges | Shape: {shape}',\n 'hint.symmetry': 'Symmetry View — Displays geometric symmetry objects | Drag to rotate, scroll to zoom',\n 'hint.sublattice': 'Subgroup Lattice — Click node to select elements | Drag to pan, scroll to zoom',\n 'hint.cycle': 'Cycle Graph — Each polygon is a cyclic subgroup ⟨g⟩ ≅ Z<sub>n</sub>',\n 'hint.tree': 'Group Tree view — the \"degenerated tree\" of ⟨S|R⟩ (BFS spanning tree of the quotient Cayley graph): solid edges = spanning tree (colored by generator); glued edges are not drawn, their count shown in the top bar | Scroll to zoom, drag to pan, double-click to reset, click a node to show its word',\n 'hint.prestable': 'Presentation Table — row × col = result, click a cell to select the element',\n 'hint.switchedTo': 'Switched to {viewLabel}',\n 'hint.elementSelected': 'Selected: {label}',\n 'hint.layoutDone': 'Layout optimization complete',\n 'hint.layoutComputing': 'Computing layout...',\n 'hint.cayleyMultiply': 'Cayley multiply type: {label}',\n 'hint.cayleyCleared': 'Cayley graph edges cleared',\n 'hint.cayleyShape': '3D Cayley shape: {shape}',\n 'hint.subsetSaved': 'Subset saved: {label} ({n} elements)',\n 'hint.symmetryAction': 'Show element action: {label}',\n 'hint.multiViewOn': 'Multi-view enabled — Click view buttons to open floating windows',\n 'hint.multiViewOff': 'Multi-view disabled — All floating windows closed',\n 'hint.cosetShow': 'Coset mode — cosets of selected elements highlighted | Subgroup: {label} (order={order})',\n 'hint.cosetHide': 'Coset mode disabled',\n 'hint.cosetType': 'Coset type: {label}',\n 'hint.cosetAll': 'All cosets shown — Verifying Lagrange: |G| = |H| × [G:H]',\n 'hint.cosetSelect': 'Select elements to highlight their cosets',\n 'hint.layoutFailed': 'Layout optimization failed, please retry',\n 'hint.quotientCreated': 'Quotient group {symbol} created (order = {order})',\n 'hint.quotientCreatedIso': 'Quotient group {symbol} created (order = {order}) — isomorphic to {isoSymbol}',\n 'hint.automorphismComputed': 'Automorphism group Aut({symbol}) computed (order = {order})',\n 'hint.automorphismComputedIso': 'Automorphism group Aut({symbol}) computed (order = {order}) — isomorphic to {isoSymbol}',\n\n /* Operation History */\n 'op.loadGroup': 'Load {name} (|G|={order})',\n 'op.switchView': 'Switch view: {view}',\n 'op.layout': 'Layout: {view}',\n 'op.checkSubset': 'Check subset: {label}',\n 'op.inverseRequest': 'Select an element to compute inverse',\n 'op.inverseDone': 'Inverse: ({label})^{-1} = {result}',\n 'op.clearCanvas': 'Clear Canvas',\n 'op.generateSubgroup': 'Generate subgroup (TBD)',\n 'op.setCayleyMultiply': 'Set Cayley multiply: {label}',\n 'op.clearCayley': 'Clear Cayley edges',\n 'op.setShape': 'Set 3D shape: {shape}',\n 'op.saveSubset': 'Save subset: {label} ({n} items)',\n 'op.removeSubset': 'Remove subset',\n 'op.clearSubsets': 'Clear all subsets',\n 'op.multiViewOn': 'Enable multi-view',\n 'op.multiViewOff': 'Disable multi-view',\n 'op.openFloatView': 'Open floating view: {viewLabel}',\n 'op.cosetShow': 'Show cosets: {label}',\n 'op.cosetHide': 'Hide cosets',\n 'op.cosetType': 'Switch coset type: {label}',\n 'op.cosetAll': 'Show all cosets',\n 'op.cosetSelect': 'Show cosets by selection',\n 'op.createQuotient': 'Create quotient group {parent} (order = {order})',\n 'op.removeQuotient': 'Remove quotient group',\n 'op.computedAutomorphism': 'Computed automorphism group Aut({symbol}) (order = {order})',\n 'op.removeAutomorphism': 'Remove automorphism group',\n\n /* Subset Results */\n 'subset.plain': 'Plain Subset',\n 'subset.subgroup': 'Subgroup',\n 'subset.normalSubgroup': 'Normal Subgroup',\n\n /* Coset */\n 'coset.left': 'Left Coset',\n 'coset.right': 'Right Coset',\n\n /* Language Toggle */\n 'lang.zh': '简体中文',\n 'lang.en': 'English',\n\n /* Direct Product */\n 'dp.title': 'Direct Product',\n 'dp.mode': 'Creation Mode',\n 'dp.mode.cayley': 'Cayley Graph',\n 'dp.mode.table': 'Mult. Table',\n 'dp.mode.direct': 'Direct Create',\n 'dp.sourceGroup': 'G',\n 'dp.targetGroup': 'H',\n 'dp.selectGroup': 'Select Group...',\n 'dp.importGroup': 'Import',\n 'dp.createDirectProduct': 'Create G×H',\n 'dp.storeGroup': 'Store Group',\n 'dp.groupList': 'Direct Product Groups',\n 'dp.noGroups': 'No direct product groups',\n 'dp.enterMode': 'Enter Direct Product View',\n 'dp.exitMode': 'Exit Direct Product View',\n 'dp.workspace': 'Direct Product Workspace',\n 'dp.dragHint': 'Drag one group onto a node of the other group to create a direct product',\n 'dp.tableDragHint': 'Drag H elements onto G to perform direct product',\n 'dp.creating': 'Creating direct product...',\n 'dp.created': 'Created direct product: {symbol} (order={order})',\n 'dp.selectBoth': 'Please import G and H first',\n 'dp.animation': 'Direct product animation...',\n 'dp.orderTooLarge': 'Direct product order too large ({n})',\n 'dp.directHint': 'Select two group types to create a direct product group',\n 'dp.paramN': 'Parameter n',\n 'dp.paramM': 'Parameter m',\n 'dp.create': 'Create {a} × {b}',\n 'dp.storeHint': 'Stored direct product: {symbol}',\n 'dp.removeHint': 'Removed direct product: {symbol}',\n 'dp.exportGif': 'Export GIF',\n 'dp.exporting': 'Exporting...',\n 'dp.exportCayleyHint': 'Exporting GIF: outer ring = {tgt} (H), inner cluster = {src} (G) → direct product',\n\n /* Semidirect Product */\n 'sd.title': 'Semidirect',\n 'sd.enterMode': 'Enter Semidirect Mode',\n 'sd.exitMode': 'Exit Semidirect Mode',\n 'sd.normalSubgroup': 'Normal Subgroup N',\n 'sd.actingGroup': 'Acting Group H',\n 'sd.importAsN': 'Import current as N',\n 'sd.importAsH': 'Import current as H',\n 'sd.computeAut': 'Compute Aut(N)',\n 'sd.autComputed': 'Aut(N) computed: {n} automorphisms',\n 'sd.autTooLarge': 'Aut(N) is too large to compute',\n 'sd.phiMapping': 'φ: H → Aut(N) Gen Mapping',\n 'sd.expandPhi': 'Expand φ',\n 'sd.phiValid': 'φ is a homomorphism',\n 'sd.phiInvalid': 'φ is NOT a homomorphism',\n 'sd.create': 'Create N ⋊_φ H',\n 'sd.storeGroup': 'Store Group',\n 'sd.groupList': 'Semidirect Groups',\n 'sd.noGroups': 'No semidirect groups',\n 'sd.selectGroup': 'Select group...',\n 'sd.selectBoth': 'Select N and H first',\n 'sd.selectNFirst': 'Select normal subgroup N first',\n 'sd.selectBothInPanel': 'Select N and H in the left panel',\n 'sd.mapAllGens': 'Map all generators first',\n 'sd.extendFailed': 'φ extension failed',\n 'sd.orderTooLarge': 'Semidirect product order too large ({n})',\n 'sd.createFailed': 'Semidirect product creation failed',\n 'sd.storeHint': 'Stored semidirect group: {symbol}',\n 'sd.removeHint': 'Removed semidirect group: {symbol}',\n 'sd.created': 'Created semidirect group: {symbol} (order={order})',\n 'sd.decomposeHint': 'Semidirect decomposition imported: {symbol}, N/H and φ are ready',\n 'sd.decomposeTitle': 'Semidirect Decompositions',\n 'sd.decomposeCount': 'Found {n} semidirect decompositions, first one loaded',\n 'sd.decomposeSES': 'Split short exact sequence',\n 'sd.decomposeVerified': 'Verified (rebuilt group is isomorphic)',\n 'sd.decomposeUnverified': 'Unverified (rebuilt group structure mismatch)',\n 'sd.decomposeSelect': 'Click to load this decomposition',\n 'sd.noDecomposition': 'Group {symbol} has no semidirect decomposition (no normal N and complement H with N∩H={e})',\n 'sd.dragHint': 'Drag + handle to build semidirect',\n 'sd.dropToCreate': 'Drop to create N ⋊_φ H',\n 'pres.title': 'Group Presentation',\n 'pres.placeholder': 'Enter a group presentation… (e.g. ⟨a, b | a², b³, (ab)³⟩ or ⟨a | a^4⟩)',\n 'pres.presets': 'Presets',\n 'pres.create': 'Create Group',\n 'pres.clear': 'Clear',\n 'pres.preview': 'Preview',\n 'pres.groups': 'Created Presentation Groups',\n 'pres.noGroups': 'No presentation groups yet',\n 'pres.created': 'Group created: {symbol} (order {order})',\n 'pres.createdIso': 'Group created: {symbol} (order {order}, isomorphic to {iso})',\n 'pres.error.parse': 'Parse error: {msg}',\n 'pres.error.parseText': 'Invalid presentation: check generators and relators',\n 'pres.error.infinite': 'This presentation defines an infinite group',\n 'pres.error.overflow': 'Group too large or coset enumeration limit exceeded',\n 'pres.error.unconnected': 'Generator action is not connected (generators do not generate the whole group)',\n 'pres.error.empty': 'Please enter a group presentation',\n 'importGroup.placeholder': 'Type a group notation, e.g. PSL(2,7), C_3×D_4 or SmallGroup(16,13)',\n 'importGroup.samples': 'Samples',\n 'importGroup.order': 'Order',\n 'importGroup.orderUnknown': 'Order unknown',\n 'importGroup.pathLocal': 'Built locally',\n 'importGroup.pathBackend': 'Imported via backend GAP',\n 'importGroup.import': 'Import Group',\n 'importGroup.loading': 'Importing…',\n 'importGroup.error.empty': 'Type a group notation',\n 'importGroup.error.semidirect': 'Semidirect notation needs the automorphism φ — use SmallGroup(n,i) instead',\n 'importGroup.error.unknown': 'Unrecognized group notation',\n 'importGroup.error.noRoute': 'This notation can neither be built locally nor mapped to a GAP expression',\n 'importGroup.error.backend': 'Backend is not running or GAP is unavailable — start the backend first',\n 'importGroup.error.fetch': 'Import failed: {msg}',\n 'pres.storeHint': 'Presentation group stored: {symbol}',\n 'pres.removeHint': 'Presentation group removed: {symbol}',\n 'pres.loadHint': 'Presentation group loaded: {symbol} (order {order})',\n 'pres.views': 'Views',\n 'pres.create.tabDirect': 'Direct Create',\n 'pres.create.tabVisual': 'Visual Create',\n 'pres.clearGroup': 'Clear current group (back to template tree)',\n 'pres.visual.template': 'Generator template',\n 'pres.visual.relation': 'Enter one relation (f = e or f1 = f2)',\n 'pres.visual.relationPlaceholder': 'e.g. a^3=e or ab=ba',\n 'pres.visual.add': 'Add',\n 'pres.visual.list': 'Added relations',\n 'pres.visual.finish': 'Finish & Create Group → Tree View',\n 'pres.visual.invalid': 'Relation must be f=e or f1=f2 (words of generators, supporting ^n and ⁻¹)',\n 'pres.visual.infinite': 'Current relations give an infinite group',\n 'pres.visual.order': '|G| = {n}',\n 'right.presentation': 'Presentation',\n 'sd.clickCreate': 'Configure φ then click button below',\n 'sd.finish': 'Finish',\n 'sd.phase1': 'Step 1: Start with the Cayley graph of H (skeleton)',\n 'sd.phase2': 'Step 2: Inflate each node into the rewired copy under φ(h)',\n 'sd.phase3': 'Step 3: Connect corresponding nodes across copies with H-arrows',\n 'sd.phase4': 'Step 4: The semidirect product is complete',\n 'sd.autoPlay': 'Auto play',\n 'sd.phaseTitle': 'Semidirect Animation',\n\n /* Homomorphism */\n 'homo.title': 'Homomorphism',\n 'homo.source': 'Domain G',\n 'homo.target': 'Codomain H',\n 'homo.savedList': 'Saved Homomorphisms ({n})',\n 'homo.activate': 'Activate',\n 'homo.autoMap': 'Auto Map',\n 'homo.trivial': 'Trivial Map',\n 'homo.projection': 'Natural Projection',\n 'homo.dpProjection': 'DP Projection ({factor})',\n 'homo.generatorHint': 'Drag elements on canvas to define generator mapping',\n 'homo.fullPreview': 'Full Preview ({m}/{n})',\n 'homo.verify': 'Verify',\n 'homo.clear': 'Clear',\n 'homo.create': 'Create',\n 'homo.openView': 'Open Homomorphism View',\n 'homo.viewSection': 'Homomorphism View',\n 'homo.valid': 'Valid',\n 'homo.invalid': 'Not a Homomorphism',\n 'homo.kernel': 'Kernel Ker',\n 'homo.image': 'Image Im',\n 'homo.injective': 'Injective',\n 'homo.notInjective': 'Not Injective',\n 'homo.surjective': 'Surjective',\n 'homo.notSurjective': 'Not Surjective',\n 'homo.isomorphism': 'Isomorphism',\n 'homo.firstIso': 'First Iso Theorem',\n 'homo.theoremMode': 'Theorem Mode →',\n 'homo.firstIso.needValid': 'Need a valid homomorphism',\n 'homo.firstIso.needValidHint': 'Please verify a homomorphism first',\n 'homo.firstIso.phase0': 'f: G \\\\to H',\n 'homo.firstIso.phase1': 'K = \\\\ker f \\\\subsetneq G',\n 'homo.firstIso.phase2': '\\\\pi: G \\\\to G/K',\n 'homo.firstIso.phase3': 'G/K \\\\cong \\\\operatorname{Im} f',\n 'homo.firstIso.phase0Desc': 'The homomorphism f maps G to H preserving the operation',\n 'homo.firstIso.phase1Desc': 'The kernel K consists of elements mapping to the identity, and K is a normal subgroup',\n 'homo.firstIso.phase2Desc': 'The natural projection π collapses G onto the quotient G/K, cosets colored by fiber',\n 'homo.firstIso.phase3Desc': 'First Isomorphism Theorem: G/K ≅ Im f, induced by f',\n 'homo.selectSourceFirst': 'Select source group first',\n 'homo.interactiveHint': 'Drag elements to map them',\n 'homo.created': 'Homomorphism created: {source} → {target}',\n 'homo.verified': 'Homomorphism verified: {source} → {target}',\n 'homo.saved': 'Homomorphism saved',\n 'homo.trivialApplied': 'Trivial mapping applied',\n 'homo.projectionApplied': 'Natural projection applied',\n 'homo.projectionFailed': 'Projection failed: no normal subgroup',\n 'homo.inclusionApplied': 'Inclusion mapping applied',\n 'homo.inclusionFailed': 'Inclusion mapping failed',\n 'homo.dpProjectionApplied': 'DP projection applied ({factor})',\n 'homo.dpProjectionFailed': 'DP projection failed',\n\n /* Quotient */\n 'quotient.title': 'Quotient Groups',\n 'quotient.boundHint': 'Select a normal subgroup to build G/N',\n 'quotient.create': 'Create Quotient',\n 'quotient.load': 'Load',\n 'quotient.noQuotient': 'No quotient groups',\n\n /* Automorphism */\n 'automorphism.title': 'Automorphism Group',\n 'automorphism.boundHint': 'Compute the automorphism group Aut(G)',\n 'automorphism.compute': 'Compute Aut(G)',\n 'automorphism.load': 'Load',\n 'automorphism.noAutomorphism': 'No automorphism groups',\n\n /* Group Action */\n 'action.title': 'Group Action',\n 'action.kind.conjugation': 'Conjugation Action',\n 'action.kind.custom': 'Custom Action',\n 'action.kind.sylow': 'Sylow {p}-subgroup conjugation action',\n 'action.kind.regular': 'Left translation (regular representation)',\n 'action.kind.coset': 'Coset action',\n 'action.create.conjugation': 'Conjugation',\n 'action.create.custom': 'Custom',\n 'action.create.regular': 'Left translation (Cayley)',\n 'action.create.coset': 'Coset action',\n 'action.create.sylow': 'Sylow p-action',\n 'action.setSize': 'Set size |X|',\n 'action.startEdit': 'Start Editing',\n 'action.editHint': 'Click an element to pick the start; the arrow follows the cursor; click a target element to deploy (auto-binds the selected generator); click the start element itself for a fixed point (self-loop); click a deployed arrow to delete it; click empty space to cancel',\n 'action.genSelectHint': 'Drag a generator onto a dashed arrow, or select one then click the arrow to bind',\n 'action.dropHint': 'Release to bind',\n 'action.cycleCandidates': 'Cycle candidates:',\n 'action.cycleUnit': 'cycle',\n 'action.editingSource': 'Choose destination of {x}',\n 'action.finish': 'Finish & Verify',\n 'action.clear': 'Clear',\n 'action.exit': 'Exit editing',\n 'action.valid': 'Homomorphism holds — action is valid',\n 'action.invalid': 'Not a homomorphism — action is invalid',\n 'action.draftRestored': 'Restored your last saved custom action draft',\n 'action.saved': 'Custom action saved to the list',\n 'action.activated': 'Action restored',\n 'action.savedList': 'Saved actions',\n 'action.activate': 'Activate',\n 'action.created': '{kind} created',\n 'action.violation': 'Φ({g}·{a}) ≠ Φ({g})∘Φ({a}) at {x}',\n 'action.orbitCount': 'Orbits: {n}',\n 'action.fixedPoints': 'Fixed points: {n}',\n 'action.sumCheck': 'Σ|Orb| = |X|: {sum} = {n}',\n 'action.ost': '|Orb(x)|·|Stab(x)| = {orbit}·{stab} = {product} = |G|',\n 'action.stabilizer': 'Stab({x})',\n 'action.orbitStab': '|Orb({x})| = {orbit}, |Stab({x})| = {stab}',\n 'action.noAction': 'Create a group action from the left panel',\n 'action.error.range': 'Arrow {from}→{to} is out of range',\n 'action.error.unbound': 'There are unbound arrows',\n 'action.error.duplicate-source': 'Generator {gen} defines source {from} twice',\n 'action.error.conflict-target': 'Target {to} of {gen} is pointed to by multiple sources',\n 'action.error.missing-target': 'Target {to} needs a destination: {gen} has no image defined for it',\n 'action.error.homomorphism': 'Not a homomorphism: Φ({g}·{gen}) ≠ Φ({g})∘Φ({gen}) at {x}; fix the arrows',\n 'action.error.unknown-generator': 'Unknown generator: {gen}',\n 'action.viewBlurb': 'Each circle is an orbit (a conjugacy class for conjugation); arcs are generator actions, colored by generator',\n 'action.showing': 'Showing element ',\n 'action.conjSuffix': \"'s conjugation action: x ↦ g·x·g⁻¹'\",\n 'action.arrowSuffix': \"'s full action arrows'\",\n 'action.orbitGroup': 'Orbit · {size} elements',\n 'action.viewTitle.conjugation': 'Conjugation action: G acts on itself, g·x = g·x·g⁻¹ (orbits = conjugacy classes)',\n 'action.viewTitle.custom': 'Custom action: G acts on the set X',\n 'action.viewTitle.sylow': 'Sylow {p}-subgroups: G acts on Syl_p(G) by conjugation (orbit = all Sylow p-subgroups, |Syl_p(G)| = n_p)',\n 'action.viewTitle.regular': 'Left translation (regular representation): G acts on itself by g·x = g·x; single orbit, free action ⇒ Cayley theorem: G ≅ subgroup of Sym(G)',\n 'action.viewTitle.coset': 'Coset action: G acts on left cosets G/H by g·(xH) = (gx)H; transitive, Stab(xH) = xHx⁻¹ (conjugate of H)',\n 'action.coset.selectSubgroup': 'Select subgroup H (for coset action)…',\n 'action.coset.noSubgroups': 'Group too large (>60), subgroups not enumerated',\n 'action.math.regular': 'Regular representation: G ≅ Sym(G) embedding',\n 'action.math.regularNote': 'Stab(x) = {e} (free)',\n 'action.math.cosetStab': 'Stab(xH) = xHx⁻¹',\n 'action.math.cosetStabNote': '≅ H',\n 'action.math.cosetTransitive': 'Transitive (single orbit)',\n 'action.math.fixedCenter': 'Fixed points = center Z(G)',\n 'action.math.burnside': 'Burnside: |X/G| = (1/|G|)·Σ|Fix(g)|',\n 'action.edgeBlurb': 'Arcs = generator actions: x → g·x, colors match the legend',\n 'action.hoverElEdges': 'Gold arcs = all actions of {el}: x → g·x for every x',\n 'action.hoverGenEdges': 'Highlighted arcs = action of generator {gen}',\n 'action.selHint': 'Selected x: orbit & stabilizer details in the right panel',\n 'action.stabilizerFor': 'Stabilizer G_x of element {el}',\n 'action.closeStab': 'Close',\n 'right.actionInfo': 'Group Action Info',\n\n /* Sylow View */\n 'sylowView.selectP': 'Prime p',\n 'sylowView.pElements': 'p-elements',\n 'sylowView.pSubgroups': 'p-subgroups',\n 'sylowView.sylowSubgroups': 'Sylow p-subgroups',\n 'sylowView.otherPSubgroups': 'Other p-subgroups',\n 'sylowView.none': 'No p-subgroups (p ∤ |G|)',\n 'sylowView.legendSelected': 'selected subgroup elements',\n 'sylowView.legendP': 'p-elements (order a power of p)',\n 'sylowView.legendOther': 'other elements',\n 'sylowView.legendEdges': 'edges = generator action (color-coded)',\n 'sylowView.edgeAction': 'Edge action',\n 'sylowView.edgeActionDefault': 'group generators',\n 'sylowView.edgeHint': 'Click a subgroup to switch edges to its generators',\n 'sylowView.twoSelectHint': 'Ctrl/⌘ or ⊕ click a second subgroup → conjugation (Sylow II)', 'sylowView.addSecond': '⊕ add as second subgroup (multi-select)',\n 'sylowView.conjLabel': 'Conjugation',\n 'sylowView.noConjugator': 'no conjugating element',\n 'sylowView.legendP2': 'P (top)',\n 'sylowView.legendQ2': 'Q (bottom)',\n 'sylowView.legendI2': 'P∩Q (middle)',\n 'sylowView.legendConj': 'arrows = conjugation x ↦ gxg⁻¹',\n 'sylowView.collapseList': 'Collapse subgroup list',\n 'sylowView.expandList': 'Expand subgroup list',\n\n /* Theme Toggle */\n 'theme.dark': 'Dark Mode',\n 'theme.light': 'Light Mode',\n 'theme.switchToLight': 'Switch to Light Mode',\n 'theme.switchToDark': 'Switch to Dark Mode',\n}\n\nexport const translations: Record<Lang, TranslationMap> = { zh, en }\n\nexport function getDefaultLang(): Lang {\n if (typeof window === 'undefined') return 'zh'\n const stored = localStorage.getItem('groupviz-lang')\n if (stored === 'en' || stored === 'zh') return stored\n const nav = navigator.language || ''\n if (nav.startsWith('zh')) return 'zh'\n return 'zh'\n}\n","import { createContext, useState, useCallback, type ReactNode } from 'react'\nimport { translations, getDefaultLang, type Lang } from './translations'\n\nexport interface I18nContextValue {\n lang: Lang\n setLang: (lang: Lang) => void\n t: (key: string, params?: Record<string, string | number>) => string\n}\n\n/**\n * 缺省 `t`(无 `<I18nProvider>` 包裹时)——**查真实词典**,而不是回落成 key。\n *\n * 旧实现是 `t: (key) => key`,于是外部嵌入漏包 Provider 时整屏文案都变成\n * `canvas.cosetStripNoCosets` 这样的 key(反馈里的高频踩坑点)。现在缺省就按\n * 「中文优先、英文兜底」渲染,漏包 Provider 只是拿不到 `setLang` 的切换能力。\n */\nfunction defaultTranslate(key: string, params?: Record<string, string | number>): string {\n let text = translations['zh'][key] ?? translations['en'][key] ?? key\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n text = text.replace(new RegExp(`\\\\{${k}\\\\}`, 'g'), String(v))\n }\n }\n return text\n}\n\n// eslint-disable-next-line react-refresh/only-export-components\nexport const I18nContext = createContext<I18nContextValue>({\n lang: 'zh',\n setLang: () => { },\n t: defaultTranslate,\n})\n\nexport interface I18nProviderProps {\n children: ReactNode\n /** 初始语言;缺省按 `getDefaultLang()`(读 localStorage / 浏览器语言) */\n lang?: Lang\n /** 是否把语言选择写入 `localStorage('groupviz-lang')`;缺省 `true`。\n * 嵌入宿主不希望与主应用抢同一 key 时可传 `false`。 */\n persist?: boolean\n}\n\nexport function I18nProvider({ children, lang: langProp, persist = true }: I18nProviderProps) {\n const [lang, setLangState] = useState<Lang>(() => langProp ?? getDefaultLang())\n\n const setLang = useCallback((newLang: Lang) => {\n setLangState(newLang)\n if (persist) localStorage.setItem('groupviz-lang', newLang)\n }, [persist])\n\n const t = useCallback((key: string, params?: Record<string, string | number>) => {\n const dict = translations[lang]\n let text = dict[key]\n if (text === undefined) {\n text = translations['en'][key]\n }\n if (text === undefined) {\n console.warn(`Missing translation key: \"${key}\" for lang \"${lang}\"`)\n return key\n }\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n text = text.replace(new RegExp(`\\\\{${k}\\\\}`, 'g'), String(v))\n }\n }\n return text\n }, [lang])\n\n return (\n <I18nContext.Provider value={{ lang, setLang, t }}>\n {children}\n </I18nContext.Provider>\n )\n}\n","import { useContext } from 'react'\nimport { I18nContext } from './I18nContext'\n\nexport function useTranslation() {\n return useContext(I18nContext)\n}\n","import { useId, useMemo } from 'react'\nimport { SceneThemeRoot, type SceneTheme } from './SceneThemeRoot'\nimport { useTranslation } from '../../i18n/useTranslation'\nimport { cosetStripLayout, cayleyCircleLayout } from '../../core/algebra/forceLayout'\nimport { computeCayleyActionEdges } from '../../core/algebra/cayleyEdges'\nimport { findMinimalGenerators } from '../../core/algebra/sylow'\nimport { buildCosetViewData } from '../../core/algebra/cosetView'\nimport { resolveElementIdsWarn } from '../../utils/elementRef'\n\n// 「H 不是子群」告警去重(同一群 + 同一集合只提示一次)\nconst _notSubgroupWarned = new Set<string>()\nfunction warnNotSubgroup(group: Group, ids: string[]) {\n const key = `${group.symbol}|${[...ids].sort().join(',')}`\n if (_notSubgroupWarned.has(key)) return\n _notSubgroupWarned.add(key)\n console.warn(\n `[groupviz] CosetStripScene.subgroup: 元素集合 [${key.split('|')[1]}] 在群 ${group.symbol} 中` +\n `不构成子群(不含单位元或乘法不封闭),陪集视图显示空态。`\n )\n}\nimport { renderTex, texify } from '../../utils/texify'\nimport type { CosetStripInfo } from '../../core/algebra/forceLayout'\nimport { COLOR_PALETTE } from '../../core/types'\nimport type { Group, GroupElement } from '../../core/types'\n\n// ─── Coset Strip props-化内核 ──────────────────────────────────────────\n// 受控 ViewWindow (FGVE) 与主画布(经 context 壳)共用。除 group / viewBoxSize 外\n// 全部可选:主画布壳由全局 Provider 组装装饰数据(陪集/子集高亮、选中、变换),\n// 窗口引擎自包含时只传 group + 由 H 派生的陪集数据,其余缺省即安全空值。\n// FGVE 打包期随视图层入包:仅依赖 i18n context(文案 key 由 @groupviz/react 自带\n// I18nProvider/语言包供给),不读 useGroup/useHover/useTheme——context 组装壳\n// 在 CosetStripView.tsx(主应用宿主专用,不入包)。\n\nexport interface CosetStripSceneProps {\n group: Group | null\n selectedElements?: Set<string>\n canvasTransform?: { x: number; y: number; scale: number }\n viewBoxSize: { width: number; height: number }\n /** 元素 → 陪集下标(与 SetView 同约定)。缺省空 Map 显示空态文案 */\n cosetElementMap?: Map<string, number> | null\n /** 每条陪集的条带颜色 */\n cosetColors?: string[]\n /** 被高亮的陪集下标集合(点击选中元素 → 其所在陪集) */\n cosetHighlightSet?: Set<number>\n /** 已保存子集(元素集合 + 颜色),命中元素描边用子集色 */\n subsets?: Array<{ elementIds: string[]; color: string }>\n /** 节点常驻标签;缺省 true(主画布行为);嵌入窗口默认关,读元素靠 hover */\n showLabels?: boolean\n /** H 条带上方的 H-Cayley 小圈;缺省 true(主画布行为),嵌入窗口默认关省空间 */\n showSubgroupCayley?: boolean\n /** 点击节点:缺省无操作(主画布壳接全局选中,窗口引擎自己维护会话态) */\n onSelect?: (elId: string, additive: boolean) => void\n /** 悬停节点:主画布走全局 Hover,窗口经 anchor 就地气泡 */\n onHover?: (el: GroupElement | null, anchor?: { x: number; y: number } | null) => void\n noGroupText?: string\n /** 有群但无陪集数据时的文案(缺省 i18n canvas.cosetStripNoCosets,主应用语境);\n * 窗口引擎可传自定义提示(如本地枚举上限) */\n noCosetsText?: string\n /** **便捷入口**:给定子群 H(元素引用数组,`id` 或 `label` 皆可),内部经\n * `@groupviz/core` 的 `buildCosetViewData` 自动派生 `cosetElementMap` /\n * `cosetColors` / `cosetHighlightSet`。与显式传三件套二选一——显式传入者优先。 */\n subgroup?: string[] | null\n /** 便捷入口配套:左 / 右陪集族;缺省 `'left'` */\n cosetType?: 'left' | 'right'\n /** 便捷入口配套:是否高亮全部陪集;缺省 `false`(仅高亮含选中元素的陪集) */\n highlightAllCosets?: boolean\n /** 视图主题作用域(`'dark' | 'light'`)。缺省不注入、跟随外层主题;显式传值时在本子树内\n * 应用 `theme.css` 对应变量块(需宿主已 `import '@groupviz/react/theme.css'`) */\n theme?: SceneTheme\n}\n\nexport function CosetStripScene(props: CosetStripSceneProps) {\n return (\n <SceneThemeRoot theme={props.theme}>\n <CosetStripSceneBody {...props} />\n </SceneThemeRoot>\n )\n}\n\nfunction CosetStripSceneBody({\n group,\n selectedElements,\n canvasTransform,\n viewBoxSize,\n cosetElementMap: cosetElementMapProp,\n cosetColors: cosetColorsProp,\n cosetHighlightSet: cosetHighlightSetProp,\n subsets,\n showLabels = true,\n showSubgroupCayley = true,\n onSelect,\n onHover,\n noGroupText,\n noCosetsText,\n subgroup,\n cosetType = 'left',\n highlightAllCosets = false,\n}: CosetStripSceneProps) {\n const { t } = useTranslation()\n // 多实例(主画布 + 多窗口)并存时避免 marker/filter id 冲突\n const uid = useId()\n const shadowId = `${uid}-cs-node-shadow`\n const arrowId = (i: number) => `${uid}-cs-cayley-arrow-${i}`\n\n // 便捷入口:显式三件套优先;未传时由 H 元素引用经 core.buildCosetViewData 一键派生\n const derived = useMemo(() => {\n if (cosetElementMapProp || !group || !subgroup || subgroup.length === 0) return null\n const ids = resolveElementIdsWarn(group, subgroup, 'CosetStripScene.subgroup')\n if (ids.length === 0) return null\n const data = buildCosetViewData(group, ids, {\n side: cosetType,\n highlightAll: highlightAllCosets,\n selected: selectedElements ?? [],\n })\n if (!data) warnNotSubgroup(group, ids)\n return data\n }, [cosetElementMapProp, group, subgroup, cosetType, highlightAllCosets, selectedElements])\n\n const cosetElementMap = cosetElementMapProp ?? derived?.cosetElementMap\n const cosetColors = cosetColorsProp ?? derived?.cosetColors\n const cosetHighlightSet = cosetHighlightSetProp ?? derived?.cosetHighlightSet\n\n const subsetDetailMap = useMemo(() => {\n const m = new Map<string, { color: string }>()\n ;(subsets ?? []).forEach(s => s.elementIds.forEach(id => { if (!m.has(id)) m.set(id, s) }))\n return m\n }, [subsets])\n\n const subgroupInfo = useMemo(() => {\n if (!group || !cosetElementMap || cosetElementMap.size === 0) return null\n // The subgroup is the coset containing the identity (eH = H); coset index 0\n // may correspond to any coset depending on group element ordering.\n const hCi = cosetElementMap.get(group.identity.id)\n if (hCi === undefined) return null\n let hSize = 0\n for (const ci of cosetElementMap.values()) { if (ci === hCi) hSize++ }\n if (hSize < 2 || hSize > 12) return null\n const r = Math.max(40, Math.min(96, hSize * 16))\n return { hSize, r, topPad: 2 * r + 64 }\n }, [group, cosetElementMap])\n\n const cosetStripData = useMemo(() => {\n if (!group) return null\n if (!cosetElementMap || cosetElementMap.size === 0) return null\n return cosetStripLayout(\n group,\n viewBoxSize.width,\n viewBoxSize.height,\n undefined,\n cosetElementMap,\n new Set(cosetElementMap.values()).size,\n cosetColors,\n subgroupInfo && showSubgroupCayley ? subgroupInfo.topPad : undefined,\n )\n }, [group, viewBoxSize.width, viewBoxSize.height, cosetElementMap, cosetColors, subgroupInfo, showSubgroupCayley])\n\n const subgroupCayley = useMemo(() => {\n if (!group || !cosetElementMap || cosetElementMap.size === 0) return null\n if (!showSubgroupCayley) return null\n // Same coset-of-identity logic as subgroupInfo: the subgroup H is the coset eH.\n const hCi = cosetElementMap.get(group.identity.id)\n if (hCi === undefined) return null\n const hIds: string[] = []\n for (const [id, ci] of cosetElementMap) { if (ci === hCi) hIds.push(id) }\n if (hIds.length < 2 || hIds.length > 12) return null\n const hIdSet = new Set(hIds)\n const hElements = group.elements.filter(el => hIdSet.has(el.id))\n const hGenerators = findMinimalGenerators(hElements, group)\n if (hGenerators.length === 0) return null\n const genIndex = new Map<string, number>()\n const actions = hGenerators.map((g, i) => {\n genIndex.set(g.id, i)\n return { elementId: g.id, enabled: true, color: COLOR_PALETTE[i % COLOR_PALETTE.length] }\n })\n const edges = computeCayleyActionEdges(group, actions, 'right')\n .filter(e => !e.isSelfLoop && hIdSet.has(e.fromId) && hIdSet.has(e.toId))\n return { hIdSet, hElements, hGenerators, genIndex, edges }\n }, [group, cosetElementMap, showSubgroupCayley])\n\n const nodeRadius = useMemo(() => {\n if (!group) return 28\n const maxLen = Math.max(...group.elements.map(el => el.label.length))\n if (maxLen > 15) return 20\n if (maxLen > 8) return 24\n return 28\n }, [group])\n const NO_GROUP = !group\n\n const handleHover = (el: GroupElement | null, anchor?: { x: number; y: number } | null) => {\n if (onHover) onHover(el, anchor)\n }\n\n return (\n <svg viewBox={`0 0 ${viewBoxSize.width} ${viewBoxSize.height}`} className=\"view-svg\" style={{ userSelect: 'none' }}>\n <defs>\n <filter id={shadowId} x=\"-30%\" y=\"-30%\" width=\"160%\" height=\"160%\">\n <feDropShadow dx=\"0\" dy=\"2\" stdDeviation=\"3\" floodColor=\"#000000\" floodOpacity=\"0.25\" />\n </filter>\n {subgroupCayley && subgroupCayley.hGenerators.map((g, i) => (\n <marker key={g.id} id={arrowId(i)} markerWidth={13} markerHeight={13} refX={10} refY={6.5} orient=\"auto\">\n <path d=\"M0,0 L13,6.5 L0,13 Z\" fill={COLOR_PALETTE[i % COLOR_PALETTE.length]} />\n </marker>\n ))}\n </defs>\n\n <g transform={`translate(${canvasTransform?.x ?? 0}, ${canvasTransform?.y ?? 0}) scale(${canvasTransform?.scale ?? 1})`}>\n {cosetStripData && cosetStripData.strips.length > 0 && cosetStripData.strips.map((strip: CosetStripInfo, si: number) => (\n <g key={`coset-bg-${si}`} data-coset-strip={si}>\n <rect\n x={strip.x}\n y={strip.y}\n width={strip.w}\n height={strip.h}\n rx={8}\n fill={strip.color + (strip.isSubgroup ? '18' : '10')}\n stroke={strip.color + (strip.isSubgroup ? '55' : '28')}\n strokeWidth={strip.isSubgroup ? 2 : 1}\n strokeDasharray={strip.isSubgroup ? undefined : '4 6'}\n />\n <text\n x={strip.x + strip.w / 2}\n y={strip.y - 10}\n textAnchor=\"middle\"\n fill={strip.color}\n fontSize={13}\n fontWeight={strip.isSubgroup ? 700 : 400}\n opacity={0.85}\n style={{ fontFamily: 'KaTeX_Main, monospace', fontStyle: 'italic' }}\n >{strip.label}</text>\n </g>\n ))}\n\n {subgroupCayley && cosetStripData && cosetStripData.strips[0] && subgroupInfo && group && (() => {\n const strip = cosetStripData.strips[0]\n const cx = strip.x + strip.w / 2\n const cy = strip.y - subgroupInfo.r - 24\n const hGroup = { ...group, order: subgroupInfo.hSize, elements: subgroupCayley.hElements }\n const positions = cayleyCircleLayout(hGroup, cx, cy, subgroupInfo.r)\n const maxLabelLen = Math.max(...subgroupCayley.hElements.map(el => {\n const l = el.label\n if (l.startsWith('\\\\begin{smallmatrix}')) return 4\n return l.length\n }))\n const labelFs = maxLabelLen <= 4 ? 15 : maxLabelLen <= 6 ? 13 : maxLabelLen <= 8 ? 11 : 9.5\n const hNodeR = Math.max(12, Math.min((maxLabelLen * labelFs * 0.62 + 10) / 2, subgroupInfo.r * 0.35))\n return (\n <g key=\"subgroup-cayley\">\n <text\n x={cx}\n y={cy - subgroupInfo.r - 12}\n textAnchor=\"middle\"\n fill=\"var(--text-muted)\"\n fontSize={13}\n fontFamily=\"KaTeX_Main, monospace\"\n >{t('canvas.cosetStripCayley')}</text>\n {subgroupCayley.edges.map(edge => {\n const fp = positions.get(edge.fromId)\n const tp = positions.get(edge.toId)\n if (!fp || !tp) return null\n const gi = subgroupCayley.genIndex.get(edge.actionElementId) ?? 0\n return (\n <line\n key={`${edge.fromId}-${edge.toId}-${edge.actionElementId}`}\n x1={fp.x}\n y1={fp.y}\n x2={tp.x}\n y2={tp.y}\n stroke={edge.color}\n strokeWidth={2.2}\n opacity={0.9}\n markerEnd={edge.isBidirectional ? undefined : `url(#${arrowId(gi)})`}\n />\n )\n })}\n {subgroupCayley.hElements.map(el => {\n const p = positions.get(el.id)\n if (!p) return null\n return (\n <g key={`h-cayley-${el.id}`} transform={`translate(${p.x}, ${p.y})`}>\n <circle\n r={hNodeR}\n fill=\"var(--node-fill)\"\n stroke={el.id === group.identity.id ? '#ffd93d' : 'var(--node-stroke)'}\n strokeWidth={1.8}\n />\n <foreignObject\n x={-hNodeR}\n y={-hNodeR}\n width={hNodeR * 2}\n height={hNodeR * 2}\n style={{ pointerEvents: 'none', userSelect: 'none' }}\n >\n <div\n style={{\n display: 'flex', alignItems: 'center', justifyContent: 'center',\n width: '100%', height: '100%', color: 'var(--node-text)', fontSize: `${labelFs}px`\n }}\n dangerouslySetInnerHTML={{ __html: renderTex(texify(el.label)) }}\n />\n </foreignObject>\n </g>\n )\n })}\n </g>\n )\n })()}\n\n {cosetStripData && cosetStripData.strips.length > 0 && group && (\n (() => {\n const shSize = cosetStripData.strips[0]?.elementIds.length || 0\n const n = group.order\n const index = cosetStripData.strips.length\n return (\n <text\n x={viewBoxSize.width / 2}\n y={viewBoxSize.height - 14}\n textAnchor=\"middle\"\n fill=\"#999\"\n fontSize={12}\n opacity={0.7}\n style={{ fontFamily: 'KaTeX_Main, monospace' }}\n >{`|G|=${n} = ${shSize}\\u00b7${index} |H|\\u00b7[G:H]`}</text>\n )\n })()\n )}\n\n {cosetStripData && group && group.elements.map((el) => {\n const pos = cosetStripData.positions.get(el.id)\n if (!pos) return null\n const isSelected = selectedElements?.has(el.id) ?? false\n const parentSubset = subsetDetailMap.get(el.id)\n const cosetIdx = cosetElementMap?.get(el.id)\n const isInHighlightedCoset = cosetIdx !== undefined && (cosetHighlightSet?.has(cosetIdx) ?? false)\n\n let fillColor = 'var(--node-fill)'\n let strokeColor = 'var(--node-stroke)'\n let strokeWidth = 2.5\n\n if (isSelected) {\n fillColor = 'var(--node-fill-selected)'\n strokeColor = '#ffd93d'\n strokeWidth = 3\n } else if (isInHighlightedCoset && cosetIdx !== undefined && cosetColors) {\n fillColor = cosetColors[cosetIdx] + '33'\n strokeColor = cosetColors[cosetIdx]\n strokeWidth = 3\n } else if (parentSubset) {\n fillColor = parentSubset.color + '33'\n strokeColor = parentSubset.color\n strokeWidth = 2.5\n }\n\n return (\n <g\n key={el.id}\n data-coset-node={el.id}\n transform={`translate(${pos.x}, ${pos.y})`}\n onClick={(e) => {\n e.stopPropagation()\n if (onSelect) onSelect(el.id, e.ctrlKey || e.metaKey)\n }}\n onMouseEnter={() => {\n // anchor 用世界→视口换算(与 CycleView 同约定):窗口 hover 气泡据此定位\n const s = canvasTransform?.scale ?? 1\n handleHover(el, {\n x: pos.x * s + (canvasTransform?.x ?? 0),\n y: pos.y * s + (canvasTransform?.y ?? 0),\n })\n }}\n onMouseLeave={() => handleHover(null)}\n style={{ cursor: 'pointer' }}\n >\n <circle\n r={nodeRadius}\n fill={fillColor}\n stroke={strokeColor}\n strokeWidth={strokeWidth}\n filter=\"url(#${shadowId})\"\n />\n {parentSubset && (\n <circle\n r={nodeRadius}\n fill={`${parentSubset.color}22`}\n stroke=\"none\"\n />\n )}\n {isInHighlightedCoset && cosetIdx !== undefined && cosetColors && (\n <circle\n r={nodeRadius}\n fill={`${cosetColors[cosetIdx]}22`}\n stroke=\"none\"\n />\n )}\n {showLabels && (\n <foreignObject\n x={-nodeRadius}\n y={-16}\n width={nodeRadius * 2}\n height={32}\n style={{ pointerEvents: 'none', userSelect: 'none' }}\n >\n <div\n style={{\n display: 'flex', alignItems: 'center', justifyContent: 'center',\n width: '100%', height: '100%', color: 'var(--node-text)',\n fontSize: el.label.length <= 4 ? '15px' : el.label.length <= 6 ? '13px' : '10px'\n }}\n dangerouslySetInnerHTML={{\n __html: renderTex(texify(el.label))\n }}\n />\n </foreignObject>\n )}\n </g>\n )\n })}\n\n {NO_GROUP && (\n <text x={viewBoxSize.width / 2} y={viewBoxSize.height / 2} textAnchor=\"middle\" fill=\"var(--text-muted)\" fontSize=\"18\">\n {noGroupText ?? t('canvas.cosetStripNoSubgroup')}\n </text>\n )}\n\n {group && (!cosetStripData || cosetStripData.strips.length === 0) && (\n <text x={viewBoxSize.width / 2} y={viewBoxSize.height / 2} textAnchor=\"middle\" fill=\"var(--text-muted)\" fontSize=\"18\">\n {noCosetsText ?? t('canvas.cosetStripNoCosets')}\n </text>\n )}\n </g>\n </svg>\n )\n}\n","/**\n * 通用 Blob 下载触发 —— 与导出链(gifenc/渲染收集)解耦的纯 DOM 工具。\n *\n * 独立成模块的动机(FGVE 阶段 3 入包):TableView 等纯内核 Scene 需要\n * \"导出当前 SVG\" 能力,但 utils/export.ts 整模块顶层依赖 gifenc(GIF 编码,\n * 无 sideEffects 声明时会被打包器保守内嵌)。把 triggerDownload 抽到零依赖\n * 模块后,react 包的程序图不再触及 export.ts,gifenc 不会进入包产物。\n */\nexport function triggerDownload(blob: Blob, filename: string) {\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = filename\n document.body.appendChild(a)\n a.click()\n document.body.removeChild(a)\n setTimeout(() => URL.revokeObjectURL(url), 1000)\n}\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type PointerEvent as RPointerEvent,\n} from 'react'\nimport { useTranslation } from '../../i18n/useTranslation'\nimport { SceneThemeRoot, type SceneTheme } from './SceneThemeRoot'\nimport { isTooLarge } from '../../core/viewBox'\nimport { findAllSubgroups } from '../../core/algebra/subgroups'\nimport { triggerDownload } from '../../utils/download'\nimport type { CanvasTransform, Group, GroupElement, Subset } from '../../core/types'\nimport type { CosetInfo } from '../../core/algebra/subgroups'\nimport type { TableStrategy } from '../../core/types/viewConfig'\n\nconst elementColors = [\n '#ff6b6b', '#4ecdc4', '#ffd93d', '#6bcb77', '#9b59b6',\n '#3498db', '#e67e22', '#1abc9c', '#e74c3c', '#2ecc71',\n '#f39c12', '#8e44ad', '#3071a9', '#d35400', '#c0392b'\n]\n\n// 完整表格(网格 + 行表头 + 列表头 + 页脚)的 viewBox 内容尺寸余量\nexport const TABLE_PAD_W = 44 // 行表头 ~38px + 右侧小余量\nexport const TABLE_PAD_H = 74 // 列表头 ~16px + 页脚 ~50px + 余量\n\n// 热力图大群聚合:超过该阶数的热力图 full 策略降采样为众数色块缩略图,\n// 既用颜色密度呈现乘法表宏观结构,又将渲染成本恒定在 HEATMAP_AGG_RES² 量级。\nconst HEATMAP_AGG_THRESHOLD = 60\nconst HEATMAP_AGG_RES = 80\n\nexport interface TableViewProps {\n group: Group | null\n selectedElements: Set<string>\n canvasTransform: CanvasTransform\n viewBoxSize: { width: number; height: number }\n /** 子集(含子群标记),用于子群/非子群着色;缺省空 */\n subsets?: Subset[]\n cosetElementMap?: Map<string, number>\n cosetColors?: string[]\n cosetData?: CosetInfo | null\n cosetType?: 'left' | 'right'\n showAllCosets?: boolean\n /** 大群告警已解除(对应主画布 forceShowLargeGroupViews.has('table'));缺省 false */\n forceShowLargeGroup?: boolean\n /** 解除大群告警回调;缺省使用本地状态 */\n onForceShowLargeGroup?: (allow: boolean) => void\n /** 大群(>16 阶)展示策略;缺省 'subgroup' */\n strategy?: TableStrategy\n /** 单元格尺寸;缺省 50 */\n cellSize?: number\n /** 热力图模式:只显示颜色,不显示元素和行/列表头;缺省 false */\n showHeatmap?: boolean\n /** 策略被内部 UI 切换时回传(供外部 viewParams 同步) */\n onStrategyChange?: (s: TableStrategy) => void\n /** 实际渲染的表格内容尺寸回传(行数×cellSize + 表头/页脚),用于 ViewWindow 设定最小窗口尺寸;\n * 大群告警/全屏占位时回传 null(无表格可显示) */\n onLayoutSize?: (size: { width: number; height: number } | null) => void\n onSelect?: (elId: string, additive: boolean) => void\n onHover?: (el: GroupElement | null) => void\n noGroupText?: string\n /** 文字乘法表「过大」阈值覆盖(群阶 > 该值时先出告警占位);缺省 100(core.sizeLimitFor('table')) */\n maxTableOrder?: number\n /** 热力图「过大」阈值覆盖;缺省 240(core.sizeLimitFor('heatmap'),聚合缩略图可承载更大群) */\n maxHeatmapOrder?: number\n /** 视图主题作用域(`'dark' | 'light'`)。缺省不注入、跟随外层主题;显式传值时在本子树内\n * 应用 `theme.css` 对应变量块(需宿主已 `import '@groupviz/react/theme.css'`) */\n theme?: SceneTheme\n}\n\nexport function TableView(props: TableViewProps) {\n return (\n <SceneThemeRoot theme={props.theme}>\n <TableViewBody {...props} />\n </SceneThemeRoot>\n )\n}\n\ninterface SubgroupPick {\n indices: number[]\n label: string\n order: number\n}\n\nconst EMPTY_IDX_MAP = new Map<string, number>()\nconst EMPTY_SUBSETS: Subset[] = []\n\nfunction pickRandomSample(group: Group, idToIdx: Map<string, number>): number[] {\n const n = group.order\n const set = new Set<number>([idToIdx.get(group.identity.id) ?? 0])\n const target = Math.max(set.size, Math.min(n, 6 + Math.floor(Math.random() * 7)))\n const pool: number[] = []\n for (let i = 0; i < n; i++) {\n if (!set.has(i)) pool.push(i)\n }\n while (set.size < target && pool.length > 0) {\n const r = Math.floor(Math.random() * pool.length)\n set.add(pool[r])\n pool.splice(r, 1)\n }\n return [...set].sort((a, b) => a - b)\n}\n\nfunction pickSubgroup(group: Group, idToIdx: Map<string, number>, subsets: Subset[]): SubgroupPick | null {\n const byKey = new Map<string, SubgroupPick>()\n const add = (indices: number[], label: string) => {\n const key = [...indices].sort((a, b) => a - b).join(',')\n if (!byKey.has(key)) {\n byKey.set(key, { indices: [...indices], label, order: indices.length })\n }\n }\n\n for (const s of subsets) {\n if (!s.isSubgroup || s.elementIds.length < 2 || s.elementIds.length > 16) continue\n const idxs: number[] = []\n let ok = true\n for (const elId of s.elementIds) {\n const idx = idToIdx.get(elId)\n if (idx === undefined) {\n ok = false\n break\n }\n idxs.push(idx)\n }\n if (ok) add(idxs, s.label)\n }\n\n const { elements, identity, multiply } = group\n for (const el of elements) {\n if (el.id === identity.id) continue\n let g = el\n let order = 1\n while (order < 17 && g.id !== identity.id) {\n g = multiply(g, el)\n order++\n }\n if (g.id === identity.id && order >= 2 && order <= 16) {\n const idxs: number[] = []\n g = el\n for (let k = 0; k < order; k++) {\n const idx = idToIdx.get(g.id)\n if (idx !== undefined) idxs.push(idx)\n g = multiply(g, el)\n }\n add(idxs, `⟨${el.label}⟩`)\n }\n }\n\n if (group.order <= 60) {\n for (const sg of findAllSubgroups(group)) {\n if (sg.order < 2 || sg.order > 16) continue\n const idxs: number[] = []\n let ok = true\n for (const el of sg.elements) {\n const idx = idToIdx.get(el.id)\n if (idx === undefined) {\n ok = false\n break\n }\n idxs.push(idx)\n }\n if (!ok) continue\n const genLabels = sg.generators.map(gr => gr.label).join(', ')\n add(idxs, sg.order === 1 ? '{e}' : `⟨${genLabels}⟩`)\n }\n }\n\n const cands = [...byKey.values()]\n const preferred = cands.filter(c => c.order >= 6 && c.order <= 12)\n const pool = preferred.length > 0 ? preferred : cands\n if (pool.length === 0) return null\n return pool[Math.floor(Math.random() * pool.length)]\n}\n\nfunction TableViewBody({\n group,\n selectedElements,\n viewBoxSize,\n canvasTransform,\n subsets: subsetsProp,\n cosetElementMap,\n cosetColors,\n cosetData: cosetDataProp,\n cosetType: cosetTypeProp,\n showAllCosets: showAllCosetsProp,\n forceShowLargeGroup,\n onForceShowLargeGroup,\n strategy: strategyProp,\n cellSize: cellSizeProp,\n showHeatmap = false,\n onStrategyChange,\n onLayoutSize,\n onSelect,\n onHover,\n noGroupText,\n maxTableOrder,\n maxHeatmapOrder,\n}: TableViewProps) {\n const { t } = useTranslation()\n const subsets = subsetsProp ?? EMPTY_SUBSETS\n const cem = cosetElementMap ?? EMPTY_IDX_MAP\n const cosetData = cosetDataProp ?? null\n const cosetType = cosetTypeProp ?? 'left'\n const showAllCosets = showAllCosetsProp ?? false\n\n const isLargeTable = group ? group.order > 16 : false\n\n const [strategy, setStrategy] = useState<TableStrategy>(() => strategyProp ?? 'subgroup')\n const [reroll, setReroll] = useState(0)\n const [confirmOpen, setConfirmOpen] = useState(false)\n const [fullscreenOpen, setFullscreenOpen] = useState(false)\n const [fsScale, setFsScale] = useState(1)\n const [fsDragging, setFsDragging] = useState(false)\n const [fsScroll, setFsScroll] = useState({ l: 0, t: 0 })\n const [fsViewport, setFsViewport] = useState({ w: 0, h: 0 })\n const fsBodyRef = useRef<HTMLDivElement>(null)\n const fsScrollRaf = useRef(0)\n const fsSvgRef = useRef<SVGSVGElement>(null)\n const fsDragRef = useRef<{ x: number; y: number; sl: number; st: number } | null>(null)\n\n // 大群告警:外部受控(主画布)优先,否则本地状态兜底(ViewWindow)\n const [localForceShow, setLocalForceShow] = useState(false)\n const forceShow = forceShowLargeGroup ?? localForceShow\n const requestForceShow = useCallback(() => {\n if (onForceShowLargeGroup) onForceShowLargeGroup(true)\n else setLocalForceShow(true)\n }, [onForceShowLargeGroup])\n\n // 外部 strategy 受控同步:渲染期比对 props 变化(参数面板驱动),避免 effect 内 setState\n const [prevStrategyProp, setPrevStrategyProp] = useState<TableStrategy | undefined>(strategyProp)\n if (strategyProp !== prevStrategyProp) {\n setPrevStrategyProp(strategyProp)\n if (strategyProp !== undefined) setStrategy(strategyProp)\n }\n\n const applyStrategy = useCallback((s: TableStrategy) => {\n setStrategy(s)\n onStrategyChange?.(s)\n }, [onStrategyChange])\n\n const idToIdx = useMemo(() => {\n if (!group) return new Map<string, number>()\n const m = new Map<string, number>()\n group.elements.forEach((el, i) => m.set(el.id, i))\n return m\n }, [group])\n\n const labelToIdx = useMemo(() => {\n if (!group) return new Map<string, number>()\n const m = new Map<string, number>()\n group.elements.forEach((el, i) => m.set(el.label, i))\n return m\n }, [group])\n\n const table = useMemo(() => {\n if (!group) return null\n const { elements, multiply } = group\n const n = elements.length\n const tableData: { label: string; id: string }[][] = []\n for (let i = 0; i < n; i++) {\n const row: { label: string; id: string }[] = []\n for (let j = 0; j < n; j++) {\n const result = multiply(elements[j], elements[i])\n row.push({ label: result.label, id: result.id })\n }\n tableData.push(row)\n }\n return tableData\n }, [group])\n\n const getElementColor = (label: string): string => {\n const idx = labelToIdx.get(label)\n if (idx === undefined) return '#ccc'\n return elementColors[idx % elementColors.length]\n }\n\n const selectedIndices = useMemo(() => {\n const set = new Set<number>()\n selectedElements.forEach(id => {\n const idx = idToIdx.get(id)\n if (idx !== undefined) set.add(idx)\n })\n return set\n }, [selectedElements, idToIdx])\n\n const subgroupIndexSets = useMemo(() => {\n if (!group) return [] as { color: string; indices: Set<number> }[]\n return subsets\n .filter(s => s.isSubgroup)\n .map(s => {\n const indices = new Set<number>()\n s.elementIds.forEach(elId => {\n const idx = idToIdx.get(elId)\n if (idx !== undefined) indices.add(idx)\n })\n return { color: s.color, indices }\n })\n }, [subsets, idToIdx, group])\n\n const nonSubgroupSubsetIndices = useMemo(() => {\n const set = new Set<number>()\n for (const subset of subsets) {\n if (subset.isSubgroup) continue\n for (const elId of subset.elementIds) {\n const idx = idToIdx.get(elId)\n if (idx !== undefined) set.add(idx)\n }\n }\n return set\n }, [subsets, idToIdx])\n\n const subsetElemMap = useMemo(() => {\n const map = new Map<number, { color: string; isSubgroup: boolean }>()\n for (const subset of subsets) {\n for (const elId of subset.elementIds) {\n const idx = idToIdx.get(elId)\n if (idx !== undefined) {\n if (!map.has(idx)) {\n map.set(idx, { color: subset.color, isSubgroup: subset.isSubgroup })\n }\n }\n }\n }\n return map\n }, [subsets, idToIdx])\n\n const subgroupCellColors = useMemo(() => {\n if (!group) return new Map<string, string>()\n const map = new Map<string, string>()\n for (const sg of subgroupIndexSets) {\n for (const ri of sg.indices) {\n for (const ci of sg.indices) {\n map.set(`${ri},${ci}`, sg.color)\n }\n }\n }\n return map\n }, [subgroupIndexSets, group])\n\n const cosetSubgroupIndices = useMemo(() => {\n const set = new Set<number>()\n if (!group || !cosetData) return set\n for (const el of cosetData.subgroup.elements) {\n const idx = idToIdx.get(el.id)\n if (idx !== undefined) set.add(idx)\n }\n return set\n }, [group, cosetData, idToIdx])\n\n const cosetActiveRowIds = useMemo(() => {\n if (!group || !cosetData) return new Set<string>()\n if (showAllCosets) {\n const reps = new Set<string>()\n const cosets = cosetType === 'left' ? cosetData.leftCosets : cosetData.rightCosets\n for (const coset of cosets) {\n if (coset.length > 0) reps.add(coset[0].id)\n }\n return reps\n }\n return new Set(selectedElements)\n }, [group, cosetData, showAllCosets, cosetType, selectedElements])\n\n const cosetActiveColIds = useMemo(() => {\n if (!group || !cosetData) return new Set<string>()\n if (showAllCosets) {\n const reps = new Set<string>()\n const cosets = cosetType === 'right' ? cosetData.rightCosets : cosetData.leftCosets\n for (const coset of cosets) {\n if (coset.length > 0) reps.add(coset[0].id)\n }\n return reps\n }\n return new Set(selectedElements)\n }, [group, cosetData, showAllCosets, cosetType, selectedElements])\n\n const elementsInAnySubgroup = useMemo(() => {\n const set = new Set<number>()\n for (const sg of subgroupIndexSets) {\n for (const i of sg.indices) set.add(i)\n }\n return set\n }, [subgroupIndexSets])\n\n const subgroupInfo = useMemo(() => {\n if (!group || !isLargeTable || strategy !== 'subgroup') return null\n return pickSubgroup(group, idToIdx, subsets)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [group, isLargeTable, strategy, subsets, idToIdx, reroll])\n\n const randomSample = useMemo(() => {\n if (!group || !isLargeTable) return [] as number[]\n return pickRandomSample(group, idToIdx)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [group, isLargeTable, idToIdx, reroll])\n\n const strategyIndices = useMemo(() => {\n if (!group) return [] as number[]\n if (!isLargeTable) return group.elements.map((_, i) => i)\n if (strategy === 'full') return group.elements.map((_, i) => i)\n if (strategy === 'random') return randomSample\n return subgroupInfo ? subgroupInfo.indices : randomSample\n }, [group, isLargeTable, strategy, subgroupInfo, randomSample])\n\n // 热力图 full 大群聚合:把 n×n 乘法表降采样到固定分辨率的众数色块网格。\n // 每个聚合色块覆盖原表一个矩形区域,颜色取该区域结果元素的众数。\n const heatmapAgg = useMemo(() => {\n if (!group || !table || !(showHeatmap && strategy === 'full' && group.order > HEATMAP_AGG_THRESHOLD)) return null\n const n = group.order\n const res = Math.min(HEATMAP_AGG_RES, n)\n const grid: number[][] = []\n for (let ai = 0; ai < res; ai++) {\n const r0 = Math.floor((ai * n) / res)\n const r1 = Math.floor(((ai + 1) * n) / res)\n const rowArr = new Array<number>(res)\n for (let aj = 0; aj < res; aj++) {\n const c0 = Math.floor((aj * n) / res)\n const c1 = Math.floor(((aj + 1) * n) / res)\n const counter = new Map<number, number>()\n for (let i = r0; i < r1; i++) {\n const row = table[i]\n for (let j = c0; j < c1; j++) {\n const v = idToIdx.get(row[j].id) ?? 0\n counter.set(v, (counter.get(v) ?? 0) + 1)\n }\n }\n let mode = idToIdx.get(table[r0][c0].id) ?? 0\n let best = -1\n for (const [v, c] of counter) {\n if (c > best) { best = c; mode = v }\n }\n rowArr[aj] = mode\n }\n grid.push(rowArr)\n }\n return grid\n }, [group, table, idToIdx, showHeatmap, strategy])\n\n // 向宿主上报实际渲染表格的内容尺寸(供 ViewWindow 设定最小窗口尺寸):\n // 大群告警 / 全屏占位时不渲染网格,回传 null(不强制窗口大小)\n const cellSize = cellSizeProp ?? 50\n // 热力图自适应 cell:显示「全表」(小群全表 或 大群 full 策略)时,cell 无需容纳文字,\n // 自适应缩小使整表在 viewBox 内可见,但不超过 cellSize 上限(不放大)。\n // 这样热力图窗口无论缩到多小都能看清整体色块模式(核心价值)。\n const isFullTable = group !== null && (!isLargeTable || strategy === 'full')\n const heatmapAutoFit = showHeatmap && isFullTable\n const heatmapRenderDim = heatmapAgg ? heatmapAgg.length : strategyIndices.length\n const fitCell = Math.max(4, Math.floor((Math.min(viewBoxSize.width, viewBoxSize.height) - 60) / Math.max(1, heatmapRenderDim)))\n const renderCell = heatmapAutoFit ? Math.min(cellSize, fitCell) : cellSize\n // 热力图(纯色块 + 聚合缩略图)可展示更大群,阈值放宽到 240;普通乘法表(文字)保持 100\n const tableBlocked = group ? isTooLarge(group.order, showHeatmap ? 'heatmap' : 'table', showHeatmap ? maxHeatmapOrder : maxTableOrder) && !forceShow : false\n // 热力图模式下的 full 策略不占位:纯色 cell 直接渲染整表,无需进入全屏\n const tablePlaceholder = !showHeatmap && isLargeTable && strategy === 'full' && !!group && group.order > 30 && !fullscreenOpen\n useEffect(() => {\n if (!group || !table) { onLayoutSize?.(null); return }\n if (tableBlocked || tablePlaceholder) { onLayoutSize?.(null); return }\n const k = heatmapAgg ? heatmapAgg.length : strategyIndices.length\n const padW = showHeatmap ? 0 : TABLE_PAD_W\n const padH = showHeatmap ? 40 : TABLE_PAD_H\n onLayoutSize?.({ width: k * renderCell + padW, height: k * renderCell + padH })\n }, [group, table, tableBlocked, tablePlaceholder, strategyIndices.length, heatmapAgg, renderCell, onLayoutSize, showHeatmap])\n\n const exitFullscreen = useCallback(() => {\n setFullscreenOpen(false)\n applyStrategy('subgroup')\n }, [applyStrategy])\n\n useEffect(() => {\n if (!fullscreenOpen) return\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') exitFullscreen()\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [fullscreenOpen, exitFullscreen])\n\n useEffect(() => {\n if (fullscreenOpen) {\n const body = fsBodyRef.current\n if (body) {\n body.scrollLeft = 0\n body.scrollTop = 0\n }\n }\n }, [fullscreenOpen])\n\n const openFullscreen = () => {\n setFsScale(1)\n setFullscreenOpen(true)\n }\n\n const handleStrategy = (s: TableStrategy) => {\n if (s === strategy) {\n setReroll(r => r + 1)\n return\n }\n if (s === 'full') {\n // 热力图模式的 full 策略:纯色 cell 直接渲染,不弹确认框、不进全屏\n if (!showHeatmap && group && group.order > 30) {\n setConfirmOpen(true)\n return\n }\n applyStrategy('full')\n return\n }\n applyStrategy(s)\n }\n\n const confirmFull = () => {\n setConfirmOpen(false)\n openFullscreen()\n }\n\n const adjustZoom = useCallback((factor: number, cx?: number, cy?: number) => {\n const body = fsBodyRef.current\n if (!body) return\n const rect = body.getBoundingClientRect()\n const mx = cx ?? rect.width / 2\n const my = cy ?? rect.height / 2\n const px = (body.scrollLeft + mx) / fsScale\n const py = (body.scrollTop + my) / fsScale\n const next = Math.min(6, Math.max(0.25, fsScale * factor))\n setFsScale(next)\n requestAnimationFrame(() => {\n body.scrollLeft = px * next - mx\n body.scrollTop = py * next - my\n })\n }, [fsScale])\n\n const onFsSlider = (v: number) => {\n adjustZoom(v / 100 / fsScale)\n }\n\n const onFwPointerDown = (e: RPointerEvent<HTMLDivElement>) => {\n const body = fsBodyRef.current\n if (!body) return\n fsDragRef.current = { x: e.clientX, y: e.clientY, sl: body.scrollLeft, st: body.scrollTop }\n setFsDragging(true)\n body.setPointerCapture(e.pointerId)\n }\n\n const onFwPointerMove = (e: RPointerEvent<HTMLDivElement>) => {\n const body = fsBodyRef.current\n const d = fsDragRef.current\n if (!body || !d) return\n body.scrollLeft = d.sl - (e.clientX - d.x)\n body.scrollTop = d.st - (e.clientY - d.y)\n }\n\n const onFwPointerUp = () => {\n fsDragRef.current = null\n setFsDragging(false)\n }\n\n const onFsScroll = useCallback(() => {\n const body = fsBodyRef.current\n if (!body || fsScrollRaf.current) return\n fsScrollRaf.current = requestAnimationFrame(() => {\n fsScrollRaf.current = 0\n setFsScroll({ l: body.scrollLeft, t: body.scrollTop })\n })\n }, [])\n\n useEffect(() => {\n return () => {\n if (fsScrollRaf.current) cancelAnimationFrame(fsScrollRaf.current)\n }\n }, [])\n\n useEffect(() => {\n if (!fullscreenOpen) return\n const body = fsBodyRef.current\n if (!body) return\n const update = () => setFsViewport({ w: body.clientWidth, h: body.clientHeight })\n update()\n const ro = new ResizeObserver(update)\n ro.observe(body)\n return () => ro.disconnect()\n }, [fullscreenOpen])\n\n const exportFullscreen = () => {\n const svg = fsSvgRef.current\n if (!svg || !group) return\n const clone = svg.cloneNode(true) as SVGSVGElement\n const vb = (svg.getAttribute('viewBox') || '0 0 800 600').trim().split(/\\s+/).map(Number)\n clone.setAttribute('width', String(vb[2] || 800))\n clone.setAttribute('height', String(vb[3] || 600))\n clone.removeAttribute('style')\n const blob = new Blob([new XMLSerializer().serializeToString(clone)], {\n type: 'image/svg+xml;charset=utf-8',\n })\n const sym = group.symbol.replace(/[^A-Za-z0-9]+/g, '_')\n triggerDownload(blob, `table_${sym}_${group.order}x${group.order}.svg`)\n }\n\n if (!group || !table) {\n return (\n <div className=\"view-empty\">\n <p>{noGroupText ?? t('canvas.noGroup')}</p>\n </div>\n )\n }\n\n if (isTooLarge(group.order, 'table', maxTableOrder) && !forceShow) {\n return (\n <div className=\"large-group-warning\">\n <p>{t('canvas.orderTooLarge', { n: group.order })}</p>\n <button className=\"panel-btn\" onClick={requestForceShow}>\n {t('canvas.show')}\n </button>\n </div>\n )\n }\n\n const { elements } = group\n\n const tableWidth = heatmapRenderDim * renderCell\n const tableHeight = heatmapRenderDim * renderCell\n const vw = viewBoxSize.width\n const vh = viewBoxSize.height\n const offsetX = vw / 2 - tableWidth / 2\n const offsetY = vh / 2 - tableHeight / 2\n\n const caption = isLargeTable\n ? strategy === 'subgroup' && subgroupInfo\n ? t('table.subgroupCaption', { label: subgroupInfo.label, order: subgroupInfo.order })\n : strategy === 'random'\n ? t('table.randomCaption', { n: strategyIndices.length })\n : strategy === 'full' && heatmapAgg\n ? t('table.heatmapAggCaption', { n: group.order, res: heatmapAgg.length })\n : ''\n : ''\n\n const showFullPlaceholder = !showHeatmap && isLargeTable && strategy === 'full' && group.order > 30 && !fullscreenOpen\n\n if (showFullPlaceholder) {\n return (\n <>\n <div className=\"table-strategy-bar\">\n {(['subgroup', 'random', 'full'] as TableStrategy[]).map(s => (\n <button\n key={s}\n className={`table-strategy-btn${strategy === s ? ' active' : ''}`}\n onClick={() => handleStrategy(s)}\n >\n {s === 'subgroup'\n ? t('table.strategy.subgroup')\n : s === 'random'\n ? t('table.strategy.random')\n : t('table.strategy.full')}\n </button>\n ))}\n </div>\n <div className=\"large-group-warning\">\n <p>{t('table.fullPlaceholderMsg', { n: group.order })}</p>\n <button className=\"panel-btn\" onClick={openFullscreen}>\n {t('table.fullEnter')}\n </button>\n </div>\n </>\n )\n }\n\n return (\n <>\n {isLargeTable && (\n <div className=\"table-strategy-bar\">\n {(['subgroup', 'random', 'full'] as TableStrategy[]).map(s => (\n <button\n key={s}\n className={`table-strategy-btn${strategy === s ? ' active' : ''}`}\n onClick={() => handleStrategy(s)}\n >\n {s === 'subgroup'\n ? t('table.strategy.subgroup')\n : s === 'random'\n ? t('table.strategy.random')\n : t('table.strategy.full')}\n </button>\n ))}\n {caption && <span className=\"table-strategy-caption\">{caption}</span>}\n </div>\n )}\n\n <svg viewBox={`0 0 ${vw} ${vh}`} className=\"view-svg\" style={{ userSelect: 'none' }}>\n <g transform={`translate(${canvasTransform.x}, ${canvasTransform.y}) scale(${canvasTransform.scale}) translate(${offsetX}, ${offsetY})`}>\n\n {/* Row headers — hidden in heatmap mode */}\n {!showHeatmap && strategyIndices.map((rowIdx, ri) => {\n const rowEl = elements[rowIdx]\n const isSelected = selectedIndices.has(rowIdx)\n const sInfo = subsetElemMap.get(rowIdx)\n const inSubgroup = elementsInAnySubgroup.has(rowIdx)\n const cosetMode = cosetData !== null\n const rowIsCosetAnchor = cosetActiveRowIds.has(rowEl.id)\n const rowCosetIdx = cem.get(rowEl.id)\n const rowCosetHl = rowIsCosetAnchor && rowCosetIdx !== undefined\n\n let headerFill = elementColors[rowIdx % elementColors.length]\n let bg: string | null = null\n if (!cosetMode && isSelected) bg = '#ffd93d33'\n else if (rowCosetHl) bg = (cosetColors ?? [])[rowCosetIdx] + '33'\n else if (!cosetMode && inSubgroup && sInfo) bg = sInfo.color + '33'\n if (!cosetMode && isSelected) headerFill = '#ffd93d'\n\n return (\n <g\n key={rowEl.id}\n transform={`translate(0, ${ri * cellSize})`}\n onClick={() => onSelect?.(rowEl.id, true)}\n style={{ cursor: 'pointer' }}\n >\n {bg && (\n <rect x={-38} y={2} width={33} height={cellSize - 4} fill={bg} rx={4} />\n )}\n <text\n x={-35}\n y={cellSize / 2 + 5}\n textAnchor=\"end\"\n fill={headerFill}\n fontSize={14}\n fontFamily=\"serif\"\n fontWeight={isSelected ? 'bold' : 'normal'}\n style={{ userSelect: 'none' }}\n >\n {rowEl.label}\n </text>\n </g>\n )\n })}\n\n {/* Column headers — hidden in heatmap mode */}\n {!showHeatmap && strategyIndices.map((colIdx, ci) => {\n const colEl = elements[colIdx]\n const isSelected = selectedIndices.has(colIdx)\n const sInfo = subsetElemMap.get(colIdx)\n const inSubgroup = elementsInAnySubgroup.has(colIdx)\n const cosetMode = cosetData !== null\n const colIsCosetAnchor = cosetActiveColIds.has(colEl.id)\n const colCosetIdx = cem.get(colEl.id)\n const colCosetHl = colIsCosetAnchor && colCosetIdx !== undefined\n\n let headerFill = elementColors[colIdx % elementColors.length]\n let bg: string | null = null\n if (!cosetMode && isSelected) bg = '#ffd93d33'\n else if (colCosetHl) bg = (cosetColors ?? [])[colCosetIdx] + '33'\n else if (!cosetMode && inSubgroup && sInfo) bg = sInfo.color + '33'\n if (!cosetMode && isSelected) headerFill = '#ffd93d'\n\n return (\n <g\n key={`head-${colEl.id}`}\n onClick={() => onSelect?.(colEl.id, true)}\n style={{ cursor: 'pointer' }}\n >\n {bg && (\n <rect x={ci * cellSize + 2} y={-16} width={cellSize - 4} height={18} fill={bg} rx={4} />\n )}\n <text\n x={ci * cellSize + cellSize / 2}\n y={-12}\n textAnchor=\"middle\"\n fill={headerFill}\n fontSize={14}\n fontFamily=\"serif\"\n fontWeight={isSelected ? 'bold' : 'normal'}\n style={{ userSelect: 'none' }}\n >\n {colEl.label}\n </text>\n </g>\n )\n })}\n\n {/* Heatmap aggregate thumbnail: downsampled mode-color blocks for large groups */}\n {heatmapAgg && heatmapAgg.map((aggRow, ai) =>\n aggRow.map((resultIdx, aj) => {\n const resultColor = elementColors[resultIdx % elementColors.length]\n const heatGap = renderCell <= 8 ? 0.5 : renderCell <= 20 ? 1 : 2\n const heatR = renderCell <= 8 ? 1 : renderCell <= 20 ? 2 : 3\n return (\n <g\n key={`agg-${ai}-${aj}`}\n transform={`translate(${aj * renderCell}, ${ai * renderCell})`}\n >\n <rect\n width={renderCell - heatGap}\n height={renderCell - heatGap}\n fill={resultColor}\n stroke=\"rgba(0,0,0,0.12)\"\n strokeWidth={renderCell <= 8 ? 0.2 : 0.5}\n rx={heatR}\n />\n </g>\n )\n })\n )}\n\n {/* Table cells */}\n {!heatmapAgg && strategyIndices.map((rowIdx, ri) =>\n strategyIndices.map((colIdx, ci) => {\n const rowEl = elements[rowIdx]\n const colEl = elements[colIdx]\n const result = table[rowIdx][colIdx]\n const resultColor = getElementColor(result.label)\n\n const isRowSel = selectedIndices.has(rowIdx)\n const isColSel = selectedIndices.has(colIdx)\n\n const sgKey = `${rowIdx},${colIdx}`\n const sgColor = subgroupCellColors.get(sgKey)\n\n const identityIdx = idToIdx.get(group.identity.id) ?? -1\n const nonSubRow = identityIdx >= 0 && rowIdx === identityIdx && nonSubgroupSubsetIndices.has(colIdx)\n const nonSubCol = identityIdx >= 0 && colIdx === identityIdx && nonSubgroupSubsetIndices.has(rowIdx)\n\n const colInSubgroup = cosetSubgroupIndices.has(colIdx)\n const rowInSubgroup = cosetSubgroupIndices.has(rowIdx)\n const cosetMode = cosetData !== null\n const rowIsCosetAnchor = cosetActiveRowIds.has(rowEl.id)\n const colIsCosetAnchor = cosetActiveColIds.has(colEl.id)\n\n const isLeftCosetCell = cosetType === 'left' && rowIsCosetAnchor && colInSubgroup\n const isRightCosetCell = cosetType === 'right' && colIsCosetAnchor && rowInSubgroup\n const isCosetCell = isLeftCosetCell || isRightCosetCell\n\n // Heatmap mode: solid fill, thin border\n if (showHeatmap) {\n // 大群热力图:cell 很小时用更小的间隙与圆角,保证色块紧凑、宏观结构清晰\n const heatGap = renderCell <= 8 ? 0.5 : renderCell <= 20 ? 1 : 2\n const heatR = renderCell <= 8 ? 1 : renderCell <= 20 ? 2 : 3\n let cellFill = resultColor\n let cellStroke = 'rgba(0,0,0,0.18)'\n let cellStrokeW = renderCell <= 8 ? 0.2 : 0.5\n\n if (isCosetCell) {\n const elId = cosetType === 'left' ? rowEl.id : colEl.id\n const cIdx = cem.get(elId)\n const cColor = cIdx !== undefined ? (cosetColors ?? [])[cIdx] : '#888'\n cellStroke = cColor\n cellStrokeW = 3\n } else if (sgColor) {\n cellStroke = sgColor\n cellStrokeW = 2.5\n } else if (!cosetMode && isRowSel && isColSel) {\n cellStroke = '#ffd93d'\n cellStrokeW = 2.5\n } else if (!cosetMode && (isRowSel || isColSel)) {\n cellStroke = '#ffd93d88'\n cellStrokeW = 1.5\n } else if (nonSubRow || nonSubCol) {\n cellFill = 'var(--table-cell-bg)'\n cellStroke = 'var(--table-cell-border)'\n cellStrokeW = 1.5\n }\n\n return (\n <g\n key={`${rowEl.id}-${colEl.id}`}\n transform={`translate(${ci * renderCell}, ${ri * renderCell})`}\n onClick={() => {\n const targetEl = elements.find(e => e.id === result.id)\n if (targetEl) onSelect?.(targetEl.id, true)\n }}\n onMouseEnter={() => {\n const targetEl = elements.find(e => e.id === result.id)\n if (targetEl) onHover?.(targetEl)\n }}\n onMouseLeave={() => onHover?.(null)}\n style={{ cursor: 'pointer' }}\n >\n <rect\n width={renderCell - heatGap}\n height={renderCell - heatGap}\n fill={cellFill}\n stroke={cellStroke}\n strokeWidth={cellStrokeW}\n rx={heatR}\n />\n </g>\n )\n }\n\n // Normal table mode: semi-transparent fill + text\n let cellFill = resultColor + '22'\n let cellStroke = resultColor\n let cellStrokeW = 0.5\n\n if (isCosetCell) {\n const elId = cosetType === 'left' ? rowEl.id : colEl.id\n const cIdx = cem.get(elId)\n const cColor = cIdx !== undefined ? (cosetColors ?? [])[cIdx] : '#888'\n cellFill = cColor + '40'\n cellStroke = cColor\n cellStrokeW = 2.5\n } else if (sgColor) {\n cellFill = sgColor + '28'\n cellStroke = sgColor\n cellStrokeW = 2\n } else if (!cosetMode && isRowSel && isColSel) {\n cellFill = '#ffd93d22'\n cellStroke = '#ffd93d'\n cellStrokeW = 2\n } else if (!cosetMode && (isRowSel || isColSel)) {\n cellFill = '#ffd93d15'\n cellStroke = '#ffd93d88'\n cellStrokeW = 1\n } else if (nonSubRow || nonSubCol) {\n cellFill = 'var(--table-cell-bg)'\n cellStroke = 'var(--table-cell-border)'\n cellStrokeW = 1.5\n }\n\n return (\n <g\n key={`${rowEl.id}-${colEl.id}`}\n transform={`translate(${ci * renderCell}, ${ri * renderCell})`}\n onClick={() => {\n const targetEl = elements.find(e => e.id === result.id)\n if (targetEl) onSelect?.(targetEl.id, true)\n }}\n onMouseEnter={() => {\n const targetEl = elements.find(e => e.id === result.id)\n if (targetEl) onHover?.(targetEl)\n }}\n onMouseLeave={() => onHover?.(null)}\n style={{ cursor: 'pointer' }}\n >\n <rect\n width={renderCell - 2}\n height={renderCell - 2}\n fill={cellFill}\n stroke={cellStroke}\n strokeWidth={cellStrokeW}\n rx={4}\n />\n <text\n x={renderCell / 2}\n y={renderCell / 2 + 5}\n textAnchor=\"middle\"\n fill={resultColor}\n fontSize={13}\n fontFamily=\"serif\"\n style={{ userSelect: 'none', pointerEvents: 'none' }}\n >\n {result.label}\n </text>\n </g>\n )\n })\n )}\n </g>\n\n <text x={vw / 2} y={tableHeight + offsetY + 35} textAnchor=\"middle\" fill=\"#666\" fontSize={11} style={{ userSelect: 'none' }}>\n {t('table.footer1')}\n </text>\n\n <text x={vw / 2} y={tableHeight + offsetY + 50} textAnchor=\"middle\" fill=\"#666\" fontSize={10} style={{ userSelect: 'none' }}>\n {t('table.footer2')}\n </text>\n </svg>\n\n {confirmOpen && (\n <div className=\"table-confirm-overlay\">\n <div className=\"table-confirm-modal\">\n <div className=\"table-confirm-title\">{t('table.fullConfirmTitle')}</div>\n <div className=\"table-confirm-msg\">\n {t('table.fullConfirmMsg', { n: group.order })}\n </div>\n <div className=\"table-confirm-actions\">\n <button className=\"panel-btn\" onClick={() => setConfirmOpen(false)}>\n {t('table.confirmCancel')}\n </button>\n <button className=\"panel-btn\" onClick={confirmFull}>\n {t('table.confirmOk')}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {fullscreenOpen && (\n <div className=\"table-fullscreen\">\n <div className=\"table-fullscreen-header\">\n <div className=\"table-fullscreen-title\">\n {t('table.fullTitle', { symbol: group.symbol, n: group.order })}\n </div>\n <div className=\"table-fullscreen-toolbar\">\n <button\n className=\"table-fs-btn\"\n title={t('table.fullZoomOut')}\n onClick={() => adjustZoom(1 / 1.25)}\n >\n −\n </button>\n <button\n className=\"table-fs-btn\"\n title={t('table.fullZoomIn')}\n onClick={() => adjustZoom(1.25)}\n >\n +\n </button>\n <button\n className=\"table-fs-btn\"\n title={t('table.fullZoomReset')}\n onClick={() => adjustZoom(1 / fsScale)}\n >\n ⟳\n </button>\n <input\n type=\"range\"\n className=\"table-fs-slider\"\n min={25}\n max={600}\n step={1}\n value={Math.round(fsScale * 100)}\n aria-label={t('table.zoomSlider')}\n onChange={(e) => onFsSlider(Number(e.target.value))}\n />\n <button className=\"panel-btn\" onClick={exportFullscreen}>\n {t('table.fullExport')}\n </button>\n <button className=\"panel-btn\" onClick={exitFullscreen}>\n {t('table.fullExit')}\n </button>\n </div>\n </div>\n <div\n className={`table-fullscreen-body${fsDragging ? ' dragging' : ''}`}\n ref={fsBodyRef}\n onScroll={onFsScroll}\n onPointerDown={onFwPointerDown}\n onPointerMove={onFwPointerMove}\n onPointerUp={onFwPointerUp}\n onPointerLeave={onFwPointerUp}\n >\n {(() => {\n const n = group.order\n const fsCell = 32\n const padL = 44\n const padT = 26\n const padB = 34\n const tw = n * fsCell + padL + 16\n const th = n * fsCell + padT + padB\n const fsIdentityIdx = idToIdx.get(group.identity.id) ?? -1\n const fvw = fsViewport.w || 960\n const fvh = fsViewport.h || 600\n const viewL = fsScroll.l / fsScale\n const viewT = fsScroll.t / fsScale\n const viewW = fvw / fsScale\n const viewH = fvh / fsScale\n const buf = 3\n const cStart = Math.max(0, Math.floor((viewL - padL) / fsCell) - buf)\n const cEnd = Math.min(n - 1, Math.ceil((viewL + viewW - padL) / fsCell) + buf)\n const rStart = Math.max(0, Math.floor((viewT - padT) / fsCell) - buf)\n const rEnd = Math.min(n - 1, Math.ceil((viewT + viewH - padT) / fsCell) + buf)\n const rowIdxList = Array.from({ length: rEnd - rStart + 1 }, (_, k) => rStart + k)\n const colIdxList = Array.from({ length: cEnd - cStart + 1 }, (_, k) => cStart + k)\n return (\n <svg\n ref={fsSvgRef}\n className=\"table-fullscreen-svg\"\n viewBox={`0 0 ${tw} ${th}`}\n style={{ width: tw * fsScale, height: th * fsScale }}\n >\n <g transform={`translate(${showHeatmap ? 8 : padL}, ${showHeatmap ? 8 : padT})`}>\n {!showHeatmap && rowIdxList.map((rowIdx) => {\n const rowEl = elements[rowIdx]\n return (\n <text\n key={`fr-${rowEl.id}`}\n x={-6}\n y={rowIdx * fsCell + fsCell / 2 + 4}\n textAnchor=\"end\"\n fill={elementColors[rowIdx % elementColors.length]}\n fontSize={11}\n fontFamily=\"serif\"\n >\n {rowEl.label}\n </text>\n )\n })}\n {!showHeatmap && colIdxList.map((colIdx) => {\n const colEl = elements[colIdx]\n return (\n <text\n key={`fc-${colEl.id}`}\n x={colIdx * fsCell + fsCell / 2}\n y={-6}\n textAnchor=\"middle\"\n fill={elementColors[colIdx % elementColors.length]}\n fontSize={11}\n fontFamily=\"serif\"\n >\n {colEl.label}\n </text>\n )\n })}\n {rowIdxList.map(rowIdx =>\n colIdxList.map(colIdx => {\n const rowEl = elements[rowIdx]\n const colEl = elements[colIdx]\n const result = table[rowIdx][colIdx]\n const resultColor = getElementColor(result.label)\n const sgKey = `${rowIdx},${colIdx}`\n const sgColor = subgroupCellColors.get(sgKey)\n const isRowSel = selectedIndices.has(rowIdx)\n const isColSel = selectedIndices.has(colIdx)\n const nonSubRow = fsIdentityIdx >= 0 && rowIdx === fsIdentityIdx && nonSubgroupSubsetIndices.has(colIdx)\n const nonSubCol = fsIdentityIdx >= 0 && colIdx === fsIdentityIdx && nonSubgroupSubsetIndices.has(rowIdx)\n const cosetMode = cosetData !== null\n const rowIsCosetAnchor = cosetActiveRowIds.has(rowEl.id)\n const colIsCosetAnchor = cosetActiveColIds.has(colEl.id)\n const colInSubgroup = cosetSubgroupIndices.has(colIdx)\n const rowInSubgroup = cosetSubgroupIndices.has(rowIdx)\n const isLeftCosetCell = cosetType === 'left' && rowIsCosetAnchor && colInSubgroup\n const isRightCosetCell = cosetType === 'right' && colIsCosetAnchor && rowInSubgroup\n const isCosetCell = isLeftCosetCell || isRightCosetCell\n\n if (showHeatmap) {\n let cellFill = resultColor\n let cellStroke = 'rgba(0,0,0,0.18)'\n let cellStrokeW = 0.5\n\n if (isCosetCell) {\n const elId = cosetType === 'left' ? rowEl.id : colEl.id\n const cIdx = cem.get(elId)\n const cColor = cIdx !== undefined ? (cosetColors ?? [])[cIdx] : '#888'\n cellStroke = cColor\n cellStrokeW = 3\n } else if (sgColor) {\n cellStroke = sgColor\n cellStrokeW = 2.5\n } else if (!cosetMode && isRowSel && isColSel) {\n cellStroke = '#ffd93d'\n cellStrokeW = 2.5\n } else if (!cosetMode && (isRowSel || isColSel)) {\n cellStroke = '#ffd93d88'\n cellStrokeW = 1.5\n } else if (nonSubRow || nonSubCol) {\n cellFill = 'var(--table-cell-bg)'\n cellStroke = 'var(--table-cell-border)'\n cellStrokeW = 1.5\n }\n\n return (\n <g key={`${rowEl.id}-${colEl.id}`} transform={`translate(${colIdx * fsCell}, ${rowIdx * fsCell})`}>\n <rect\n width={fsCell - 2}\n height={fsCell - 2}\n fill={cellFill}\n stroke={cellStroke}\n strokeWidth={cellStrokeW}\n rx={2}\n />\n </g>\n )\n }\n\n let cellFill = resultColor + '30'\n let cellStroke = resultColor\n let cellStrokeW = 0.5\n\n if (isCosetCell) {\n const elId = cosetType === 'left' ? rowEl.id : colEl.id\n const cIdx = cem.get(elId)\n const cColor = cIdx !== undefined ? (cosetColors ?? [])[cIdx] : '#888'\n cellFill = cColor + '40'\n cellStroke = cColor\n cellStrokeW = 2.5\n } else if (sgColor) {\n cellFill = sgColor + '28'\n cellStroke = sgColor\n cellStrokeW = 2\n } else if (!cosetMode && isRowSel && isColSel) {\n cellFill = '#ffd93d22'\n cellStroke = '#ffd93d'\n cellStrokeW = 2\n } else if (!cosetMode && (isRowSel || isColSel)) {\n cellFill = '#ffd93d15'\n cellStroke = '#ffd93d88'\n cellStrokeW = 1\n } else if (nonSubRow || nonSubCol) {\n cellFill = '#ffffff0d'\n cellStroke = '#8899aa'\n cellStrokeW = 1.5\n }\n\n return (\n <g key={`${rowEl.id}-${colEl.id}`} transform={`translate(${colIdx * fsCell}, ${rowIdx * fsCell})`}>\n <rect\n width={fsCell - 2}\n height={fsCell - 2}\n fill={cellFill}\n stroke={cellStroke}\n strokeWidth={cellStrokeW}\n rx={2}\n />\n <text\n x={fsCell / 2}\n y={fsCell / 2 + 4}\n textAnchor=\"middle\"\n fill={resultColor}\n fontSize={11}\n fontFamily=\"serif\"\n style={{ pointerEvents: 'none' }}\n >\n {result.label}\n </text>\n </g>\n )\n })\n )}\n </g>\n <text\n x={tw / 2}\n y={th - 10}\n textAnchor=\"middle\"\n fill=\"#888\"\n fontSize={12}\n >\n {t('table.footer1')}\n </text>\n </svg>\n )\n })()}\n </div>\n </div>\n )}\n </>\n )\n}\n","import { useMemo, useRef, useState } from 'react'\nimport { SceneThemeRoot, type SceneTheme } from './SceneThemeRoot'\nimport { useTranslation } from '../../i18n/useTranslation'\nimport { texify, renderTex } from '../../utils/texify'\nimport type { Group, GroupActionArrow, GroupActionComputation, GroupActionKind, GroupElement, CanvasTransform } from '../../core/types'\nimport { computeFixedPoints, computeCycleCandidates, type CustomArrowError } from '../../core/algebra/actions'\n\n// ─── Action props 化内核(批次六 FGVE) ─────────────────────────────────\n// 受控 ViewWindow(conjugation/regular/custom 三来源)与主画布(经 context 壳\n// ActionView)共用。group/computation 之外全部可选:主画布壳由全局 Provider 组装,\n// 窗口引擎自包含时自算 computation 并以本地/受控态驱动选中与编辑。\n\nconst NODE_R = 28\nconst CLUSTER_PAD = 26\nconst CLUSTER_GAP = 90\nconst CHIP_W = 100\nconst CHIP_H = 30\nconst CHIP_GAP = 10\nconst CHIP_ROW_H = CHIP_H + 10\nconst CHIP_PER_ROW = 8\nconst GRP_PAD = 8\nconst GRP_HDR = 18\nconst GRP_GAP = 14\nconst HOVER_COLOR = '#ffd93d'\nconst SNAP_R = 44\n\nfunction clusterRadius(size: number): number {\n // 相邻节点弦长 = 2r·sin(π/size) ≈ 220,两端各收缩 ~50(nodeR+headLen)后边仍 ~120 可见\n if (size <= 1) return 52\n return Math.max(52, Math.ceil(110 / Math.sin(Math.PI / size)))\n}\n\nfunction arrowHeadPoints(ex: number, ey: number, angle: number, size = 10): string {\n const a1 = angle - Math.PI / 6\n const a2 = angle + Math.PI / 6\n return `${ex},${ey} ${ex - Math.cos(a1) * size},${ey - Math.sin(a1) * size} ${ex - Math.cos(a2) * size},${ey - Math.sin(a2) * size}`\n}\n\ninterface EdgeProps {\n sx: number\n sy: number\n ex: number\n ey: number\n color: string\n width?: number\n dashed?: boolean\n dir?: 1 | -1\n opacity?: number\n headSize?: number\n nodeR?: number\n offset?: number\n tFrom?: { x: number; y: number }\n onClick?: () => void\n onDrop?: (e: React.DragEvent) => void\n highlight?: boolean\n}\n\nfunction DirectedEdge({ sx, sy, ex, ey, color, width = 2.2, dashed, dir: _dir = 1, opacity = 0.85, headSize = 12, nodeR = 0, offset = 0, tFrom, onClick, onDrop, highlight }: EdgeProps) {\n const dx = ex - sx\n const dy = ey - sy\n const dist = Math.sqrt(dx * dx + dy * dy) || 1\n const ux = dx / dist\n const uy = dy / dist\n const headLen = Math.min(headSize * 1.25, Math.max(12, dist * 0.25))\n const arrowSize = Math.min(headSize, headLen)\n const fx = tFrom ? tFrom.x : -uy\n const fy = tFrom ? tFrom.y : ux\n const ax = sx + ux * nodeR + fx * offset\n const ay = sy + uy * nodeR + fy * offset\n const bx = ex - ux * (nodeR + headLen) + fx * offset\n const by = ey - uy * (nodeR + headLen) + fy * offset\n const c1x = (ax + bx) / 2\n const c1y = (ay + by) / 2\n const angle = Math.atan2(by - c1y, bx - c1x)\n const d = `M${ax},${ay} Q${c1x},${c1y} ${bx},${by}`\n\n return (\n <g>\n <path\n d={d}\n fill=\"none\"\n stroke={color}\n strokeWidth={width}\n strokeDasharray={dashed ? '5 4' : undefined}\n strokeOpacity={opacity}\n strokeLinecap=\"round\"\n />\n <polygon\n points={arrowHeadPoints(bx, by, angle, arrowSize)}\n fill={color}\n stroke={color}\n strokeWidth={0.5}\n opacity={opacity}\n />\n {highlight && (\n <path\n d={d}\n fill=\"none\"\n stroke={HOVER_COLOR}\n strokeWidth={6.5}\n strokeDasharray={dashed ? '8 5' : undefined}\n strokeOpacity={0.95}\n strokeLinecap=\"round\"\n style={{ pointerEvents: 'none' }}\n />\n )}\n {(onClick || onDrop) && (\n <path\n d={d}\n fill=\"none\"\n stroke=\"transparent\"\n strokeWidth={16}\n style={{ cursor: onClick ? 'pointer' : 'default', pointerEvents: 'stroke' }}\n onClick={(e) => { e.stopPropagation(); onClick?.() }}\n onDragOver={(e) => { if (onDrop) { e.preventDefault(); e.dataTransfer.dropEffect = 'copy' } }}\n onDrop={(e) => { if (onDrop) { e.preventDefault(); e.stopPropagation(); onDrop(e) } }}\n />\n )}\n </g>\n )\n}\n\nfunction ClusterNode({\n x, y, label, isSelected, isFixed, nodeR = NODE_R, onClick, onPointerDown, showNumber, onHoverIn, onHoverOut, testId,\n}: {\n x: number\n y: number\n label: string\n isSelected: boolean\n isFixed: boolean\n nodeR?: number\n onClick?: () => void\n onPointerDown?: (e: React.PointerEvent) => void\n showNumber?: number\n /** 悬停进入(窗口接就地气泡 + 金色箭头联动;主画布壳不传) */\n onHoverIn?: () => void\n onHoverOut?: () => void\n /** 测试钩子(action-node 显示态环节点 / action-edit-node 编辑态数字节点) */\n testId?: string\n}) {\n const fill = isSelected ? 'var(--node-fill-selected)' : 'var(--node-fill)'\n const stroke = isSelected ? HOVER_COLOR : 'var(--node-stroke)'\n return (\n <g\n transform={`translate(${x}, ${y})`}\n onClick={(e) => { e.stopPropagation(); onClick?.() }}\n onPointerDown={onPointerDown}\n onMouseEnter={onHoverIn}\n onMouseLeave={onHoverOut}\n data-testid={testId}\n style={{ cursor: onClick || onPointerDown ? 'pointer' : 'default' }}\n >\n <circle r={nodeR} fill={fill} stroke={stroke} strokeWidth={isSelected ? 3 : 2} filter=\"url(#node-shadow)\" />\n {isFixed && (\n <text x={nodeR - 2} y={-(nodeR + 2)} textAnchor=\"middle\" fill={HOVER_COLOR} fontSize={13} fontWeight=\"bold\">★</text>\n )}\n {label !== '' ? (\n <foreignObject\n x={-nodeR}\n y={-12}\n width={nodeR * 2}\n height={24}\n style={{ pointerEvents: 'none', userSelect: 'none' }}\n >\n <div\n style={{\n display: 'flex', alignItems: 'center', justifyContent: 'center',\n width: '100%', height: '100%', color: 'var(--node-text)', fontSize: '13px',\n whiteSpace: 'nowrap',\n }}\n dangerouslySetInnerHTML={{ __html: label }}\n />\n </foreignObject>\n ) : showNumber !== undefined ? (\n <text y={4} textAnchor=\"middle\" fill=\"var(--node-text)\" fontSize={14} style={{ pointerEvents: 'none' }}>\n {showNumber}\n </text>\n ) : null}\n </g>\n )\n}\n\nfunction ElementChip({ label, color, symbol, isSelected, onClick, onHover, onPointerDown }: {\n label: string\n color?: string\n symbol?: string\n isSelected: boolean\n onClick: () => void\n onHover?: (on: boolean) => void\n onPointerDown?: (e: React.PointerEvent, symbol: string) => void\n}) {\n return (\n <g\n onClick={(e) => { e.stopPropagation(); onClick() }}\n onMouseEnter={() => onHover?.(true)}\n onMouseLeave={() => onHover?.(false)}\n onPointerDown={symbol && onPointerDown ? (e) => onPointerDown(e, symbol) : undefined}\n style={{ cursor: 'pointer', touchAction: 'none' }}\n >\n <rect\n width={CHIP_W}\n height={CHIP_H}\n rx={6}\n fill={isSelected ? 'var(--node-fill-selected)' : 'var(--node-fill)'}\n stroke={isSelected ? HOVER_COLOR : (color || 'var(--node-stroke)')}\n strokeWidth={isSelected ? 2.5 : 1.5}\n />\n <foreignObject\n x={0}\n y={0}\n width={CHIP_W}\n height={CHIP_H}\n style={{ pointerEvents: 'none', userSelect: 'none' }}\n >\n <div\n style={{\n display: 'flex', alignItems: 'center', justifyContent: 'center',\n width: '100%', height: '100%', color: 'var(--node-text)', fontSize: '14px',\n whiteSpace: 'nowrap', overflow: 'hidden',\n }}\n dangerouslySetInnerHTML={{ __html: label }}\n />\n </foreignObject>\n </g>\n )\n}\n\nconst UNBOUND_COLOR = '#f59e0b'\n\nfunction quadPoint(p0: { x: number; y: number }, c: { x: number; y: number }, p1: { x: number; y: number }, t: number) {\n const mt = 1 - t\n return {\n x: mt * mt * p0.x + 2 * mt * t * c.x + t * t * p1.x,\n y: mt * mt * p0.y + 2 * mt * t * c.y + t * t * p1.y,\n }\n}\n\nfunction distToArrow(from: { x: number; y: number }, to: { x: number; y: number }, p: { x: number; y: number }): number {\n const dx = to.x - from.x\n const dy = to.y - from.y\n const dist = Math.sqrt(dx * dx + dy * dy) || 1\n const ux = -dy / dist\n const uy = dx / dist\n const c = { x: (from.x + to.x) / 2 + ux * 8, y: (from.y + to.y) / 2 + uy * 8 }\n let best = Infinity\n for (let i = 0; i <= 20; i++) {\n const q = quadPoint(from, c, to, i / 20)\n best = Math.min(best, Math.hypot(q.x - p.x, q.y - p.y))\n }\n return best\n}\n\ninterface CustomActionEditorProps {\n group: Group\n vw: number\n vh: number\n setSize: number\n arrows: GroupActionArrow[]\n error: CustomArrowError | null\n onAddArrow: (from: number, to: number, generatorId?: string | null) => void\n onBindArrow: (from: number, to: number, generatorId: string) => void\n onRemoveArrow: (from: number, generatorId?: string | null, to?: number) => void\n onReplaceGenArrows: (generatorId: string | null, pairs: [number, number][]) => void\n}\n\nfunction CustomActionEditor({ group, vw, vh, setSize: actionSetSize, arrows: actionArrows, error: actionError, onAddArrow: addArrow, onBindArrow: bindArrow, onRemoveArrow: removeArrow, onReplaceGenArrows: replaceGenArrows }: CustomActionEditorProps) {\n const { t } = useTranslation()\n const [selectedGen, setSelectedGen] = useState<string | null>(null)\n const [drag, setDrag] = useState<{ symbol: string; x: number; y: number } | null>(null)\n const [hoverArrow, setHoverArrow] = useState<number | null>(null)\n const [draw, setDraw] = useState<{ from: number; x: number; y: number; snap: number | null } | null>(null)\n const drawInfoRef = useRef<{ from: number; origin: { x: number; y: number }; snap: number | null; justStarted: boolean; justPicked: boolean } | null>(null)\n const movedRef = useRef(false)\n const dragRef = useRef<{ symbol: string; from: number } | null>(null)\n const downPosRef = useRef<{ x: number; y: number } | null>(null)\n const dragMovedRef = useRef(false)\n const hoverArrowRef = useRef<number | null>(null)\n\n const n = actionSetSize\n const ringR = Math.max(220, n * 22)\n const cx = vw / 2\n const cy = vh / 2 + 40\n const pos = (i: number) => {\n const angle = (i / n) * 2 * Math.PI - Math.PI / 2\n return { x: cx + Math.cos(angle) * ringR, y: cy + Math.sin(angle) * ringR }\n }\n\n const genColor = (symbol: string) => {\n const gen = group.generators.find(g => g.symbol === symbol)\n return gen?.color || 'var(--node-stroke)'\n }\n\n const toViewBox = (clientX: number, clientY: number, svg: SVGSVGElement) => {\n const r = svg.getBoundingClientRect()\n const scale = Math.min(r.width / vw, r.height / vh)\n const x0 = r.left + (r.width - vw * scale) / 2\n const y0 = r.top + (r.height - vh * scale) / 2\n return { x: (clientX - x0) / scale, y: (clientY - y0) / scale }\n }\n\n const startDrag = (e: React.PointerEvent, symbol: string) => {\n if (e.button !== 0) return\n const svg = (e.currentTarget as SVGElement).ownerSVGElement\n if (!svg) return\n e.preventDefault()\n e.stopPropagation()\n ;(e.currentTarget as Element).setPointerCapture(e.pointerId)\n const p = toViewBox(e.clientX, e.clientY, svg)\n dragMovedRef.current = false\n downPosRef.current = p\n dragRef.current = { symbol, from: -1 }\n setDrag({ symbol, x: p.x, y: p.y })\n }\n\n const onDragMove = (e: React.PointerEvent) => {\n if (!dragRef.current) return\n const svg = (e.currentTarget as SVGElement).ownerSVGElement\n if (!svg) return\n const p = toViewBox(e.clientX, e.clientY, svg)\n if (downPosRef.current && Math.hypot(p.x - downPosRef.current.x, p.y - downPosRef.current.y) > 14) {\n dragMovedRef.current = true\n }\n let bestIdx: number | null = null\n let bestDist = 48\n actionArrows.forEach((a, i) => {\n if (a.generatorId !== null) return\n const d = distToArrow(pos(a.from), pos(a.to), p)\n if (d < bestDist) {\n bestDist = d\n bestIdx = i\n }\n })\n hoverArrowRef.current = bestIdx\n setHoverArrow(bestIdx)\n setDrag(d => (d ? { ...d, x: p.x, y: p.y } : d))\n }\n\n const onDragEnd = () => {\n if (!dragRef.current) return\n const targetIdx = hoverArrowRef.current\n const moved = dragMovedRef.current\n const symbol = dragRef.current.symbol\n dragRef.current = null\n downPosRef.current = null\n hoverArrowRef.current = null\n setDrag(null)\n setHoverArrow(null)\n if (moved && targetIdx !== null) {\n const a = actionArrows[targetIdx]\n if (a && a.generatorId === null) bindArrow(a.from, a.to, symbol)\n }\n window.setTimeout(() => { dragMovedRef.current = false }, 0)\n }\n\n const startArrowDraw = (e: React.PointerEvent, i: number) => {\n if (e.button !== 0) return\n if (drawInfoRef.current) return\n const svg = (e.currentTarget as SVGElement).ownerSVGElement\n if (!svg) return\n e.preventDefault()\n e.stopPropagation()\n ;(e.currentTarget as Element).setPointerCapture(e.pointerId)\n const p = toViewBox(e.clientX, e.clientY, svg)\n movedRef.current = false\n drawInfoRef.current = { from: i, origin: p, snap: null, justStarted: true, justPicked: false }\n setDraw({ from: i, x: p.x, y: p.y, snap: null })\n }\n\n const onArrowMove = (e: React.PointerEvent) => {\n const info = drawInfoRef.current\n if (!info) return\n const svg = (e.currentTarget as SVGElement).ownerSVGElement\n if (!svg) return\n const p = toViewBox(e.clientX, e.clientY, svg)\n if (Math.hypot(p.x - info.origin.x, p.y - info.origin.y) > 6) movedRef.current = true\n let snap: number | null = null\n for (let j = 0; j < n; j++) {\n const q = pos(j)\n if (Math.hypot(p.x - q.x, p.y - q.y) < SNAP_R) {\n snap = j\n break\n }\n }\n drawInfoRef.current = { ...info, snap }\n setDraw(d => (d ? { ...d, x: p.x, y: p.y, snap } : d))\n }\n\n const deployArrow = (from: number, to: number) => {\n addArrow(from, to, selectedGen)\n drawInfoRef.current = null\n setDraw(null)\n }\n\n const onArrowUp = () => {\n const info = drawInfoRef.current\n if (!info) return\n if (movedRef.current) {\n drawInfoRef.current = null\n setDraw(null)\n if (info.snap !== null && info.snap !== info.from) {\n addArrow(info.from, info.snap, selectedGen)\n }\n return\n }\n if (info.justStarted) {\n drawInfoRef.current = { ...info, justStarted: false, justPicked: true }\n }\n }\n\n const k = group.generators.length\n const genColX = 60\n const genTop = cy - ((k - 1) / 2) * CHIP_ROW_H\n const genChips = group.generators.map((gen, i) => {\n return (\n <g\n key={`genchip-${i}`}\n transform={`translate(${genColX}, ${genTop + i * CHIP_ROW_H})`}\n onPointerMove={onDragMove}\n onPointerUp={onDragEnd}\n >\n <ElementChip\n label={renderTex(texify(gen.symbol))}\n color={gen.color}\n symbol={gen.symbol}\n isSelected={selectedGen === gen.symbol}\n onClick={() => { if (!dragMovedRef.current) setSelectedGen(prev => (prev === gen.symbol ? null : gen.symbol)) }}\n onPointerDown={startDrag}\n />\n </g>\n )\n })\n\n const dirCount = new Map<string, number>()\n const dirIndex = new Map<number, number>()\n actionArrows.forEach((a, i) => {\n if (a.from === a.to) return\n const key = `${Math.min(a.from, a.to)}|${Math.max(a.from, a.to)}`\n const dk = a.from < a.to ? `${key}f` : `${key}b`\n const c = dirCount.get(dk) ?? 0\n dirCount.set(dk, c + 1)\n dirIndex.set(i, c)\n })\n\n const loopGroups = new Map<number, number[]>()\n actionArrows.forEach((a, i) => {\n if (a.from !== a.to) return\n const arr = loopGroups.get(a.from)\n if (arr) arr.push(i)\n else loopGroups.set(a.from, [i])\n })\n const loopSlot = new Map<number, number>()\n loopGroups.forEach(arr => arr.forEach((idx, slot) => loopSlot.set(idx, slot)))\n\n const arrowsEls = actionArrows.map((a, i) => {\n const from = pos(a.from)\n const to = pos(a.to)\n const isUnbound = a.generatorId === null\n const color = a.generatorId === null ? UNBOUND_COLOR : genColor(a.generatorId)\n const handleClick = () => {\n if (dragMovedRef.current) return\n if (isUnbound) {\n if (selectedGen) bindArrow(a.from, a.to, selectedGen)\n else removeArrow(a.from, null, a.to)\n } else {\n removeArrow(a.from, a.generatorId)\n }\n }\n if (a.from === a.to) {\n const slot = loopSlot.get(i) ?? 0\n const cy = from.y - 32 + slot * 24\n return (\n <g key={`loop-${a.generatorId ?? 'u'}-${a.from}`} style={{ cursor: 'pointer' }} onClick={(e) => { e.stopPropagation(); handleClick() }}>\n <circle cx={from.x} cy={cy} r={16} fill=\"none\" stroke=\"transparent\" strokeWidth={16} />\n <circle cx={from.x} cy={cy} r={12} fill=\"none\" stroke={color} strokeWidth={isUnbound ? 4.5 : 3} strokeDasharray={isUnbound ? '5 4' : undefined} opacity={1} />\n <polygon points={`${from.x},${cy - 14} ${from.x - 6},${cy - 23} ${from.x + 6},${cy - 23}`} fill={color} opacity={1} />\n </g>\n )\n }\n const offset = 8 + (dirIndex.get(i) ?? 0) * 18\n return (\n <DirectedEdge\n key={`${a.from}-${i}`}\n sx={from.x}\n sy={from.y}\n ex={to.x}\n ey={to.y}\n color={color}\n width={isUnbound ? 4.5 : 3}\n headSize={isUnbound ? 13 : 12}\n nodeR={20}\n offset={offset}\n dashed={isUnbound}\n opacity={1}\n highlight={hoverArrow === i}\n onClick={handleClick}\n />\n )\n })\n\n const hintY = genTop + k * CHIP_ROW_H + 16\n\n const chainArrows =\n selectedGen !== null\n ? actionArrows.some(a => a.generatorId === selectedGen)\n ? actionArrows.filter(a => a.generatorId === selectedGen)\n : actionArrows.filter(a => a.generatorId === null)\n : actionArrows.filter(a => a.generatorId === null)\n const candidates = computeCycleCandidates(chainArrows, n)\n\n return (\n <g onPointerMove={onArrowMove} onPointerUp={onArrowUp}>\n <rect\n x={0}\n y={0}\n width={vw}\n height={vh}\n fill=\"transparent\"\n onClick={() => {\n drawInfoRef.current = null\n setDraw(null)\n }}\n />\n {genChips}\n {candidates.length > 0 && (\n <foreignObject x={0} y={24} width={vw} height={46} style={{ pointerEvents: 'none' }}>\n <div\n style={{\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n gap: 8,\n flexWrap: 'wrap',\n pointerEvents: 'auto',\n }}\n >\n <span style={{ fontSize: 13, color: 'var(--text-secondary)' }}>{t('action.cycleCandidates')}</span>\n {candidates.map(c => (\n <button\n key={c.length}\n onClick={() => {\n if (dragMovedRef.current) return\n replaceGenArrows(selectedGen, c.pairs)\n }}\n style={{\n fontSize: 13,\n padding: '3px 10px',\n cursor: 'pointer',\n borderRadius: 6,\n border: '1px solid var(--node-stroke)',\n background: 'var(--node-fill)',\n color: 'var(--text-primary)',\n }}\n >\n {c.length} {t('action.cycleUnit')} {c.label}\n </button>\n ))}\n </div>\n </foreignObject>\n )}\n <text x={genColX} y={hintY} fill=\"var(--text-secondary)\" fontSize={14}>\n {t('action.editHint')}\n </text>\n <text x={genColX} y={hintY + 22} fill=\"var(--text-secondary)\" fontSize={13}>\n {t('action.genSelectHint')}\n </text>\n {arrowsEls}\n {draw && (\n <DirectedEdge\n sx={pos(draw.from).x}\n sy={pos(draw.from).y}\n ex={draw.snap !== null ? pos(draw.snap).x : draw.x}\n ey={draw.snap !== null ? pos(draw.snap).y : draw.y}\n color={HOVER_COLOR}\n width={3}\n headSize={13}\n nodeR={20}\n dashed\n opacity={0.9}\n />\n )}\n {Array.from({ length: n }, (_, i) => (\n <ClusterNode\n key={i}\n x={pos(i).x}\n y={pos(i).y}\n label=\"\"\n showNumber={i + 1}\n isSelected={draw?.snap === i}\n isFixed={false}\n nodeR={20}\n testId={`action-edit-node-${i + 1}`}\n onPointerDown={(e) => startArrowDraw(e, i)}\n onClick={() => {\n const info = drawInfoRef.current\n if (!info) return\n if (info.justPicked) {\n drawInfoRef.current = { ...info, justPicked: false }\n return\n }\n deployArrow(info.from, i)\n }}\n />\n ))}\n {drag && (\n <g transform={`translate(${drag.x}, ${drag.y})`} opacity={0.92} style={{ pointerEvents: 'none' }}>\n <rect x={-CHIP_W / 2} y={-CHIP_H / 2} width={CHIP_W} height={CHIP_H} rx={6}\n fill={genColor(drag.symbol)} fillOpacity={0.35}\n stroke={genColor(drag.symbol)} strokeWidth={2.5} />\n <text x={0} y={5} textAnchor=\"middle\" fill=\"var(--node-text)\" fontSize={17} fontWeight=\"bold\" style={{ pointerEvents: 'none' }}>\n {drag.symbol}\n </text>\n <text x={0} y={CHIP_H / 2 + 16} textAnchor=\"middle\" fill={HOVER_COLOR} fontSize={13} style={{ pointerEvents: 'none' }}>\n {t('action.dropHint')}\n </text>\n </g>\n )}\n {actionError && (\n <text x={cx} y={cy + ringR + 92} textAnchor=\"middle\" fill=\"#f43f5e\" fontSize={14}>\n {actionError.type === 'homomorphism'\n ? t('action.error.homomorphism', {\n g: actionError.g ?? '',\n gen: actionError.generatorId ?? '',\n x: String(actionError.from + 1),\n })\n : t(`action.error.${actionError.type}`, {\n gen: actionError.generatorId ?? '',\n from: String(actionError.from + 1),\n to: String(actionError.to + 1),\n })}\n </text>\n )}\n </g>\n )\n}\n\nfunction computeFitVB(computation: GroupActionComputation, showLabels = true): { width: number; height: number } {\n const widths = computation.orbits.map(o => 2 * (clusterRadius(o.elements.length) + NODE_R + CLUSTER_PAD))\n const totalW = widths.reduce((a, b) => a + b, 0) + CLUSTER_GAP * Math.max(0, computation.orbits.length - 1)\n let yAcc = 0\n if (showLabels) {\n computation.orbits.forEach(o => {\n const size = o.elements.length\n yAcc += GRP_HDR + Math.ceil(size / CHIP_PER_ROW) * CHIP_ROW_H + 2 * GRP_PAD + GRP_GAP\n })\n }\n const chipsH = showLabels ? yAcc - GRP_GAP : 0\n // showLabels=false(嵌入窗口缺省):顶部 chips 区隐藏,只留生成元图例高度\n const topRegion = (showLabels ? 12 : 42) + chipsH + 30\n const maxH = Math.max(0, ...widths)\n const contentH = topRegion + 60 + maxH + 60\n const contentW = Math.max(totalW + 2 * CLUSTER_GAP, 320)\n return { width: Math.ceil(contentW), height: Math.ceil(contentH) }\n}\n\ninterface DisplayModeProps {\n group: Group\n computation: GroupActionComputation\n kind: GroupActionKind\n selectedElement: number | null\n onSelectedElementChange?: (x: number | null) => void\n hoveredElement: string | null\n onHoverElementChange?: (id: string | null) => void\n /** chips 群元素点击 → 主画布全局选中;窗口不传(chips 缺省隐藏也无需此交互) */\n onSetElementSelect?: (id: string) => void\n /** 节点常驻标签 + 顶部轨道 chips 区;缺省 true(主画布观感)。窗口 false:节点空圈 + chips 区隐藏 */\n showLabels: boolean\n /** 悬停就地气泡(窗口接 handleHover);主画布壳不传 */\n onHover?: (el: GroupElement | null, anchor?: { x: number; y: number } | null) => void\n legendHover: string | null\n onLegendHover: (s: string | null) => void\n viewBoxOverride?: { width: number; height: number }\n canvasTransform: CanvasTransform\n viewBoxSize: { width: number; height: number }\n}\n\nfunction DisplayMode({ group, computation, kind, selectedElement, onSelectedElementChange, hoveredElement, onHoverElementChange, onSetElementSelect, showLabels, onHover, legendHover, onLegendHover, viewBoxOverride, canvasTransform, viewBoxSize }: DisplayModeProps) {\n const { t } = useTranslation()\n const vw = viewBoxOverride?.width ?? viewBoxSize.width\n const vh = viewBoxOverride?.height ?? viewBoxSize.height\n\n const { n, perms, orbits, orbitOf } = computation\n const fixed = useMemo(() => new Set(computeFixedPoints(perms, n)), [perms, n])\n const isConjugation = kind === 'conjugation'\n const showsElements = isConjugation || kind === 'regular'\n const hoverActive = !!hoveredElement\n\n // 场景 svg viewBox = computeFitVB 内容包围盒(vw/vh),但 .view-svg 拉伸填满\n // 视口(viewBoxSize = 容器 CSS 像素)。宽高比不一致时浏览器按 preserveAspectRatio\n // 居中缩放(letterbox)→ 视口坐标 = viewBox 坐标经仿射 (s, ox, oy)。锚点必须套同一\n // 仿射,否则就地气泡偏离节点(其它视图 svg viewBox=容器尺寸 1:1,无需此步)。\n const svgFit = Math.min(viewBoxSize.width / Math.max(vw, 1), viewBoxSize.height / Math.max(vh, 1))\n const letterboxX = (viewBoxSize.width - vw * svgFit) / 2\n const letterboxY = (viewBoxSize.height - vh * svgFit) / 2\n const anchorOf = (p: { x: number; y: number }) => ({\n x: (p.x * canvasTransform.scale + canvasTransform.x) * svgFit + letterboxX,\n y: (p.y * canvasTransform.scale + canvasTransform.y) * svgFit + letterboxY,\n })\n\n const widths = orbits.map(o => 2 * (clusterRadius(o.elements.length) + NODE_R + CLUSTER_PAD))\n const totalW = widths.reduce((a, b) => a + b, 0) + CLUSTER_GAP * (orbits.length - 1)\n const heights = orbits.map(o => 2 * (clusterRadius(o.elements.length) + NODE_R + CLUSTER_PAD))\n const maxH = Math.max(0, ...heights)\n\n const legendStart = vw - 40 - group.generators.length * 110\n const legend = group.generators.map((gen, i) => (\n <g\n key={`legend-${i}`}\n transform={`translate(${legendStart + i * 110}, 0)`}\n onMouseEnter={() => onLegendHover(gen.symbol)}\n onMouseLeave={() => onLegendHover(null)}\n style={{ cursor: 'pointer' }}\n >\n <circle cx={10} cy={10} r={6} fill={gen.color || 'var(--node-stroke)'} />\n <text x={22} y={15} fill=\"var(--text-secondary)\" fontSize={14}>{gen.symbol}</text>\n </g>\n ))\n\n const grpW: number[] = []\n const grpH: number[] = []\n orbits.forEach(o => {\n const size = o.elements.length\n const colsInRow = Math.min(CHIP_PER_ROW, size)\n grpW.push(colsInRow * CHIP_W + (colsInRow - 1) * CHIP_GAP + 2 * GRP_PAD)\n grpH.push(GRP_HDR + Math.ceil(size / CHIP_PER_ROW) * CHIP_ROW_H + 2 * GRP_PAD)\n })\n\n let yAcc = 0\n const lineTop = orbits.map((_, gi) => {\n const top = yAcc\n yAcc += grpH[gi] + GRP_GAP\n return top\n })\n const chipsH = showLabels ? yAcc - GRP_GAP : 0\n\n const topRegion = (showLabels ? 12 : 42) + chipsH + 30\n const contentH = topRegion + 60 + maxH\n const vOffset = Math.max(30, (vh - contentH) / 2)\n\n const centers: { x: number; y: number; r: number }[] = []\n let cursorX = Math.max(0, (vw - totalW) / 2)\n for (let i = 0; i < orbits.length; i++) {\n const r = clusterRadius(orbits[i].elements.length)\n centers.push({ x: cursorX + widths[i] / 2, y: vOffset + topRegion + 60 + maxH / 2, r })\n cursorX += widths[i] + CLUSTER_GAP\n }\n\n const nodePos = (x: number) => {\n const oi = orbitOf[x]\n const c = centers[oi]\n const idx = orbits[oi].elements.indexOf(x)\n const angle = (idx / orbits[oi].elements.length) * 2 * Math.PI - Math.PI / 2\n return { x: c.x + Math.cos(angle) * c.r, y: c.y + Math.sin(angle) * c.r }\n }\n\n const hoverPerm = useMemo(() => {\n if (!hoveredElement) return null\n return perms.get(hoveredElement) ?? null\n }, [hoveredElement, perms])\n\n if (isConjugation && computation.n !== group.order) return null\n\n interface PairRec { x: number; y: number; gi: number }\n const pairMap = new Map<string, PairRec[]>()\n const edgeList: { key: string; rec: PairRec }[] = []\n for (let gi = 0; gi < group.generators.length; gi++) {\n const gen = group.generators[gi]\n const genEl = gen.apply(group.identity)\n const p = perms.get(genEl.id)\n if (!p) continue\n for (let x = 0; x < n; x++) {\n const y = p[x]\n if (y === x) continue\n const a = Math.min(x, y)\n const b = Math.max(x, y)\n const key = `${a}|${b}`\n const rec: PairRec = { x, y, gi }\n const arr = pairMap.get(key)\n if (arr) arr.push(rec)\n else pairMap.set(key, [rec])\n edgeList.push({ key, rec })\n }\n }\n\n const genEdges: React.ReactNode[] = []\n for (const { key, rec } of edgeList) {\n const { x, y, gi } = rec\n const gen = group.generators[gi]\n const arr = pairMap.get(key)!\n const slot = arr.indexOf(rec)\n const total = arr.length\n const from = nodePos(x)\n const to = nodePos(y)\n const edgeLen = Math.sqrt((to.x - from.x) ** 2 + (to.y - from.y) ** 2) || 1\n const step = Math.max(10, Math.min(16, edgeLen * 0.06))\n const offset = (slot - (total - 1) / 2) * step\n const c = centers[orbitOf[x]]\n const ref = nodePos(arr[0].x)\n const angA = Math.atan2(ref.y - c.y, ref.x - c.x)\n const tFrom = { x: -Math.sin(angA), y: Math.cos(angA) }\n const isLegendTarget = legendHover !== null && legendHover === gen.symbol\n const dimmed = hoverActive || (legendHover !== null && !isLegendTarget)\n genEdges.push(\n <DirectedEdge\n key={`genedge-${gi}-${x}`}\n sx={from.x}\n sy={from.y}\n ex={to.x}\n ey={to.y}\n color={dimmed ? 'var(--node-stroke)' : (gen.color || 'var(--node-stroke)')}\n width={dimmed ? 1.2 : (isLegendTarget ? 3.4 : 3)}\n headSize={18}\n nodeR={NODE_R}\n offset={offset}\n tFrom={tFrom}\n dashed={dimmed}\n opacity={dimmed ? 0.18 : 0.95}\n />\n )\n }\n\n const hoverEdges: React.ReactNode[] = []\n if (hoverPerm) {\n for (let x = 0; x < n; x++) {\n const y = hoverPerm[x]\n if (y === x) {\n const p = nodePos(x)\n hoverEdges.push(\n <circle key={`loop-${x}`} cx={p.x} cy={p.y - NODE_R - 6} r={5} fill=\"none\" stroke={HOVER_COLOR} strokeWidth={1.5} />\n )\n continue\n }\n const from = nodePos(x)\n const to = nodePos(y)\n hoverEdges.push(\n <DirectedEdge\n key={`h-${x}`}\n sx={from.x}\n sy={from.y}\n ex={to.x}\n ey={to.y}\n color={HOVER_COLOR}\n width={3}\n headSize={18}\n nodeR={NODE_R}\n opacity={0.95}\n dir={x < y ? 1 : -1}\n />\n )\n }\n }\n\n const selectedOrbit = selectedElement !== null ? orbitOf[selectedElement] : -1\n\n const chips: React.ReactNode[] = []\n orbits.forEach((o, g) => {\n const xStart = (vw - grpW[g]) / 2\n const gy = vOffset + 12 + lineTop[g]\n const groupChips = o.elements.map((x, ci) => {\n const row = Math.floor(ci / CHIP_PER_ROW)\n const col = ci % CHIP_PER_ROW\n const el = showsElements ? group.elements[x] : null\n const label = el\n ? renderTex(texify(el.label))\n : computation.setLabels?.[x]\n ? renderTex(texify(computation.setLabels[x]))\n : String(x + 1)\n return (\n <g key={el ? el.id : `s-${x}`} transform={`translate(${GRP_PAD + col * (CHIP_W + CHIP_GAP)}, ${GRP_HDR + GRP_PAD + row * CHIP_ROW_H})`}>\n <ElementChip\n label={label}\n isSelected={el ? hoveredElement === el.id : selectedElement === x}\n onClick={el ? () => onSetElementSelect?.(el.id) : () => {\n const next = selectedElement === x ? null : x\n onHoverElementChange?.(null)\n onSelectedElementChange?.(next)\n }}\n onHover={el ? (on) => onHoverElementChange?.(on ? el.id : null) : undefined}\n />\n </g>\n )\n })\n chips.push(\n <g key={`grp-${g}`} transform={`translate(${xStart}, ${gy})`}>\n <rect\n width={grpW[g]}\n height={grpH[g]}\n rx={8}\n fill=\"var(--node-fill)\"\n fillOpacity={0.15}\n stroke=\"var(--node-stroke)\"\n strokeOpacity={0.25}\n strokeDasharray=\"3 3\"\n />\n <text x={GRP_PAD + 2} y={GRP_HDR - 4} fill=\"var(--text-secondary)\" fontSize={13}>\n {t('action.orbitGroup', { size: String(o.elements.length) })}\n </text>\n {groupChips}\n </g>\n )\n })\n\n return (\n <>\n {legend}\n {showLabels && chips}\n {centers.map((c, oi) => (\n <circle\n key={`glow-${oi}`}\n cx={c.x}\n cy={c.y}\n r={c.r + NODE_R + 14}\n fill=\"none\"\n stroke={selectedOrbit === oi ? HOVER_COLOR : 'var(--node-stroke)'}\n strokeWidth={selectedOrbit === oi ? 3 : 1}\n strokeOpacity={selectedOrbit === oi ? 0.9 : 0.25}\n strokeDasharray={selectedOrbit === oi ? undefined : '4 6'}\n />\n ))}\n {genEdges}\n {hoverEdges}\n {Array.from({ length: n }, (_, x) => {\n const p = nodePos(x)\n const el = showsElements ? group.elements[x] : null\n // 窗口模式(onHover 传入):节点悬停触发就地气泡 + 金色箭头联动;\n // 主画布壳不传 onHover → 不挂 hover,保持原行为零变化\n const canHover = !!el && !!onHover\n return (\n <ClusterNode\n key={x}\n x={p.x}\n y={p.y}\n label={showLabels && showsElements ? renderTex(texify(group.elements[x].label)) : showLabels && computation.setLabels?.[x] ? renderTex(texify(computation.setLabels[x])) : ''}\n showNumber={showsElements ? undefined : (computation.setLabels ? undefined : x + 1)}\n isSelected={selectedElement === x}\n isFixed={fixed.has(x)}\n testId={`action-node-${x}`}\n onClick={() => onSelectedElementChange?.(selectedElement === x ? null : x)}\n onHoverIn={canHover ? () => {\n onHoverElementChange?.(el!.id)\n onHover?.(el, anchorOf(p))\n } : undefined}\n onHoverOut={canHover ? () => {\n onHoverElementChange?.(null)\n onHover?.(null, null)\n } : undefined}\n />\n )\n })}\n </>\n )\n}\n\n// ─── ActionScene:banner + svg 场景 + Stab box 全场景 ──────────────────────\n\nexport interface ActionSceneProps {\n group: Group\n /** 作用来源;窗口范围 conjugation/regular/custom(sylow/coset 仅主画布壳会传) */\n kind: GroupActionKind\n computation: GroupActionComputation | null\n /** custom 编辑模式(渲染 CustomActionEditor,不吃 canvasTransform) */\n editing?: boolean\n /** 编辑模式 |X|(1..20) */\n setSize?: number | null\n /** 编辑模式箭头列表 */\n arrows?: GroupActionArrow[]\n /** 编辑模式错误(画布内红字提示) */\n error?: CustomArrowError | null\n onAddArrow?: (from: number, to: number, generatorId?: string | null) => void\n onBindArrow?: (from: number, to: number, generatorId: string) => void\n onRemoveArrow?: (from: number, generatorId?: string | null, to?: number) => void\n onReplaceGenArrows?: (generatorId: string | null, pairs: [number, number][]) => void\n /** 选中集合元素索引(OST 交互 + 底部 Stab box) */\n selectedElement?: number | null\n onSelectedElementChange?: (x: number | null) => void\n /** 悬停群元素 id(金色箭头联动;主画布壳接 context) */\n hoveredElement?: string | null\n onHoverElementChange?: (id: string | null) => void\n /** chips 群元素点击 → 主画布全局选中;窗口不传 */\n onSetElementSelect?: (id: string) => void\n /** 节点常驻标签 + 顶部轨道 chips 区;缺省 true(主画布观感)。窗口传 false:\n * 节点空圈 + chips 区隐藏 + conjugation/regular 节点悬停就地气泡 */\n showLabels?: boolean\n /** 悬停就地气泡回调(窗口接 handleHover) */\n onHover?: (el: GroupElement | null, anchor?: { x: number; y: number } | null) => void\n /** 内容平移缩放(主画布壳接 canvasTransform,窗口接窗口 ct);编辑模式不吃 */\n canvasTransform?: CanvasTransform\n /** 视口尺寸;fitVB 自适应时作为兜底 */\n viewBoxSize?: { width: number; height: number }\n /** sylow 作用的素数(banner 标题用);窗口不传 */\n prime?: number | null\n /** 视图主题作用域(`'dark' | 'light'`)。缺省不注入、跟随外层主题;显式传值时在本子树内\n * 应用 `theme.css` 对应变量块(需宿主已 `import '@groupviz/react/theme.css'`) */\n theme?: SceneTheme\n}\n\nexport function ActionScene(props: ActionSceneProps) {\n return (\n <SceneThemeRoot theme={props.theme}>\n <ActionSceneBody {...props} />\n </SceneThemeRoot>\n )\n}\n\nconst DEFAULT_TRANSFORM: CanvasTransform = { x: 0, y: 0, scale: 1 }\nconst DEFAULT_VB = { width: 2000, height: 2000 }\n\nfunction ActionSceneBody({\n group,\n kind,\n computation,\n editing = false,\n setSize = null,\n arrows = [],\n error = null,\n onAddArrow,\n onBindArrow,\n onRemoveArrow,\n onReplaceGenArrows,\n selectedElement = null,\n onSelectedElementChange,\n hoveredElement = null,\n onHoverElementChange,\n onSetElementSelect,\n showLabels = true,\n onHover,\n canvasTransform = DEFAULT_TRANSFORM,\n viewBoxSize = DEFAULT_VB,\n prime = null,\n}: ActionSceneProps) {\n const { t } = useTranslation()\n const [legendHover, setLegendHover] = useState<string | null>(null)\n\n const isConjugation = kind === 'conjugation'\n const showsElements = isConjugation || kind === 'regular'\n const hoverEl = hoveredElement ? group.elements.find(e => e.id === hoveredElement) ?? null : null\n const showBanner = !!computation && !editing\n // 窗口模式(onHover 传入)banner 收敛为一行核心公式,隐藏第二行动态说明:\n // kind 名已在窗口标题栏,轨道/弧线含义由视图自明(custom 无公式 → 整条 banner 隐藏)。\n // 主画布壳不传 onHover → 保留原两行完整说明,零行为变化。\n const isWindow = !!onHover\n const titleLine = isWindow\n ? isConjugation ? 'g·x = g·x·g⁻¹'\n : kind === 'regular' ? 'g·x = g·x'\n : ''\n : isConjugation\n ? t('action.viewTitle.conjugation')\n : kind === 'sylow'\n ? t('action.viewTitle.sylow', { p: prime ?? '' })\n : kind === 'regular'\n ? t('action.viewTitle.regular')\n : kind === 'coset'\n ? t('action.viewTitle.coset')\n : t('action.viewTitle.custom')\n const edgeLine = hoverEl\n ? t('action.hoverElEdges', { el: hoverEl.label })\n : legendHover\n ? t('action.hoverGenEdges', { gen: legendHover })\n : selectedElement !== null\n ? t('action.selHint')\n : t('action.edgeBlurb')\n const edgeColor = hoverEl || legendHover ? HOVER_COLOR : 'var(--text-secondary)'\n\n const fitVB = computation && !editing ? computeFitVB(computation, showLabels) : null\n const editRingR = Math.max(220, (setSize ?? 1) * 22)\n const editVH = Math.max(900, 2 * editRingR + 520)\n const vb = editing ? { width: 1200, height: editVH } : fitVB ?? viewBoxSize\n\n const stabElements = computation && selectedElement !== null\n ? (computation.stabilizers.get(selectedElement) ?? [])\n .map(id => group.elements.find(e => e.id === id))\n .filter((el): el is NonNullable<typeof el> => !!el)\n : []\n const selLabel = computation && selectedElement !== null\n ? (showsElements\n ? renderTex(texify(group.elements[selectedElement]?.label ?? ''))\n : computation.setLabels?.[selectedElement]\n ? renderTex(texify(computation.setLabels[selectedElement]))\n : String(selectedElement + 1))\n : ''\n const showStabBox = !!computation && !editing && selectedElement !== null && stabElements.length > 0\n\n return (\n <>\n {showBanner && titleLine !== '' && (\n <div\n style={{\n position: 'absolute',\n top: 8,\n left: '50%',\n transform: 'translateX(-50%)',\n zIndex: 5,\n maxWidth: '92%',\n background: 'var(--panel-bg)',\n opacity: 0.94,\n padding: isWindow ? '4px 12px' : '6px 14px',\n borderRadius: 8,\n border: '1px solid var(--border-color, rgba(128,128,128,0.35))',\n textAlign: 'center',\n pointerEvents: 'none',\n }}\n >\n <div style={{ fontSize: isWindow ? 12 : 13, fontWeight: 600, color: 'var(--text-primary)' }}>{titleLine}</div>\n {!isWindow && <div style={{ fontSize: 12, color: edgeColor, marginTop: 2 }}>{edgeLine}</div>}\n </div>\n )}\n <svg viewBox={`0 0 ${vb.width} ${vb.height}`} className=\"view-svg\" style={{ userSelect: 'none' }}>\n <defs>\n <filter id=\"node-shadow\" x=\"-30%\" y=\"-30%\" width=\"160%\" height=\"160%\">\n <feDropShadow dx=\"0\" dy=\"2\" stdDeviation=\"3\" floodColor=\"#000000\" floodOpacity=\"0.25\" />\n </filter>\n </defs>\n <g transform={editing ? undefined : `translate(${canvasTransform.x}, ${canvasTransform.y}) scale(${canvasTransform.scale})`}>\n {editing ? (\n <CustomActionEditor\n group={group}\n vw={1200}\n vh={editVH}\n setSize={setSize ?? 1}\n arrows={arrows}\n error={error}\n onAddArrow={onAddArrow ?? (() => {})}\n onBindArrow={onBindArrow ?? (() => {})}\n onRemoveArrow={onRemoveArrow ?? (() => {})}\n onReplaceGenArrows={onReplaceGenArrows ?? (() => {})}\n />\n ) : computation ? (\n <DisplayMode\n group={group}\n computation={computation}\n kind={kind}\n selectedElement={selectedElement}\n onSelectedElementChange={onSelectedElementChange}\n hoveredElement={hoveredElement}\n onHoverElementChange={onHoverElementChange}\n onSetElementSelect={onSetElementSelect}\n showLabels={showLabels}\n onHover={onHover}\n legendHover={legendHover}\n onLegendHover={setLegendHover}\n viewBoxOverride={fitVB ?? undefined}\n canvasTransform={canvasTransform}\n viewBoxSize={viewBoxSize}\n />\n ) : (\n <text x={viewBoxSize.width / 2} y={viewBoxSize.height / 2} textAnchor=\"middle\" fill=\"var(--text-secondary)\" fontSize={22}>\n {t('action.noAction')}\n </text>\n )}\n </g>\n </svg>\n {showStabBox && (\n <div\n style={{\n position: 'absolute',\n bottom: 8,\n left: '50%',\n transform: 'translateX(-50%)',\n zIndex: 5,\n maxWidth: '92%',\n background: 'var(--panel-bg)',\n opacity: 0.96,\n padding: '8px 14px',\n borderRadius: 8,\n border: '1px solid var(--border-color, rgba(128,128,128,0.35))',\n boxShadow: '0 4px 14px rgba(0,0,0,0.25)',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>\n <span style={{ fontSize: 13, fontWeight: 700, color: 'var(--text-primary)' }}>\n <span dangerouslySetInnerHTML={{ __html: t('action.stabilizerFor', { el: selLabel }) }} /> <span style={{ color: 'var(--text-secondary)', fontWeight: 400 }}>|G_x| = {stabElements.length}</span>\n </span>\n <button\n onClick={() => onSelectedElementChange?.(null)}\n style={{\n marginLeft: 'auto', border: 'none', background: 'none', cursor: 'pointer',\n color: 'var(--text-secondary)', fontSize: 14, lineHeight: 1, padding: '2px 4px',\n }}\n title={t('action.closeStab')}\n >×</button>\n </div>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginTop: 6, maxHeight: 160, overflowY: 'auto' }}>\n {stabElements.map(el => (\n <span\n key={el.id}\n style={{\n padding: '2px 8px', borderRadius: 10, fontSize: 12,\n background: 'var(--bg-interactive)', border: '1px solid var(--border-primary)',\n color: 'var(--text-primary)', whiteSpace: 'nowrap',\n }}\n dangerouslySetInnerHTML={{ __html: renderTex(texify(el.label)) }}\n />\n ))}\n </div>\n </div>\n )}\n </>\n )\n}\n","import { useMemo, useState, useCallback, useRef, type ReactNode } from 'react'\nimport { SceneThemeRoot, type SceneTheme } from './SceneThemeRoot'\nimport { useTranslation } from '../../i18n/useTranslation'\nimport { renderTex, texify } from '../../utils/texify'\nimport { verifyHomomorphism, getHomomorphismProperties } from '../../core/algebra/homomorphisms'\nimport { computeCayleyActionEdges } from '../../core/algebra/cayleyEdges'\nimport { cayleyCircleLayout } from '../../core/algebra/forceLayout'\nimport { COLOR_PALETTE } from '../../core/types'\nimport type { Group, GroupElement, HomomorphismResult } from '../../core/types'\n\nconst HOMO_COLORS = [\n '#4ecdc4', '#a78bfa', '#ffd93d', '#f97316',\n '#38bdf8', '#84cc16', '#f43f5e', '#eab308',\n '#6366f1', '#ec4899', '#14b8a6', '#0ea5e9',\n '#22c55e', '#a855f7', '#06b6d4',\n]\n\nconst KERNEL_RED = '#ff6b6b'\nconst IMAGE_CYAN = '#4ecdc4'\n\nfunction bezierPath(x1: number, y1: number, x2: number, y2: number): string {\n const dx = Math.abs(x2 - x1) * 0.3\n return `M ${x1} ${y1} C ${x1 + dx} ${y1}, ${x2 - dx} ${y2}, ${x2} ${y2}`\n}\n\nfunction findGeneratorElements(group: { elements: GroupElement[]; generators: { name: string; symbol: string; apply: (el: GroupElement) => GroupElement }[]; identity: GroupElement }): GroupElement[] {\n const result: GroupElement[] = []\n for (const gen of group.generators) {\n let el = group.elements.find(e => e.label === gen.symbol || e.label === gen.name)\n if (!el) {\n const image = gen.apply(group.identity)\n el = group.elements.find(e => e.id === image.id)\n }\n if (el) result.push(el)\n }\n return result\n}\n\n// ─── Homomorphism props-化内核 ──────────────────────────────────────────\n// 受控 ViewWindow (FGVE) 与主画布(经 context 壳 HomomorphismView)共用。\n// source/target/mapping 之外全部可选:主画布壳由全局 Provider 组装\n// (含 theoremMode 定理动画注入);窗口引擎自包含时只传双群 + mapping。\n\nexport interface HomomorphismSceneProps {\n source: Group | null\n target: Group | null\n mapping: Map<string, string>\n /** 预计算结果(null=源/目标缺失或 mapping 为空)。缺省(undefined)由 Scene 内部 verifyHomomorphism 推导 */\n result?: HomomorphismResult | null\n /** 映射显示名(TeX 或纯文本);缺省 `${source.symbol} → ${target.symbol}` */\n name?: string\n /** 定理模式(第一同构定理动画);缺省 false。动画内容由 theoremAnimation 注入 */\n theoremMode?: boolean\n onTheoremModeChange?: (v: boolean) => void\n /** 定理动画内容(主画布壳注入 <FirstIsomorphismAnimation>);窗口不传 */\n theoremAnimation?: ReactNode\n /** 节点常驻标签;缺省 true(主画布行为);嵌入窗口默认关,读元素靠悬停就地气泡 */\n showLabels?: boolean\n /** 悬停节点(源/目标元素 + 视口内屏幕锚点);主画布壳不传(内部高亮即可),窗口接就地气泡 */\n onHover?: (el: GroupElement | null, anchor?: { x: number; y: number } | null) => void\n /** 视图主题作用域(`'dark' | 'light'`)。缺省不注入、跟随外层主题;显式传值时在本子树内\n * 应用 `theme.css` 对应变量块(需宿主已 `import '@groupviz/react/theme.css'`) */\n theme?: SceneTheme\n}\n\nexport function HomomorphismScene(props: HomomorphismSceneProps) {\n return (\n <SceneThemeRoot theme={props.theme}>\n <HomomorphismSceneBody {...props} />\n </SceneThemeRoot>\n )\n}\n\nfunction HomomorphismSceneBody({\n source,\n target,\n mapping,\n result,\n name,\n theoremMode = false,\n onTheoremModeChange,\n theoremAnimation,\n showLabels = true,\n onHover,\n}: HomomorphismSceneProps) {\n const { t } = useTranslation()\n const svgRef = useRef<SVGSVGElement>(null)\n\n const [hoverSource, setHoverSource] = useState<string | null>(null)\n const [hoverTarget, setHoverTarget] = useState<string | null>(null)\n const [pinnedSource, setPinnedSource] = useState<string | null>(null)\n\n const resolvedResult = useMemo(() => {\n if (result !== undefined) return result\n if (!source || !target || mapping.size === 0) return null\n return verifyHomomorphism(source, target, mapping)\n }, [source, target, mapping, result])\n\n const kernelIds = resolvedResult?.kernel || []\n const imageIds = resolvedResult?.image || []\n\n const properties = resolvedResult?.isHomomorphism\n ? getHomomorphismProperties(source!, target!, resolvedResult)\n : null\n\n const kernelSet = new Set(kernelIds)\n const imageSet = new Set(imageIds)\n\n const highlightedSource = pinnedSource || hoverSource\n const highlightedTargetId = highlightedSource ? mapping.get(highlightedSource) : hoverTarget\n\n const highlightPreimageIds = useMemo(() => {\n if (!highlightedTargetId || highlightedSource) return new Set<string>()\n const preimages = new Set<string>()\n mapping.forEach((tgt, src) => {\n if (tgt === highlightedTargetId) preimages.add(src)\n })\n return preimages\n }, [highlightedTargetId, highlightedSource, mapping])\n\n const handleSourceClick = useCallback((elId: string) => {\n setPinnedSource(prev => prev === elId ? null : elId)\n }, [])\n\n const gCayleyEdges = useMemo(() => {\n if (!source) return []\n const genEls = findGeneratorElements(source)\n if (genEls.length === 0) return []\n const actions = genEls.map((el, i) => ({\n elementId: el.id,\n enabled: true,\n color: COLOR_PALETTE[i % COLOR_PALETTE.length],\n }))\n return computeCayleyActionEdges(source, actions, 'right')\n }, [source])\n\n const hCayleyEdges = useMemo(() => {\n if (!target) return []\n const genEls = findGeneratorElements(target)\n if (genEls.length === 0) return []\n const actions = genEls.map((el, i) => ({\n elementId: el.id,\n enabled: true,\n color: COLOR_PALETTE[i % COLOR_PALETTE.length],\n }))\n return computeCayleyActionEdges(target, actions, 'right')\n }, [target])\n\n if (!source || !target) {\n return (\n <svg viewBox=\"0 0 800 500\" style={{ width: '100%', height: '100%' }}>\n <text x=\"400\" y=\"250\" textAnchor=\"middle\" fill=\"var(--text-muted)\" fontSize=\"16\">\n {t('homo.selectSourceFirst')}\n </text>\n </svg>\n )\n }\n\n if (theoremMode) {\n return (\n <div style={{ display: 'flex', flexDirection: 'column', width: '100%', height: '100%' }}>\n <div style={{ display: 'flex', justifyContent: 'flex-start', padding: '4px 8px' }}>\n <button className=\"panel-btn\"\n onClick={() => onTheoremModeChange?.(false)}\n style={{ fontSize: '10px', padding: '3px 8px' }}>\n ← {t('homo.title')}\n </button>\n </div>\n <div style={{ flex: 1 }}>\n {theoremAnimation}\n </div>\n </div>\n )\n }\n\n const vw = 800\n const vh = 500\n const leftCx = 170\n const rightCx = 630\n const midY = vh * 0.48\n\n const srcR = Math.min(140, Math.max(65, source.order * 4.5))\n const tgtR = Math.min(140, Math.max(65, target.order * 4.5))\n const sourcePositions = cayleyCircleLayout(source, leftCx, midY, srcR)\n const targetPositions = cayleyCircleLayout(target, rightCx, midY, tgtR)\n\n function renderEdge(\n posMap: Map<string, { x: number; y: number }>,\n fromId: string, toId: string, color: string, key: string,\n width = 1.5, opacity = 0.5, selfLoop = false, _isBidirectional = false,\n pairOffset = 0,\n ) {\n const from = posMap.get(fromId)\n const to = posMap.get(toId)\n if (!from || !to) return null\n if (selfLoop) return null\n const dx = to.x - from.x; const dy = to.y - from.y\n const dist = Math.sqrt(dx * dx + dy * dy)\n if (dist < 0.5) return null\n if (pairOffset === 0) {\n return (\n <line key={key} x1={from.x} y1={from.y} x2={to.x} y2={to.y}\n stroke={color} strokeWidth={width} opacity={opacity} />\n )\n }\n const len = dist || 1\n const nx = -dy / len; const ny = dx / len\n const mx = (from.x + to.x) / 2 + nx * pairOffset\n const my = (from.y + to.y) / 2 + ny * pairOffset\n return (\n <path key={key} d={`M ${from.x} ${from.y} Q ${mx} ${my} ${to.x} ${to.y}`}\n stroke={color} strokeWidth={width} fill=\"none\" opacity={opacity} />\n )\n }\n\n function buildPairOffsets(edges: { fromId: string; toId: string }[]) {\n const pairMap = new Map<string, number[]>()\n edges.forEach((e, i) => {\n const pair = [e.fromId, e.toId].sort()\n const key = `${pair[0]}|${pair[1]}`\n const arr = pairMap.get(key)\n if (arr) arr.push(i)\n else pairMap.set(key, [i])\n })\n const offsets = new Array<number>(edges.length).fill(0)\n pairMap.forEach((indices) => {\n if (indices.length < 2) return\n const total = indices.length\n indices.forEach((idx, slot) => {\n offsets[idx] = (slot - (total - 1) / 2) * 14\n })\n })\n return offsets\n }\n\n const mappingLines: {\n srcId: string\n tgtId: string\n color: string\n pathD: string\n isKernel: boolean\n isHighlighted: boolean\n }[] = []\n\n mapping.forEach((targetId, sourceId) => {\n const from = sourcePositions.get(sourceId)\n const to = targetPositions.get(targetId)\n if (!from || !to) return\n\n const isKernel = kernelSet.has(sourceId)\n const tgtIdx = target.elements.findIndex(e => e.id === targetId)\n const baseColor = isKernel ? KERNEL_RED : HOMO_COLORS[tgtIdx >= 0 ? tgtIdx % HOMO_COLORS.length : 0]\n\n const isHL = highlightedSource === sourceId || highlightedTargetId === targetId\n\n mappingLines.push({\n srcId: sourceId,\n tgtId: targetId,\n color: baseColor,\n pathD: bezierPath(from.x, from.y, to.x, to.y),\n isKernel,\n isHighlighted: !!isHL,\n })\n })\n\n return (\n <svg ref={svgRef} viewBox={`0 0 ${vw} ${vh}`} style={{ width: '100%', height: '100%' }}>\n {/* Background separator line */}\n <line x1={vw / 2} y1={40} x2={vw / 2} y2={vh - 10}\n stroke=\"var(--border-color)\" strokeWidth={0.5} strokeDasharray=\"4,6\" opacity={0.5} />\n\n {/* Title */}\n <foreignObject x={vw / 2 - 140} y={4} width={280} height={28}>\n <div style={{ fontSize: '16px', fontWeight: 'bold', textAlign: 'center', color: 'var(--text-primary)', lineHeight: '28px' }}\n dangerouslySetInnerHTML={{ __html: renderTex(texify(name || `${source.symbol} → ${target.symbol}`)) }} />\n </foreignObject>\n\n {/* Domain Label */}\n <foreignObject x={leftCx - 70} y={34} width={140} height={22}>\n <div style={{ fontSize: '12px', fontWeight: 'bold', textAlign: 'center', color: 'var(--text-primary)', lineHeight: '22px' }}\n dangerouslySetInnerHTML={{ __html: `${renderTex(texify(source.symbol))} <span style=\"color:var(--text-muted);font-weight:400\">(|G|=${source.order})</span>` }} />\n </foreignObject>\n {/* Codomain Label */}\n <foreignObject x={rightCx - 70} y={34} width={140} height={22}>\n <div style={{ fontSize: '12px', fontWeight: 'bold', textAlign: 'center', color: 'var(--text-primary)', lineHeight: '22px' }}\n dangerouslySetInnerHTML={{ __html: `${renderTex(texify(target.symbol))} <span style=\"color:var(--text-muted);font-weight:400\">(|H|=${target.order})</span>` }} />\n </foreignObject>\n\n {/* ═══ G Cayley edges ═══ */}\n {(() => {\n const gOffsets = buildPairOffsets(gCayleyEdges)\n return gCayleyEdges.map((e, i) =>\n renderEdge(\n sourcePositions, e.fromId, e.toId, e.color, `gce-${i}`,\n 1.8, 0.7, e.isSelfLoop, e.isBidirectional, gOffsets[i],\n )\n )\n })()}\n\n {/* ═══ H Cayley edges ═══ */}\n {(() => {\n const hOffsets = buildPairOffsets(hCayleyEdges)\n return hCayleyEdges.map((e, i) =>\n renderEdge(\n targetPositions, e.fromId, e.toId, e.color, `hce-${i}`,\n 1.4, 0.65, e.isSelfLoop, e.isBidirectional, hOffsets[i],\n )\n )\n })()}\n\n {/* Mapping Lines — layered: non-highlighted first, highlighted on top */}\n {mappingLines.filter(l => !l.isHighlighted).map((line, i) => (\n <path\n key={`nl-${i}`}\n d={line.pathD}\n stroke={line.color}\n strokeWidth={line.isKernel ? 2.0 : 1.0}\n strokeOpacity={line.isKernel ? 0.45 : 0.28}\n fill=\"none\"\n />\n ))}\n {mappingLines.filter(l => l.isHighlighted).map((line, i) => (\n <path\n key={`hl-${i}`}\n d={line.pathD}\n stroke={line.color}\n strokeWidth={2.5}\n strokeOpacity={0.85}\n fill=\"none\"\n style={{ filter: 'drop-shadow(0 0 4px currentColor)' }}\n />\n ))}\n\n {/* Source Nodes */}\n {source.elements.map((el) => {\n const pos = sourcePositions.get(el.id)\n if (!pos) return null\n const inKernel = kernelSet.has(el.id)\n const isMapped = mapping.has(el.id)\n const isHL = highlightedSource === el.id || highlightPreimageIds.has(el.id)\n const isPinned = pinnedSource === el.id\n const dimmed = highlightedSource && !isHL\n\n let fill = 'var(--node-fill)'\n if (inKernel) fill = KERNEL_RED\n else if (isMapped) {\n const mTgt = mapping.get(el.id)!\n const tgtIdx = target.elements.findIndex(e => e.id === mTgt)\n if (tgtIdx >= 0) fill = HOMO_COLORS[tgtIdx % HOMO_COLORS.length]\n }\n\n return (\n <g key={`s-${el.id}`} data-homo-source-node\n onMouseEnter={(e) => {\n setHoverSource(el.id)\n const rect = svgRef.current?.getBoundingClientRect()\n if (rect && onHover) onHover(el, { x: e.clientX - rect.left, y: e.clientY - rect.top })\n }}\n onMouseLeave={() => { setHoverSource(null); onHover?.(null, null) }}\n onClick={() => handleSourceClick(el.id)}\n style={{ cursor: 'pointer' }}\n >\n {isHL && (\n <circle cx={pos.x} cy={pos.y} r={18}\n fill=\"none\" stroke={inKernel ? KERNEL_RED : 'var(--accent-teal)'}\n strokeWidth={2} opacity={0.6}\n style={{ filter: 'drop-shadow(0 0 6px currentColor)' }} />\n )}\n <circle\n cx={pos.x} cy={pos.y} r={isMapped ? 13 : 8}\n fill={fill}\n stroke={inKernel ? KERNEL_RED : isMapped ? 'var(--border-color)' : 'var(--border-color)'}\n strokeWidth={inKernel ? 2 : 1}\n opacity={dimmed ? 0.3 : 1}\n />\n {isPinned && (\n <circle cx={pos.x} cy={pos.y} r={15}\n fill=\"none\" stroke=\"var(--accent-teal)\" strokeWidth={2}\n opacity={0.8} />\n )}\n {showLabels && (\n <foreignObject\n x={pos.x - 24} y={pos.y + 6}\n width={48} height={18}\n style={{ overflow: 'visible' }}\n >\n <div style={{\n fontSize: '8px',\n textAlign: 'center',\n color: inKernel ? KERNEL_RED : dimmed ? 'var(--text-muted)' : 'var(--text-primary)',\n fontWeight: inKernel || isHL ? 700 : 400,\n pointerEvents: 'none',\n }} dangerouslySetInnerHTML={{ __html: renderTex(el.label) }} />\n </foreignObject>\n )}\n </g>\n )\n })}\n\n {/* Target Nodes */}\n {target.elements.map((el) => {\n const pos = targetPositions.get(el.id)\n if (!pos) return null\n const inImage = imageSet.has(el.id)\n const isHL = highlightedTargetId === el.id\n const dimmed = highlightedTargetId && !isHL\n\n return (\n <g key={`t-${el.id}`} data-homo-target-node\n onMouseEnter={(e) => {\n setHoverTarget(el.id)\n const rect = svgRef.current?.getBoundingClientRect()\n if (rect && onHover) onHover(el, { x: e.clientX - rect.left, y: e.clientY - rect.top })\n }}\n onMouseLeave={() => { setHoverTarget(null); onHover?.(null, null) }}\n style={{ cursor: 'pointer' }}\n >\n {isHL && (\n <circle cx={pos.x} cy={pos.y} r={18}\n fill=\"none\" stroke={IMAGE_CYAN}\n strokeWidth={2} opacity={0.6}\n style={{ filter: 'drop-shadow(0 0 8px currentColor)' }} />\n )}\n <circle\n cx={pos.x} cy={pos.y} r={inImage ? 13 : 8}\n fill={inImage ? IMAGE_CYAN : 'var(--node-fill)'}\n stroke={inImage ? IMAGE_CYAN : 'var(--border-color)'}\n strokeWidth={inImage ? 2 : 1}\n opacity={dimmed ? 0.3 : 1}\n />\n {highlightPreimageIds.size > 0 && isHL && (\n <text x={pos.x} y={pos.y - 18} textAnchor=\"middle\" fill=\"var(--text-muted)\" fontSize=\"9\">\n ← {highlightPreimageIds.size}\n </text>\n )}\n {showLabels && (\n <foreignObject\n x={pos.x - 24} y={pos.y + 6}\n width={48} height={18}\n style={{ overflow: 'visible' }}\n >\n <div style={{\n fontSize: '8px',\n textAlign: 'center',\n color: inImage ? IMAGE_CYAN : dimmed ? 'var(--text-muted)' : 'var(--text-primary)',\n fontWeight: inImage || isHL ? 700 : 400,\n pointerEvents: 'none',\n }} dangerouslySetInnerHTML={{ __html: renderTex(el.label) }} />\n </foreignObject>\n )}\n </g>\n )\n })}\n\n {/* Legend / status line at bottom */}\n <g transform={`translate(0, ${vh - 16})`}>\n {resolvedResult?.isHomomorphism && properties && (\n <>\n <rect x={leftCx - 50} y={-12} width={100} height={16} rx={3}\n fill={properties.isInjective ? 'rgba(78,205,196,0.15)' : 'rgba(255,107,107,0.1)'} />\n <text x={leftCx} y={0} textAnchor=\"middle\" fontSize=\"9\"\n fill={properties.isInjective ? 'var(--accent-teal)' : KERNEL_RED}>\n {properties.isInjective ? t('homo.injective') : t('homo.notInjective')}\n </text>\n\n <rect x={vw / 2 - 60} y={-12} width={120} height={16} rx={3}\n fill=\"rgba(78,205,196,0.08)\" />\n <text x={vw / 2} y={0} textAnchor=\"middle\" fontSize=\"9\" fill=\"var(--text-muted)\">\n Ker={kernelSet.size}{' '}|{' '}Im={imageSet.size}{' '}|{' '}G/Ker={source.order}/{kernelSet.size}={source.order / (kernelSet.size || 1)}\n </text>\n\n <rect x={rightCx - 50} y={-12} width={100} height={16} rx={3}\n fill={properties.isSurjective ? 'rgba(78,205,196,0.15)' : 'rgba(255,107,107,0.1)'} />\n <text x={rightCx} y={0} textAnchor=\"middle\" fontSize=\"9\"\n fill={properties.isSurjective ? 'var(--accent-teal)' : KERNEL_RED}>\n {properties.isSurjective ? t('homo.surjective') : t('homo.notSurjective')}\n </text>\n\n {properties.isIsomorphism && (\n <>\n <rect x={vw / 2 - 40} y={-26} width={80} height={14} rx={3}\n fill=\"rgba(78,205,196,0.2)\" stroke=\"var(--accent-teal)\" strokeWidth={0.5} />\n <text x={vw / 2} y={-15} textAnchor=\"middle\" fontSize=\"10\" fontWeight=\"bold\" fill=\"var(--accent-teal)\">\n {t('homo.isomorphism')}\n </text>\n </>\n )}\n </>\n )}\n {resolvedResult && !resolvedResult.isHomomorphism && (\n <text x={vw / 2} y={0} textAnchor=\"middle\" fontSize=\"10\" fill={KERNEL_RED} fontWeight=\"bold\">\n ✗ {t('homo.invalid')}\n </text>\n )}\n {/* Interactive hint */}\n <text x={vw - 10} y={0} textAnchor=\"end\" fontSize=\"8\" fill=\"var(--text-muted)\" opacity={0.6}>\n {t('homo.interactiveHint')}\n </text>\n </g>\n </svg>\n )\n}\n","import { useMemo, useState, useRef, useEffect } from 'react'\r\nimport { Canvas, useFrame } from '@react-three/fiber'\r\nimport { OrbitControls, Html } from '@react-three/drei'\r\nimport * as THREE from 'three'\r\nimport { useTranslation } from '../../i18n/useTranslation'\r\nimport { texify, renderTex } from '../../utils/texify'\r\nimport { resolveElementWarn } from '../../utils/elementRef'\r\nimport type { SceneTheme } from './SceneThemeRoot'\r\nimport { computeElementRotation } from '../../core/elementRotation'\r\nimport type { Group, GroupElement } from '../../core/types'\r\nimport { getSymmetryType } from '../../core/symmetryType'\r\nimport type { SymmetryType } from '../../core/symmetryType'\r\n\r\ninterface SymmetryData {\r\n vertices: THREE.Vector3[]\r\n edges: [number, number][]\r\n directed?: boolean\r\n}\r\n\r\nfunction getCyclicFigure(n: number, radius: number): SymmetryData {\r\n const vertices: THREE.Vector3[] = []\r\n const edges: [number, number][] = []\r\n for (let i = 0; i < n; i++) {\r\n const angle = (2 * Math.PI * i) / n - Math.PI / 2\r\n vertices.push(new THREE.Vector3(Math.cos(angle) * radius, 0, Math.sin(angle) * radius))\r\n edges.push([i, (i + 1) % n])\r\n }\r\n return { vertices, edges, directed: true }\r\n}\r\n\r\nfunction getDihedralFigure(n: number, radius: number): SymmetryData {\r\n const vertices: THREE.Vector3[] = []\r\n const edges: [number, number][] = []\r\n for (let i = 0; i < n; i++) {\r\n const angle = (2 * Math.PI * i) / n - Math.PI / 2\r\n vertices.push(new THREE.Vector3(Math.cos(angle) * radius, 0, Math.sin(angle) * radius))\r\n edges.push([i, (i + 1) % n])\r\n }\r\n return { vertices, edges }\r\n}\r\n\r\nfunction getTetrahedron(radius: number): SymmetryData {\r\n const s = radius / Math.sqrt(3)\r\n const vertices = [\r\n new THREE.Vector3(1, 1, 1).multiplyScalar(s),\r\n new THREE.Vector3(1, -1, -1).multiplyScalar(s),\r\n new THREE.Vector3(-1, 1, -1).multiplyScalar(s),\r\n new THREE.Vector3(-1, -1, 1).multiplyScalar(s),\r\n ]\r\n const edges: [number, number][] = []\r\n for (let i = 0; i < 4; i++) for (let j = i + 1; j < 4; j++) edges.push([i, j])\r\n return { vertices, edges }\r\n}\r\n\r\nfunction getCube(radius: number): SymmetryData {\r\n const s = radius / Math.sqrt(3)\r\n const signs = [-1, 1]\r\n const vertices: THREE.Vector3[] = []\r\n for (const x of signs) for (const y of signs) for (const z of signs)\r\n vertices.push(new THREE.Vector3(x * s, y * s, z * s))\r\n const edges: [number, number][] = []\r\n for (let i = 0; i < 8; i++) {\r\n for (let j = i + 1; j < 8; j++) {\r\n const dx = Math.abs(vertices[i].x - vertices[j].x)\r\n const dy = Math.abs(vertices[i].y - vertices[j].y)\r\n const dz = Math.abs(vertices[i].z - vertices[j].z)\r\n if ([dx, dy, dz].filter(v => v > 0.001).length === 1) edges.push([i, j])\r\n }\r\n }\r\n return { vertices, edges }\r\n}\r\n\r\nfunction getIcosahedron(radius: number): SymmetryData {\r\n const φ = (1 + Math.sqrt(5)) / 2\r\n const raw = [[0,1,φ],[0,-1,φ],[0,1,-φ],[0,-1,-φ],[1,φ,0],[-1,φ,0],[1,-φ,0],[-1,-φ,0],[φ,0,1],[φ,0,-1],[-φ,0,1],[-φ,0,-1]]\r\n const maxCoord = Math.sqrt(1 + φ * φ)\r\n const s = radius / maxCoord\r\n const vertices = raw.map(([x,y,z]) => new THREE.Vector3(x*s,y*s,z*s))\r\n const edges: [number,number][] = []\r\n const targetDistSq = 4 * s * s, tol = 0.01 * targetDistSq\r\n for (let i = 0; i < 12; i++)\r\n for (let j = i + 1; j < 12; j++)\r\n if (Math.abs(vertices[i].distanceToSquared(vertices[j]) - targetDistSq) < tol) edges.push([i, j])\r\n return { vertices, edges }\r\n}\r\n\r\nconst TRIANGULAR_FACE_CACHE = new Map<string, [number, number, number][]>()\r\n\r\nfunction getRectangle(radius: number): SymmetryData {\r\n const hw = radius * 1.0, hh = radius * 0.55\r\n const vertices = [new THREE.Vector3(-hw,0,-hh),new THREE.Vector3(hw,0,-hh),new THREE.Vector3(hw,0,hh),new THREE.Vector3(-hw,0,hh)]\r\n const edges: [number,number][] = [[0,1],[1,2],[2,3],[3,0]]\r\n return { vertices, edges }\r\n}\r\n\r\nfunction getOctahedron(radius: number): SymmetryData {\r\n const vertices = [new THREE.Vector3(radius,0,0),new THREE.Vector3(-radius,0,0),new THREE.Vector3(0,radius,0),new THREE.Vector3(0,-radius,0),new THREE.Vector3(0,0,radius),new THREE.Vector3(0,0,-radius)]\r\n const edges: [number,number][] = []\r\n for (let i = 0; i < 6; i++)\r\n for (let j = i + 1; j < 6; j++)\r\n if (Math.abs(vertices[i].distanceToSquared(vertices[j]) - 4*radius*radius) > 0.01) edges.push([i, j])\r\n return { vertices, edges }\r\n}\r\n\r\nfunction getDodecahedron(radius: number): SymmetryData {\r\n const φ = (1+Math.sqrt(5))/2, a=1, b=1/φ, c=φ\r\n const raw: [number,number,number][] = []\r\n for (const x of [-1,1]) for (const y of [-1,1]) for (const z of [-1,1]) raw.push([x*a,y*a,z*a])\r\n for (const s1 of [-1,1]) for (const s2 of [-1,1]) raw.push([0,s1*c,s2*b])\r\n for (const s1 of [-1,1]) for (const s2 of [-1,1]) raw.push([s2*b,0,s1*c])\r\n for (const s1 of [-1,1]) for (const s2 of [-1,1]) raw.push([s1*c,s2*b,0])\r\n const maxCoord = Math.sqrt(a*a+a*a+a*a), ss = radius/maxCoord\r\n const vertices = raw.map(([x,y,z])=>new THREE.Vector3(x*ss,y*ss,z*ss))\r\n const edgeDist = (2*b)*ss, tol = edgeDist*0.05\r\n const edges: [number,number][] = []\r\n for (let i = 0; i < 20; i++)\r\n for (let j = i + 1; j < 20; j++)\r\n if (Math.abs(vertices[i].distanceTo(vertices[j]) - edgeDist) < tol) edges.push([i, j])\r\n return { vertices, edges }\r\n}\r\n\r\nfunction getVertexColor(index: number, total: number): string {\r\n const hue = (index / total) * 360\r\n return `hsl(${hue}, 70%, 60%)`\r\n}\r\n\r\nfunction computeTriangularFaces(data: SymmetryData): [number, number, number][] {\r\n const key = `${data.vertices.length}:${data.edges.map(e => e.join('-')).join('|')}`\r\n const cached = TRIANGULAR_FACE_CACHE.get(key)\r\n if (cached) return cached\r\n const adj = new Map<number, number[]>()\r\n for (let i = 0; i < data.vertices.length; i++) adj.set(i, [])\r\n for (const [a, b] of data.edges) { adj.get(a)!.push(b); adj.get(b)!.push(a) }\r\n const faceSet = new Set<string>()\r\n const faces: [number, number, number][] = []\r\n for (let vi = 0; vi < data.vertices.length; vi++) {\r\n const neighbors = adj.get(vi)!\r\n if (neighbors.length < 2) continue\r\n const vPos = data.vertices[vi], vDir2 = vPos.clone().normalize()\r\n const refDir = new THREE.Vector3().subVectors(data.vertices[neighbors[0]], vPos).normalize()\r\n const sorted = neighbors.map(ni => ({\r\n ni,\r\n angle: Math.atan2(\r\n new THREE.Vector3().crossVectors(refDir, new THREE.Vector3().subVectors(data.vertices[ni], vPos).normalize()).dot(vDir2),\r\n refDir.dot(new THREE.Vector3().subVectors(data.vertices[ni], vPos).normalize())\r\n )\r\n }))\r\n sorted.sort((a, b) => a.angle - b.angle)\r\n for (let si = 0; si < sorted.length; si++) {\r\n const a = sorted[si].ni, b2 = sorted[(si + 1) % sorted.length].ni\r\n if (adj.get(a)?.includes(b2)) {\r\n const fKey = [vi, a, b2].sort().join(',')\r\n if (!faceSet.has(fKey)) {\r\n faceSet.add(fKey)\r\n faces.push([vi, a, b2])\r\n }\r\n }\r\n }\r\n }\r\n TRIANGULAR_FACE_CACHE.set(key, faces)\r\n return faces\r\n}\r\n\r\nfunction getCubeFaceCenters(data: SymmetryData): THREE.Vector3[] {\r\n const s = data.vertices[0].length() / Math.sqrt(3)\r\n return [\r\n new THREE.Vector3(s, 0, 0), new THREE.Vector3(-s, 0, 0),\r\n new THREE.Vector3(0, s, 0), new THREE.Vector3(0, -s, 0),\r\n new THREE.Vector3(0, 0, s), new THREE.Vector3(0, 0, -s),\r\n ]\r\n}\r\n\r\nfunction computeFaceCenters(data: SymmetryData, triangularFaces: [number, number, number][]): THREE.Vector3[] {\r\n const centers: THREE.Vector3[] = []\r\n if (triangularFaces.length > 0 && data.vertices.length <= 12) {\r\n for (const [vi, vj, vk] of triangularFaces) {\r\n centers.push(data.vertices[vi].clone().add(data.vertices[vj]).add(data.vertices[vk]).multiplyScalar(1 / 3))\r\n }\r\n return centers\r\n }\r\n if (data.vertices.length === 8) {\r\n return getCubeFaceCenters(data)\r\n }\r\n if (data.vertices.length >= 20) {\r\n const adj = new Map<number, Set<number>>()\r\n for (let i = 0; i < data.vertices.length; i++) adj.set(i, new Set())\r\n for (const [a, b] of data.edges) { adj.get(a)!.add(b); adj.get(b)!.add(a) }\r\n const found = new Set<string>()\r\n for (let v0 = 0; v0 < data.vertices.length; v0++) {\r\n const neis = [...adj.get(v0)!]\r\n for (let i = 0; i < neis.length; i++) {\r\n for (let j = i + 1; j < neis.length; j++) {\r\n const v1 = neis[i], v2 = neis[j]\r\n if (!adj.get(v1)!.has(v2)) continue\r\n const seeds = adj.get(v2)!.size === 3\r\n ? [...adj.get(v2)!].filter(x => x !== v0 && x !== v1)\r\n : [v2]\r\n for (const v3 of seeds) {\r\n const finalCands = [...adj.get(v3)!].filter(x => x !== v2 && adj.get(v0)!.has(x))\r\n for (const v4 of finalCands) {\r\n const pathVerts = [v0, v1, v2, v3, v4]\r\n const sorted = [...pathVerts].sort((a, b) => a - b)\r\n const key = sorted.join(',')\r\n if (found.has(key)) continue\r\n found.add(key)\r\n const c = new THREE.Vector3()\r\n for (const vi of pathVerts) c.add(data.vertices[vi])\r\n centers.push(c.multiplyScalar(1 / 5))\r\n }\r\n }\r\n }\r\n }\r\n }\r\n return centers\r\n }\r\n return []\r\n}\r\n\r\n/** 轴与转角完全由 core 的置换反解给出(几何体与 core 点模型同源),\r\n * react 侧不再二次选轴——单一真源,避免两层各算一遍导致语义漂移。 */\r\nfunction computeGeometricRotation(group: Group, element: GroupElement): { axis: [number,number,number]; angleRad: number; label: string } | null {\r\n return computeElementRotation(group, element)\r\n}\r\n\r\nexport interface SymmetryViewSceneProps {\r\n /** 展示群(null 由调用方自行占位,本组件要求非空) */\r\n group: Group\r\n /** 对称类型;缺省按 getSymmetryType(group) 推导(unsupported 群渲染提示 overlay) */\r\n symmetryType?: SymmetryType\r\n /** 深色场景配色(背景 + 顶部标注文字);主画布传主主题,ViewWindow 传窗口主题(解耦) */\r\n dark?: boolean\r\n /** 对偶多面体(cube↔octahedron / icosahedron↔dodecahedron):受控形态(false=主形 / true=对偶形)。\r\n * 切换入口由宿主提供(ViewWindow ⚙ 面板 / 主画布 ViewPanel 的 Shape 选项),场景内不再悬浮切换按钮 */\r\n variant?: boolean\r\n /** 元素作用演示开关;缺省 false */\r\n showAction?: boolean\r\n /** 演示元素 id(受控,toggle 语义:点活跃元素回到恒等姿态);缺省 null */\r\n actionElementId?: string | null\r\n /** 动画倍速 0.2–5;缺省 1 */\r\n rotateSpeed?: number\r\n /** 顶部群名 + 几何描述标注;缺省 true(小窗可关) */\r\n showFigureTitle?: boolean\r\n /** 锁定相机交互(拖拽旋转/平移/缩放);演示动画期间本就禁用 */\r\n locked?: boolean\r\n /** 演示状态提示回调(主画布接 hint bar,ViewWindow 显示为内容区底部唯一浮条);缺省无 */\r\n onHint?: (msg: string) => void\r\n /** 演示开启但当前元素无可旋转作用(恒等/未选)时,是否上抛 clickHint 引导;\r\n * 主画布缺省 true(提示去其它视图点元素);ViewWindow 传 false(引导文案写在参数面板,浮条只显示真实状态) */\r\n hintOnIdle?: boolean\r\n /** 重放信号:宿主自增该值即对当前演示元素重播一次动画(姿态不改变目标,\r\n * 解决同元素动画播完一次后无入口重看的缺口);缺省 0 */\r\n replaySignal?: number\r\n /** 显式主题(`'dark' | 'light'`);与 `dark` 二选一,本项优先。\r\n * 推荐新代码用 `theme` —— 与其余 Scene 命名统一(`dark` 作为兼容别名保留) */\r\n theme?: SceneTheme\r\n /** 演示动画期间是否禁用相机旋转 / 平移;缺省 `false`。\r\n * **注意行为变更**:旧实现恒等于 `true`(`enableRotate = !showAction && !locked`),\r\n * 导致\"演示元素未命中 / 恒等元素时动画不跑,视角却已被锁死\"。需要旧行为的宿主显式传 `true`。 */\r\n lockCameraOnAction?: boolean\r\n /** 演示动画播放结束(姿态落定)回调;用于宿主编排「看完自动切下一个」等自定义流程 */\r\n onAnimationEnd?: () => void\r\n}\r\n\r\n/** 对称性视图纯渲染核(props 化、主题解耦):Canvas + 场景 + 顶部标注 + 演示动画。\r\n * 主画布经 SymmetryView 适配器接入全局 context;ViewWindow(FGVE 引擎)受控直接使用。 */\r\nexport function SymmetryViewScene({\r\n group,\r\n symmetryType: symmetryTypeProp,\r\n dark = false,\r\n variant = false,\r\n showAction = false,\r\n actionElementId = null,\r\n rotateSpeed = 1,\r\n showFigureTitle = true,\r\n locked = false,\r\n onHint,\r\n hintOnIdle = true,\r\n replaySignal = 0,\r\n theme,\r\n lockCameraOnAction = false,\r\n onAnimationEnd,\r\n}: SymmetryViewSceneProps) {\r\n const symmetryType = symmetryTypeProp ?? getSymmetryType(group)\r\n const isDark = theme ? theme === 'dark' : dark\r\n\r\n // hooks 前置(不随 unsupported 分支提前返回,保证切换群时 hooks 顺序稳定)\r\n const data = useMemo((): SymmetryData => {\r\n const radius = 4\r\n switch (symmetryType) {\r\n case 'cyclic': return getCyclicFigure(group.order, radius)\r\n case 'dihedral': { const n = group.order / 2; return getDihedralFigure(Math.round(n), radius) }\r\n case 'tetrahedron': return getTetrahedron(radius)\r\n case 'cube': return variant ? getOctahedron(radius) : getCube(radius)\r\n case 'icosahedron': return variant ? getDodecahedron(radius) : getIcosahedron(radius)\r\n case 'rectangle': return getRectangle(radius)\r\n default: return getCyclicFigure(1, radius)\r\n }\r\n }, [group, symmetryType, variant])\r\n\r\n if (symmetryType === 'unsupported') return <UnsupportedOverlay group={group} />\r\n\r\n const bgColor = isDark ? '#0a0a1a' : '#f4f4f7'\r\n\r\n return (\r\n <div style={{ width: '100%', height: '100%', background: bgColor }}>\r\n <Canvas camera={{ position: [0, 3, 10], fov: 50, near: 0.1, far: 100 }} gl={{ antialias: true, alpha: false, preserveDrawingBuffer: true }}>\r\n <color attach=\"background\" args={[bgColor]} />\r\n <SymmetryScene\r\n group={group}\r\n symmetryType={symmetryType}\r\n data={data}\r\n variant={variant}\r\n showAction={showAction}\r\n actionElementId={actionElementId}\r\n rotateSpeed={rotateSpeed}\r\n showFigureTitle={showFigureTitle}\r\n dark={isDark}\r\n locked={locked}\r\n onHint={onHint}\r\n hintOnIdle={hintOnIdle}\r\n replaySignal={replaySignal}\r\n lockCameraOnAction={lockCameraOnAction}\r\n onAnimationEnd={onAnimationEnd}\r\n />\r\n </Canvas>\r\n </div>\r\n )\r\n}\r\n\r\n\r\nfunction useAnimatedRotation(\r\n targetQuat: THREE.Quaternion | null,\r\n speed: number,\r\n onPhaseChange: (phase: 'rest' | 'reset' | 'rotating') => void,\r\n replaySignal?: number,\r\n onAnimationEnd?: () => void,\r\n) {\r\n const stateRef = useRef({\r\n target: null as THREE.Quaternion | null,\r\n t: 2,\r\n speed: 1,\r\n phase: 'rest' as 'rest' | 'reset' | 'rotating',\r\n settled: false,\r\n currentQuat: new THREE.Quaternion(),\r\n })\r\n\r\n // 结束回调放 ref:避免宿主每帧传新闭包导致 useFrame 里读到过期函数。\r\n // 用 effect 同步而非渲染期赋值 —— 渲染期写 ref 会触发 react-hooks/refs。\r\n const endRef = useRef(onAnimationEnd)\r\n useEffect(() => { endRef.current = onAnimationEnd }, [onAnimationEnd])\r\n\r\n useEffect(() => { stateRef.current.speed = speed }, [speed])\r\n\r\n useEffect(() => {\r\n if (targetQuat) {\r\n stateRef.current.target = targetQuat.clone()\r\n stateRef.current.t = 0\r\n stateRef.current.phase = 'reset'\r\n stateRef.current.settled = false\r\n onPhaseChange('reset')\r\n } else {\r\n stateRef.current.target = null\r\n stateRef.current.t = 2\r\n stateRef.current.settled = false\r\n stateRef.current.phase = 'rest'\r\n stateRef.current.currentQuat.identity()\r\n onPhaseChange('rest')\r\n }\r\n }, [targetQuat, onPhaseChange])\r\n\r\n // 显式重放:replaySignal 递增即对当前姿态再播一次(不改变目标),\r\n // 解决\"动画只在元素切换时播一次、同元素无法重看\"的交互缺口。\r\n useEffect(() => {\r\n const st = stateRef.current\r\n if (!replaySignal || !st.target) return\r\n st.t = 0\r\n st.phase = 'reset'\r\n st.settled = false\r\n onPhaseChange('reset')\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [replaySignal])\r\n\r\n useFrame((_, dt) => {\r\n const st = stateRef.current\r\n if (!st.target || st.t > 1.5) return\r\n st.t += dt * st.speed\r\n if (st.phase === 'reset') {\r\n if (st.t >= 0.5) { st.phase = 'rotating'; st.t = 0.5; onPhaseChange('rotating') }\r\n else { st.currentQuat.identity(); return }\r\n }\r\n if (st.t >= 1) {\r\n st.t = 2; st.settled = true; st.phase = 'rest'; onPhaseChange('rest')\r\n st.currentQuat.copy(st.target)\r\n // 姿态落定 → 通知宿主「这次演示播完了」(重放会再次触发)\r\n endRef.current?.()\r\n } else {\r\n st.currentQuat.slerpQuaternions(new THREE.Quaternion(), st.target, (st.t - 0.5) / 0.5)\r\n }\r\n })\r\n\r\n return stateRef\r\n}\r\n\r\nfunction AnimatedGeo({ data, symmetryType, isDirected, animState }: {\r\n data: SymmetryData\r\n symmetryType: SymmetryType\r\n isDirected: boolean\r\n animState: { current: { currentQuat: THREE.Quaternion } }\r\n}) {\r\n const [group] = useState(() => new THREE.Group())\r\n\r\n useEffect(() => {\r\n while (group.children.length > 0) group.remove(group.children[0])\r\n\r\n data.vertices.forEach((v, i) => {\r\n const mesh = new THREE.Mesh(\r\n new THREE.SphereGeometry(0.28, 16, 16),\r\n new THREE.MeshStandardMaterial({ color: getVertexColor(i, data.vertices.length), roughness: 0.3, metalness: 0.1, emissive: getVertexColor(i, data.vertices.length), emissiveIntensity: 0.3 })\r\n )\r\n mesh.position.copy(v)\r\n group.add(mesh)\r\n })\r\n\r\n data.edges.forEach(([a, b]) => {\r\n const from = data.vertices[a], to = data.vertices[b]\r\n const pts = [from.clone(), to.clone()]\r\n const geom = new THREE.BufferGeometry().setFromPoints(pts)\r\n const color = isDirected ? '#ff6b6b' : '#66aaff'\r\n group.add(new THREE.Line(geom, new THREE.LineBasicMaterial({ color })))\r\n if (isDirected) {\r\n const dir = new THREE.Vector3().subVectors(to, from).normalize()\r\n const p = new THREE.Vector3(-dir.z, 0, dir.x)\r\n const tip = to.clone().addScaledVector(dir, -0.35)\r\n const w1 = tip.clone().addScaledVector(dir, -0.12).addScaledVector(p, 0.1)\r\n const w2 = tip.clone().addScaledVector(dir, -0.12).addScaledVector(p, -0.1)\r\n const ag = new THREE.BufferGeometry().setFromPoints([w1, tip, w2])\r\n group.add(new THREE.Line(ag, new THREE.LineBasicMaterial({ color })))\r\n }\r\n })\r\n\r\n if (['tetrahedron', 'cube', 'icosahedron'].includes(symmetryType)) {\r\n const fc = symmetryType === 'cube' ? '#ff9944' : symmetryType === 'tetrahedron' ? '#44cc88' : '#cc66ff'\r\n const faces = computeTriangularFaces(data)\r\n if (faces.length > 0) {\r\n const pos: number[] = [], idx: number[] = []\r\n for (const [vi, a, b2] of faces) {\r\n const i2 = pos.length / 3\r\n const va = data.vertices[vi], vb = data.vertices[a], vc = data.vertices[b2]\r\n pos.push(va.x, va.y, va.z, vb.x, vb.y, vb.z, vc.x, vc.y, vc.z)\r\n idx.push(i2, i2 + 1, i2 + 2)\r\n }\r\n const fg = new THREE.BufferGeometry()\r\n fg.setAttribute('position', new THREE.Float32BufferAttribute(pos, 3))\r\n fg.setIndex(idx)\r\n fg.computeVertexNormals()\r\n group.add(new THREE.Mesh(fg, new THREE.MeshStandardMaterial({ color: fc, transparent: true, opacity: 0.3, side: THREE.DoubleSide, depthWrite: false })))\r\n }\r\n }\r\n }, [data, symmetryType, isDirected, group])\r\n\r\n useFrame(() => {\r\n group.quaternion.copy(animState.current.currentQuat)\r\n })\r\n\r\n return <primitive object={group} />\r\n}\r\n\r\nfunction AxisMarker({ from, to, intersections }: {\r\n from: THREE.Vector3\r\n to: THREE.Vector3\r\n intersections: { pos: THREE.Vector3; kind: 'vertex' | 'edge' | 'face-center' }[]\r\n}) {\r\n const mid = useMemo(() => from.clone().add(to).multiplyScalar(0.5), [from, to])\r\n const dir = useMemo(() => to.clone().sub(from).normalize(), [from, to])\r\n const len = useMemo(() => to.distanceTo(from), [from, to])\r\n const quat = useMemo(() => {\r\n const q = new THREE.Quaternion()\r\n q.setFromUnitVectors(new THREE.Vector3(0, 1, 0), dir)\r\n return q\r\n }, [dir])\r\n\r\n return (\r\n <group>\r\n <mesh position={mid} quaternion={quat}>\r\n <cylinderGeometry args={[0.12, 0.12, len, 8]} />\r\n <meshStandardMaterial color=\"#ff3333\" emissive=\"#ff0000\" emissiveIntensity={1.0} roughness={0.1} />\r\n </mesh>\r\n <mesh position={to} quaternion={quat}>\r\n <coneGeometry args={[0.28, 0.7, 8, 1]} />\r\n <meshStandardMaterial color=\"#ff3333\" emissive=\"#ff0000\" emissiveIntensity={1.0} roughness={0.1} />\r\n </mesh>\r\n {intersections.map((intr, i) => (\r\n <mesh key={i} position={intr.pos}>\r\n <sphereGeometry args={[intr.kind === 'vertex' ? 0.24 : intr.kind === 'face-center' ? 0.22 : 0.16, 12, 12]} />\r\n <meshStandardMaterial\r\n color={intr.kind === 'vertex' ? '#ffd93d' : intr.kind === 'face-center' ? '#84cc16' : '#4ecdc4'}\r\n emissive={intr.kind === 'vertex' ? '#ffd93d' : intr.kind === 'face-center' ? '#84cc16' : '#4ecdc4'}\r\n emissiveIntensity={0.7}\r\n roughness={0.1}\r\n />\r\n </mesh>\r\n ))}\r\n </group>\r\n )\r\n}\r\n\r\nfunction SymmetryScene({\r\n group, symmetryType, data, variant,\r\n showAction, actionElementId, rotateSpeed,\r\n showFigureTitle, dark, locked, onHint, hintOnIdle, replaySignal,\r\n lockCameraOnAction, onAnimationEnd,\r\n}: {\r\n group: Group\r\n symmetryType: SymmetryType\r\n data: SymmetryData | null\r\n variant: boolean\r\n showAction: boolean\r\n actionElementId: string | null\r\n rotateSpeed: number\r\n showFigureTitle: boolean\r\n dark: boolean\r\n locked: boolean\r\n onHint?: (msg: string) => void\r\n hintOnIdle: boolean\r\n replaySignal: number\r\n lockCameraOnAction: boolean\r\n onAnimationEnd?: () => void\r\n}) {\r\n const { t } = useTranslation()\r\n const [animPhase, setAnimPhase] = useState<'rest' | 'reset' | 'rotating'>('rest')\r\n\r\n const animInfo = useMemo(() => {\r\n if (!showAction || !actionElementId || !data) return null\r\n // 引用解析接受 id / label / value —— 传 label 不再是静默失败(未命中会 warn 一次)\r\n const el = resolveElementWarn(group, actionElementId, 'SymmetryViewScene.actionElementId')\r\n if (!el) return null\r\n const result = computeGeometricRotation(group, el)\r\n if (!result || result.angleRad === 0) return null\r\n return result\r\n }, [showAction, actionElementId, group, data])\r\n\r\n const targetQuat = useMemo(() => {\r\n if (!animInfo || animInfo.angleRad === 0) return null\r\n const q = new THREE.Quaternion()\r\n q.setFromAxisAngle(new THREE.Vector3(...animInfo.axis), animInfo.angleRad)\r\n return q\r\n }, [animInfo])\r\n\r\n const animRef = useAnimatedRotation(targetQuat, rotateSpeed, setAnimPhase, replaySignal, onAnimationEnd)\r\n\r\n // 演示状态反馈:统一经 onHint 上抛(主画布 hint bar / ViewWindow 底部浮条),宿主各自决定单处展示位置\r\n const activeEl = useMemo(\r\n () => (showAction && actionElementId\r\n ? resolveElementWarn(group, actionElementId, 'SymmetryViewScene.actionElementId')\r\n : null),\r\n [showAction, actionElementId, group],\r\n )\r\n const statusText = useMemo(() => {\r\n if (!activeEl || !animInfo) return null\r\n const phaseSuffix = animPhase === 'reset' ? ` — ${t('symmetry.reset')}`\r\n : animPhase === 'rotating' ? ` — ${t('symmetry.rotating')}`\r\n : ''\r\n return { label: activeEl.label, action: animInfo.label, suffix: phaseSuffix }\r\n }, [activeEl, animInfo, animPhase, t])\r\n\r\n useEffect(() => {\r\n if (!showAction) return\r\n if (!statusText) {\r\n // 演示开启但当前元素无可演示的几何旋转(未选 / 恒等)→ 仅主画布需要 clickHint 引导;\r\n // ViewWindow 的引导文案写在 ⚙ 面板元素列表旁(hintOnIdle=false),浮条只显示真实演示状态\r\n if (hintOnIdle) onHint?.(t('symmetry.clickHint'))\r\n return\r\n }\r\n onHint?.(`<span class=\"hint-highlight\">${statusText.label}</span>: ${statusText.action}${statusText.suffix}`)\r\n }, [showAction, statusText, onHint, hintOnIdle, t])\r\n\r\n const hasData = !!data\r\n const isDirected = data?.directed === true\r\n const topY = useMemo(() => data ? data.vertices.reduce((max, v) => Math.max(max, v.y), -Infinity) : 0, [data])\r\n const dataRadius = useMemo(() => data ? data.vertices[0].length() : 4, [data])\r\n\r\n const showAxis = animInfo && Math.abs(animInfo.angleRad) > 1e-10\r\n const axisLen = dataRadius * 1.4\r\n const axisTo = showAxis\r\n ? new THREE.Vector3(...animInfo!.axis).normalize().multiplyScalar(axisLen)\r\n : new THREE.Vector3()\r\n const axisNeg = showAxis\r\n ? new THREE.Vector3(...animInfo!.axis).normalize().multiplyScalar(-axisLen * 0.6)\r\n : new THREE.Vector3()\r\n const axisIntersections = useMemo(() => {\r\n if (!showAxis || !data) return []\r\n const dir = new THREE.Vector3(...animInfo!.axis).normalize()\r\n const intersections: { pos: THREE.Vector3; kind: 'vertex' | 'edge' | 'face-center' }[] = []\r\n const VERTEX_THRESH = 0.25\r\n const EDGE_MID_THRESH = 0.25\r\n const FACE_CENTER_THRESH = 0.25\r\n\r\n for (const v of data.vertices) {\r\n const proj = v.dot(dir)\r\n const closest = dir.clone().multiplyScalar(proj)\r\n if (v.distanceTo(closest) < VERTEX_THRESH) {\r\n intersections.push({ pos: closest.clone(), kind: 'vertex' })\r\n }\r\n }\r\n\r\n for (const [a, b] of data.edges) {\r\n const mid = data.vertices[a].clone().add(data.vertices[b]).multiplyScalar(0.5)\r\n const proj = mid.dot(dir)\r\n const closest = dir.clone().multiplyScalar(proj)\r\n if (mid.distanceTo(closest) < EDGE_MID_THRESH) {\r\n intersections.push({ pos: closest.clone(), kind: 'edge' })\r\n }\r\n }\r\n\r\n const triangularFaces = computeTriangularFaces(data)\r\n const faceCenters = computeFaceCenters(data, triangularFaces)\r\n for (const fc of faceCenters) {\r\n const proj = fc.dot(dir)\r\n const closest = dir.clone().multiplyScalar(proj)\r\n if (fc.distanceTo(closest) < FACE_CENTER_THRESH) {\r\n intersections.push({ pos: closest.clone(), kind: 'face-center' })\r\n }\r\n }\r\n\r\n const merged: { pos: THREE.Vector3; kind: 'vertex' | 'edge' | 'face-center' }[] = []\r\n for (const intr of intersections) {\r\n const dup = merged.find(m => m.pos.distanceTo(intr.pos) < 0.01)\r\n if (!dup) merged.push(intr)\r\n else if (intr.kind === 'vertex' && dup.kind !== 'vertex') {\r\n dup.kind = 'vertex'; dup.pos.copy(intr.pos)\r\n } else if (intr.kind === 'face-center' && dup.kind === 'edge') {\r\n dup.kind = 'face-center'; dup.pos.copy(intr.pos)\r\n }\r\n }\r\n\r\n return merged\r\n }, [showAxis, animInfo, data])\r\n\r\n if (!hasData) return null\r\n\r\n return (\r\n <>\r\n <ambientLight intensity={0.4} />\r\n <directionalLight position={[5, 8, 5]} intensity={1.2} />\r\n <directionalLight position={[-5, -2, -3]} intensity={0.6} />\r\n <pointLight position={[0, 5, 0]} intensity={0.5} />\r\n\r\n {showFigureTitle && (\r\n <Html position={[0, topY + 1.5, 0]} center zIndexRange={[2, 0]} wrapperClass=\"gv-html-overlay\">\r\n <div style={{ color: dark ? '#fff' : '#1a1a2e', fontSize: '20px', fontWeight: 'bold', textShadow: dark ? '0 0 10px rgba(0,0,0,0.8)' : 'none', whiteSpace: 'nowrap', userSelect: 'none', pointerEvents: 'none' }}\r\n dangerouslySetInnerHTML={{ __html: renderTex(texify(group.name)) }} />\r\n </Html>\r\n )}\r\n\r\n {showFigureTitle && (\r\n <Html position={[0, topY + 2.2, 0]} center zIndexRange={[2, 0]} wrapperClass=\"gv-html-overlay\">\r\n <div style={{ color: dark ? '#aaa' : '#555566', fontSize: '13px', textShadow: dark ? '0 0 8px rgba(0,0,0,0.8)' : 'none', whiteSpace: 'nowrap', userSelect: 'none', pointerEvents: 'none' }}\r\n dangerouslySetInnerHTML={{ __html: renderTex(\r\n // 副标题只描述几何形态(群名已在上方标题行,不再重复符号前缀)\r\n symmetryType === 'cyclic' ? t('symmetry.geo.cyclicText', { n: group.order }) :\r\n symmetryType === 'dihedral' ? t('symmetry.geo.dihedralText', { n: group.order / 2 }) :\r\n symmetryType === 'cube' ? (variant ? t('symmetry.geo.octahedron') : t('symmetry.geo.cube')) :\r\n symmetryType === 'icosahedron' ? (variant ? t('symmetry.geo.dodecahedron') : t('symmetry.geo.icosahedron')) :\r\n t('symmetry.geo.' + symmetryType)\r\n ) }} />\r\n </Html>\r\n )}\r\n\r\n {showAxis && (\r\n <AxisMarker\r\n from={axisNeg}\r\n to={axisTo}\r\n intersections={axisIntersections}\r\n />\r\n )}\r\n\r\n <AnimatedGeo data={data} symmetryType={symmetryType} isDirected={isDirected} animState={animRef} />\r\n\r\n {symmetryType === 'dihedral' && data.vertices.length > 2 && (\r\n <mesh rotation={[-Math.PI / 2, 0, 0]}>\r\n <circleGeometry args={[data.vertices[0].length() * 0.97, 64]} />\r\n <meshStandardMaterial color=\"#66aaff\" transparent opacity={0.15} side={THREE.DoubleSide} depthWrite={false} />\r\n </mesh>\r\n )}\r\n\r\n {symmetryType === 'cyclic' && (\r\n <mesh rotation={[-Math.PI / 2, 0, 0]}>\r\n <ringGeometry args={[data.vertices[0].length() * 0.93, data.vertices[0].length() * 0.97, 64]} />\r\n <meshStandardMaterial color=\"#ff6b6b\" transparent opacity={0.3} side={THREE.DoubleSide} depthWrite={false} />\r\n </mesh>\r\n )}\r\n\r\n <OrbitControls\r\n enableDamping={false}\r\n minDistance={2}\r\n maxDistance={20}\r\n enableRotate={!locked && !(showAction && lockCameraOnAction)}\r\n enablePan={!locked && !(showAction && lockCameraOnAction)}\r\n enableZoom={!locked}\r\n />\r\n </>\r\n )\r\n}\r\n\r\nfunction UnsupportedOverlay({ group }: { group: Group }) {\r\n const { t } = useTranslation()\r\n return (\r\n <div style={{ width: '100%', height: '100%', background: 'var(--bg-canvas)', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', color: 'var(--text-muted)' }}>\r\n <p style={{ fontSize: '18px', marginBottom: '8px' }}><span dangerouslySetInnerHTML={{ __html: renderTex(texify(group.name)) }} /></p>\r\n <p style={{ fontSize: '14px', color: 'var(--text-subtle)' }}>{t('symmetry.unsupported')}</p>\r\n <p style={{ fontSize: '12px', color: 'var(--text-dim)', marginTop: '12px' }}>{t('symmetry.supported')}</p>\r\n </div>\r\n )\r\n}\r\n","import { createContext, useState, useCallback, useEffect, type ReactNode } from 'react'\n\nexport type Theme = 'dark' | 'light'\n\nexport interface ThemeContextValue {\n theme: Theme\n toggleTheme: () => void\n /** 视图窗口(浮动窗/ViewWindow)独立的深浅色主题,与主界面 theme 解耦 */\n viewWindowTheme: Theme\n toggleViewWindowTheme: () => void\n}\n\n// eslint-disable-next-line react-refresh/only-export-components\nexport const ThemeContext = createContext<ThemeContextValue>({\n theme: 'dark',\n toggleTheme: () => { },\n viewWindowTheme: 'dark',\n toggleViewWindowTheme: () => { },\n})\n\nfunction getSystemTheme(): Theme {\n if (typeof window === 'undefined') return 'dark'\n if (window.matchMedia('(prefers-color-scheme: light)').matches) return 'light'\n return 'dark'\n}\n\nfunction getStoredTheme(): Theme | null {\n if (typeof window === 'undefined') return null\n try {\n const stored = localStorage.getItem('groupviz-theme')\n if (stored === 'dark' || stored === 'light') return stored\n } catch { /* localStorage unavailable (e.g., privacy mode) */ }\n return null\n}\n\nfunction getStoredViewWindowTheme(): Theme | null {\n if (typeof window === 'undefined') return null\n try {\n const stored = localStorage.getItem('groupviz-viewwindow-theme')\n if (stored === 'dark' || stored === 'light') return stored\n } catch { /* localStorage unavailable (e.g., privacy mode) */ }\n return null\n}\n\nfunction applyTheme(theme: Theme) {\n if (typeof document === 'undefined') return\n document.documentElement.setAttribute('data-theme', theme)\n}\n\nexport function ThemeProvider({ children }: { children: ReactNode }) {\n const [theme, setThemeState] = useState<Theme>(() => {\n const stored = getStoredTheme()\n if (stored) return stored\n return getSystemTheme()\n })\n\n // 视图窗口主题:独立于主界面 theme,默认深色(图形对比度更佳)\n const [viewWindowTheme, setViewWindowThemeState] = useState<Theme>(() => {\n return getStoredViewWindowTheme() ?? 'dark'\n })\n\n const toggleTheme = useCallback(() => {\n setThemeState(prev => {\n const next = prev === 'dark' ? 'light' : 'dark'\n localStorage.setItem('groupviz-theme', next)\n return next\n })\n }, [])\n\n const toggleViewWindowTheme = useCallback(() => {\n setViewWindowThemeState(prev => {\n const next = prev === 'dark' ? 'light' : 'dark'\n localStorage.setItem('groupviz-viewwindow-theme', next)\n return next\n })\n }, [])\n\n const setTheme = useCallback((t: Theme) => {\n setThemeState(t)\n localStorage.setItem('groupviz-theme', t)\n }, [])\n\n useEffect(() => {\n applyTheme(theme)\n }, [theme])\n\n useEffect(() => {\n const mql = window.matchMedia('(prefers-color-scheme: light)')\n const handler = (e: MediaQueryListEvent) => {\n const stored = getStoredTheme()\n if (!stored) {\n setTheme(e.matches ? 'light' : 'dark')\n }\n }\n mql.addEventListener('change', handler)\n return () => mql.removeEventListener('change', handler)\n }, [setTheme])\n\n return (\n <ThemeContext.Provider value={{ theme, toggleTheme, viewWindowTheme, toggleViewWindowTheme }}>\n {children}\n </ThemeContext.Provider>\n )\n}\n","import { useContext } from 'react'\nimport { ThemeContext, ThemeProvider } from './ThemeContext'\n\nexport function useTheme() {\n return useContext(ThemeContext)\n}\n\nexport { ThemeProvider }\nexport type { Theme } from './ThemeContext'\n","import type * as THREE from 'three'\n\n// 3D 凯莱图视图的轨道控制注册桥:导出 GIF 时按「帧序号 × 帧延时」精确驱动相机旋转。\n// Cayley3DView 挂载时注册(仅主视口 .canvas-viewport 内的实例),导出完成后恢复原视角。\n// GIF 相机在独立离屏渲染器上工作:不触碰实时轨道/相机,导出期间展示区照常旋转。\n\nexport interface Cayley3DOrbitSnapshot {\n theta: number\n phi: number\n radius: number\n target: THREE.Vector3\n}\n\nexport interface Cayley3DControlAPI {\n isReady: () => boolean\n snapshotOrbit: () => Cayley3DOrbitSnapshot\n beginRotation: (radPerSec: number) => void\n endRotation: (snapshot?: Cayley3DOrbitSnapshot | null) => void\n // 展示区当前的自动旋转角速度(与 ▶ 自动旋转/拖拽后同公式):GIF 按此速度导出,\n // 保证导出动图与展示区转速一致(rad/s,与群阶数无关)\n displayAngVel: () => number\n // 导出第 index 帧:将离屏相机设到「基准角 + radPerSec × index × frameDelayMs」并渲染,\n // 返回渲染好的离屏 canvas(导出循环直接 drawImage 采集,不动实时画面)\n frameAt: (index: number, frameDelayMs: number) => HTMLCanvasElement | null\n}\n\nlet registered: Cayley3DControlAPI | null = null\n\nexport function registerCayley3DControls(api: Cayley3DControlAPI) {\n registered = api\n}\n\nexport function unregisterCayley3DControls(api: Cayley3DControlAPI) {\n if (registered === api) registered = null\n}\n\nexport function getCayley3DControls(): Cayley3DControlAPI | null {\n return registered\n}","import { useRef, useMemo, useEffect, useState, useCallback, memo } from 'react'\r\nimport { Canvas, useFrame, useThree } from '@react-three/fiber'\r\nimport { Html } from '@react-three/drei'\r\nimport * as THREE from 'three'\r\nimport { useTranslation } from '../../i18n/useTranslation'\r\nimport { useTheme } from '../../theme/useTheme'\r\nimport type { Group, GroupElement, Generator, MultiplyType, Layout3D } from '../../core/types'\r\nimport { getDefaultLayout3D } from '../../core/types'\r\nimport { computeCayleyActionEdges } from '../../core/algebra/forceLayout'\r\nimport { compute3DPositions } from '../../core/algebra/layout3D'\r\nimport { texify, renderTex } from '../../utils/texify'\r\nimport { registerCayley3DControls, unregisterCayley3DControls } from '../../utils/cayley3dControls'\r\nimport type { Cayley3DControlAPI } from '../../utils/cayley3dControls'\r\nimport { normalizeCayleyActions } from '../../context/cayleyActions'\r\nimport type { CayleyActionParam, Cayley3DFaceFillParams } from '../../core/types/viewConfig'\r\nimport { subgroupFaces, buildUndirectedEdgeKeys, FACE_COLOR_PALETTE } from '../../core/algebra/faces3D'\r\n\r\ninterface EdgeData {\r\n fromIdx: number\r\n toIdx: number\r\n fromId: string\r\n toId: string\r\n fromPos: THREE.Vector3\r\n toPos: THREE.Vector3\r\n gen: Generator\r\n isSelfLoop: boolean\r\n isBidirectional?: boolean\r\n}\r\n\r\nfunction getElementColor(idx: number, total: number, isAbelian: boolean): string {\r\n if (isAbelian) {\r\n const hue = (idx / total) * 360\r\n return `hsl(${hue}, 60%, 55%)`\r\n }\r\n const hue = (idx * 137.508) % 360\r\n return `hsl(${hue}, 65%, 55%)`\r\n}\r\n\r\ninterface NodeSphereProps {\r\n position: THREE.Vector3\r\n label: string\r\n color: string\r\n isSelected: boolean\r\n isHovered: boolean\r\n subsetColor: string | null\r\n element: GroupElement\r\n nodeScale: number\r\n showLabel: boolean\r\n /** 深色主题(label 阴影深浅)。由 Scene 层从 theme prop / ThemeContext 统一解析后传入(FGVE 入包:子组件不再读 context) */\r\n isDark: boolean\r\n onSelectElement: (id: string, additive: boolean) => void\r\n onPointerEnter: (el: GroupElement) => void\r\n onPointerLeave: (el: GroupElement | null) => void\r\n}\r\n\r\nconst NodeSphere = memo(function NodeSphere({ position, label, color, isSelected, isHovered, subsetColor, element, nodeScale, showLabel, isDark, onSelectElement, onPointerEnter, onPointerLeave }: NodeSphereProps) {\r\n const texLabel = useMemo(() => renderTex(texify(label)), [label])\r\n const primary = isSelected || isHovered\r\n const seg = primary ? 24 : 12\r\n\r\n return (\r\n <group position={position}>\r\n <mesh\r\n onClick={(e) => {\r\n e.stopPropagation()\r\n onSelectElement(element.id, e.nativeEvent.ctrlKey || e.nativeEvent.metaKey)\r\n }}\r\n onPointerEnter={() => onPointerEnter(element)}\r\n onPointerLeave={() => onPointerLeave(null)}\r\n >\r\n <sphereGeometry args={[primary ? 0.55 * nodeScale : 0.42 * nodeScale, seg, seg]} />\r\n <meshStandardMaterial\r\n color={primary ? color : subsetColor || color}\r\n emissive={primary ? color : subsetColor || color}\r\n emissiveIntensity={primary ? 0.6 : subsetColor ? 0.4 : 0.2}\r\n roughness={0.3}\r\n metalness={0.1}\r\n />\r\n </mesh>\r\n {subsetColor && !isSelected && (\r\n <mesh>\r\n <sphereGeometry args={[0.55 * nodeScale, 32, 32]} />\r\n <meshBasicMaterial color={subsetColor} transparent opacity={0.25} />\r\n </mesh>\r\n )}\r\n {isSelected && (\r\n <mesh>\r\n <sphereGeometry args={[0.62 * nodeScale, 32, 32]} />\r\n <meshBasicMaterial color=\"#ffd93d\" transparent opacity={0.3} />\r\n </mesh>\r\n )}\r\n {showLabel && primary && (\r\n <Html distanceFactor={12} center style={{ pointerEvents: 'none', userSelect: 'none' }} wrapperClass=\"gv-html-overlay\">\r\n <div\r\n style={{\r\n color: 'var(--node-text)', fontSize: 11, fontWeight: 'bold',\r\n textShadow: isDark ? '0 0 6px rgba(0,0,0,0.8)' : '0 0 4px rgba(255,255,255,0.9)', whiteSpace: 'nowrap',\r\n fontFamily: 'serif', display: 'flex', alignItems: 'center', justifyContent: 'center'\r\n }}\r\n dangerouslySetInnerHTML={{ __html: texLabel }}\r\n />\r\n </Html>\r\n )}\r\n </group>\r\n )\r\n})\r\n\r\ninterface EdgeLineProps {\r\n start: THREE.Vector3\r\n end: THREE.Vector3\r\n color: string\r\n isHighlighted: boolean\r\n isSelfLoop: boolean\r\n isBidirectional?: boolean\r\n showArrow?: boolean\r\n}\r\n\r\nconst StraightEdge = memo(function StraightEdge({ start, end, color, isHighlighted }: { start: THREE.Vector3; end: THREE.Vector3; color: string; isHighlighted: boolean }) {\r\n const meshRef = useRef<THREE.Mesh>(null)\r\n\r\n const dir = new THREE.Vector3().subVectors(end, start)\r\n const len = dir.length()\r\n dir.normalize()\r\n\r\n const mid = new THREE.Vector3().addVectors(start, end).multiplyScalar(0.5)\r\n const thickness = isHighlighted ? 0.08 : 0.05\r\n\r\n useEffect(() => {\r\n const mesh = meshRef.current\r\n // 真实 R3F 下 mesh 是 THREE.Mesh(quaternion 必在);测试 stub 的 DOM 元素无此属性,跳过\r\n if (!mesh?.quaternion) return\r\n const quat = new THREE.Quaternion()\r\n quat.setFromUnitVectors(new THREE.Vector3(0, 1, 0), dir.clone())\r\n mesh.quaternion.copy(quat)\r\n }, [dir])\r\n\r\n return (\r\n <mesh ref={meshRef} position={mid}>\r\n <cylinderGeometry args={[thickness, thickness, len, 4, 1]} />\r\n <meshStandardMaterial color={color} emissive={color} emissiveIntensity={isHighlighted ? 0.7 : 0.25} roughness={0.4} />\r\n </mesh>\r\n )\r\n})\r\n\r\n// 直线边箭头锥:仅小群渲染(避免大群 draw call 爆炸);与 2D 约定一致,双向边不画箭头\r\nconst ArrowCone = memo(function ArrowCone({ position, direction, color, isHighlighted }: {\r\n position: THREE.Vector3\r\n direction: THREE.Vector3\r\n color: string\r\n isHighlighted: boolean\r\n}) {\r\n const quat = useMemo(() => {\r\n const q = new THREE.Quaternion()\r\n q.setFromUnitVectors(new THREE.Vector3(0, 1, 0), direction)\r\n return q\r\n }, [direction])\r\n return (\r\n <mesh position={position} quaternion={quat}>\r\n <coneGeometry args={[0.11, 0.32, 8, 1]} />\r\n <meshStandardMaterial color={color} emissive={color} emissiveIntensity={isHighlighted ? 0.7 : 0.25} roughness={0.4} />\r\n </mesh>\r\n )\r\n})\r\n\r\nconst EdgeLine = memo(function EdgeLine({ start, end, color, isHighlighted, isSelfLoop, isBidirectional, showArrow }: EdgeLineProps) {\r\n if (isSelfLoop) {\r\n return (\r\n <group position={start}>\r\n <mesh rotation={[Math.PI / 2, 0, 0]} position={[0, 1.0, 0]}>\r\n <torusGeometry args={[0.4, 0.04, 8, 16]} />\r\n <meshStandardMaterial color={color} emissive={color} emissiveIntensity={isHighlighted ? 0.7 : 0.2} roughness={0.4} />\r\n </mesh>\r\n <mesh position={[0.4, 1.0, 0]}>\r\n <coneGeometry args={[0.08, 0.2, 6, 8]} />\r\n <meshStandardMaterial color={color} emissive={color} emissiveIntensity={isHighlighted ? 0.7 : 0.2} roughness={0.4} />\r\n </mesh>\r\n </group>\r\n )\r\n }\r\n\r\n const dir = new THREE.Vector3().subVectors(end, start)\r\n dir.normalize()\r\n\r\n return (\r\n <group>\r\n <StraightEdge start={start} end={end} color={color} isHighlighted={isHighlighted} />\r\n {showArrow && !isBidirectional && (\r\n <ArrowCone\r\n position={end.clone().addScaledVector(dir, -0.66)}\r\n direction={dir}\r\n color={color}\r\n isHighlighted={isHighlighted}\r\n />\r\n )}\r\n </group>\r\n )\r\n})\r\n\r\nconst NOOP_SELECT = () => {}\r\n\r\nexport interface Cayley3DSceneProps {\r\n /** 群;null → .view-empty 占位 */\r\n group: Group | null\r\n /** 选中元素集合(调用方自持会话态) */\r\n selectedElements: Set<string>\r\n /** 节点点击选中回调;缺省 no-op */\r\n onSelectElement?: (id: string, additive: boolean) => void\r\n /** 作用边元素集合;缺省 = 群生成元(normalizeCayleyActions 归一化) */\r\n actions?: CayleyActionParam[]\r\n /** 边的乘法方向;缺省 'right' */\r\n multiplyType?: MultiplyType\r\n /** 3D 布局形状;缺省 getDefaultLayout3D(group) */\r\n layout3D?: Layout3D\r\n /** 节点球缩放 0.5–2.0;缺省 1 */\r\n nodeScale?: number\r\n /** 自动旋转;缺省 false。prop 优先,未设置时内部 ▶ 按钮本地态兜底 */\r\n autoRotate?: boolean\r\n /** 是否显示 hover/选中 Html 标签;缺省 true */\r\n showLabels?: boolean\r\n /** 锁定相机交互(轨道拖拽/滚轮缩放/右键平移);保留点击选中与双击复位 */\r\n locked?: boolean\r\n /** 子集高亮(元素 id → 颜色);context subsets 的同构映射 */\r\n subsetHighlights?: { elementIds: string[]; color: string }[]\r\n /** 渲染主题(canvas 背景 / label 阴影)。缺省回落到 ThemeContext(无 Provider 时 'dark');\r\n * 主应用壳不传即保持现状(读全局主题),包消费端显式传以与容器主题解耦 */\r\n theme?: 'dark' | 'light'\r\n /** 子群陪集面填充(面 = 某真子群单个陪集在布局中占满的平面凸多边形)。\r\n * 作者在 ⚙ 面板选择子群 H 后,几何上成面的陪集以半透明多边形显示,可逐面指定颜色 */\r\n faceFill?: Cayley3DFaceFillParams\r\n}\r\n\r\nfunction Cayley3DSceneBody({\r\n group,\r\n selectedElements,\r\n onSelectElement,\r\n actions: actionsProp,\r\n multiplyType: multiplyTypeProp,\r\n layout3D: layout3DProp,\r\n nodeScale: nodeScaleProp,\r\n autoRotate: autoRotateProp,\r\n showLabels: showLabelsProp,\r\n locked = false,\r\n subsetHighlights = [],\r\n theme = 'dark',\r\n faceFill,\r\n}: Cayley3DSceneProps & { group: Group }) {\r\n const { t } = useTranslation()\r\n const { gl, camera, scene } = useThree()\r\n\r\n const actions = useMemo(() => normalizeCayleyActions(group, actionsProp), [group, actionsProp])\r\n const multiplyType = multiplyTypeProp ?? 'right'\r\n const layout3D = layout3DProp ?? getDefaultLayout3D(group)\r\n const nodeScale = nodeScaleProp ?? 1\r\n const showLabels = showLabelsProp !== false\r\n const selectElement = onSelectElement ?? NOOP_SELECT\r\n\r\n const [autoRotateState, setAutoRotateState] = useState(false)\r\n const autoRotate = autoRotateProp ?? autoRotateState\r\n const [hoverElement, setHoverElement] = useState<GroupElement | null>(null)\r\n\r\n // 自定义轨道状态(替代 drei OrbitControls):theta/phi 球坐标,phi 无界(可无限翻越上下极点,无 makeSafe 钳制)\r\n const orbit = useRef({\r\n theta: 0,\r\n phi: Math.acos(3 / Math.sqrt(3 ** 2 + 12 ** 2)),\r\n radius: Math.sqrt(3 ** 2 + 12 ** 2),\r\n target: new THREE.Vector3(0, 0, 0),\r\n initialized: false,\r\n })\r\n // 最近一次鼠标拖拽向量:自动旋转时按此方向持续旋转(而非固定方向)\r\n const dragVec = useRef({ x: 0, y: 0 })\r\n const dragState = useRef({ active: false, lastX: 0, lastY: 0, x: 0, y: 0, button: 0 })\r\n // GIF 导出期间的角度驱动:beginRotation 记录基准角并创建独立离屏渲染器/相机,\r\n // frameAt 按帧索引精确求角并渲染到离屏 canvas(每帧角度 = 基准 + radPerSec × 帧延时 × 帧序号,\r\n // 与实时渲染耗时无关);实时轨道/相机全程不被触碰,展示区照常旋转\r\n const externalRotation = useRef<{\r\n active: boolean\r\n radPerSec: number\r\n baseTheta: number\r\n basePhi: number\r\n radius: number\r\n target: THREE.Vector3\r\n renderer: THREE.WebGLRenderer | null\r\n ecam: THREE.PerspectiveCamera | null\r\n }>({\r\n active: false, radPerSec: 0, baseTheta: 0, basePhi: 0, radius: 1,\r\n target: new THREE.Vector3(), renderer: null, ecam: null,\r\n })\r\n\r\n // 展示区自动旋转角速度(与 ▶ 自动旋转同一公式;拖拽后按拖拽向量长度降速):\r\n // GIF 导出用同一值,保证导出动图与展示区转速一致\r\n const displayAngVel = useCallback(() => {\r\n const d = dragVec.current\r\n const len = Math.hypot(d.x, d.y)\r\n return (len >= 8 ? 0.35 + Math.min(0.65, len / 360) : 1) * 2 * Math.PI\r\n }, [])\r\n\r\n const isLargeGroup = group.order > 100\r\n const visibleElementIds = useMemo(() => {\r\n if (!isLargeGroup) return new Set(group.elements.map(e => e.id))\r\n const ids = new Set<string>([group.identity.id])\r\n for (const a of actions.filter(x => x.enabled).slice(0, 4)) ids.add(a.elementId)\r\n for (const id of selectedElements) ids.add(id)\r\n for (let i = 0; i < group.elements.length; i += Math.max(1, Math.ceil(group.order / 24))) {\r\n ids.add(group.elements[i].id)\r\n }\r\n return ids\r\n }, [group, actions, selectedElements, isLargeGroup])\r\n\r\n const cayleyEdges = useMemo(() => {\r\n return computeCayleyActionEdges(group, actions, multiplyType)\r\n }, [group, actions, multiplyType])\r\n\r\n const positions = useMemo(() => {\r\n return compute3DPositions(group, layout3D).map(\r\n p => new THREE.Vector3(p[0], p[1], p[2])\r\n )\r\n }, [group, layout3D])\r\n\r\n // 外接球:节点云质心为球心,最大距离为半径(含节点球/自环余量),复位与初始视角均基于它\r\n const bounds = useMemo(() => {\r\n const center = new THREE.Vector3(0, 0, 0)\r\n if (positions.length === 0) return { center, radius: 3 }\r\n for (const p of positions) center.add(p)\r\n center.divideScalar(positions.length)\r\n let r = 0\r\n for (const p of positions) r = Math.max(r, p.distanceTo(center))\r\n return { center, radius: r + 1.4 }\r\n }, [positions])\r\n\r\n // 默认视角(复位目标):外接球直径 ≈ 视口高度 2/3(d = 1.5R/tan(fov/2)),相机远在球外(d ≈ 3.2R > R)。\r\n // minRadius = 球外(视角不可进入外接球);maxRadius = 适配距离 3 倍\r\n const fitOrbit = useMemo(() => {\r\n const halfFov = ((camera as THREE.PerspectiveCamera).fov * Math.PI) / 360\r\n const dist = (bounds.radius * 1.5) / Math.tan(halfFov)\r\n return {\r\n theta: 0,\r\n phi: Math.acos(3 / Math.sqrt(3 ** 2 + 12 ** 2)),\r\n radius: dist,\r\n minRadius: Math.max(1.5, bounds.radius + 0.8),\r\n maxRadius: Math.max(30, dist * 3),\r\n target: bounds.center.clone(),\r\n }\r\n }, [bounds, camera])\r\n\r\n // latestFit 在每次渲染后同步,供复位与切群/切形状自动回正使用(避免 fitOrbit 对象身份波动触发)\r\n const latestFit = useRef(fitOrbit)\r\n useEffect(() => {\r\n latestFit.current = fitOrbit\r\n })\r\n const groupKey = `${group.symbol}|${group.order}`\r\n\r\n const resetCamera = useCallback(() => {\r\n const o = orbit.current\r\n const fit = latestFit.current\r\n o.theta = fit.theta\r\n o.phi = fit.phi\r\n o.radius = fit.radius\r\n o.target.copy(fit.target)\r\n }, [])\r\n\r\n // 切换群或切换 3D 形状时自动回到默认适配视角\r\n useEffect(() => {\r\n resetCamera()\r\n }, [groupKey, layout3D, resetCamera])\r\n\r\n useEffect(() => {\r\n if (locked) return\r\n const el = gl.domElement\r\n const onDown = (e: PointerEvent) => {\r\n dragState.current = { active: true, lastX: e.clientX, lastY: e.clientY, x: 0, y: 0, button: e.button }\r\n el.setPointerCapture?.(e.pointerId)\r\n }\r\n const onMove = (e: PointerEvent) => {\r\n const s = dragState.current\r\n if (!s.active) return\r\n const dx = e.clientX - s.lastX\r\n const dy = e.clientY - s.lastY\r\n s.lastX = e.clientX\r\n s.lastY = e.clientY\r\n s.x += dx\r\n s.y += dy\r\n const o = orbit.current\r\n if (s.button === 2) {\r\n // 右键平移 target:沿相机局部 right/up 平面移动,尺度随 radius\r\n const right = new THREE.Vector3().setFromMatrixColumn(camera.matrix, 0)\r\n const up = new THREE.Vector3().setFromMatrixColumn(camera.matrix, 1)\r\n o.target.addScaledVector(right, -dx * o.radius * 0.0012).addScaledVector(up, dy * o.radius * 0.0012)\r\n } else {\r\n // 左键旋转:与 OrbitControls 同约定(拖右 theta -=;拖下 phi -=),phi 无界可翻越极点\r\n o.theta -= dx * 0.006\r\n o.phi -= dy * 0.006\r\n }\r\n }\r\n const onUp = (e: PointerEvent) => {\r\n const s = dragState.current\r\n s.active = false\r\n if (Math.hypot(s.x, s.y) >= 8) dragVec.current = { x: s.x, y: s.y }\r\n el.releasePointerCapture?.(e.pointerId)\r\n }\r\n const onWheel = (e: WheelEvent) => {\r\n e.preventDefault()\r\n const o = orbit.current\r\n o.radius = Math.min(fitOrbit.maxRadius, Math.max(fitOrbit.minRadius, o.radius * Math.pow(0.95, -e.deltaY / 100)))\r\n }\r\n el.addEventListener('pointerdown', onDown)\r\n el.addEventListener('pointermove', onMove)\r\n el.addEventListener('pointerup', onUp)\r\n el.addEventListener('pointercancel', onUp)\r\n el.addEventListener('wheel', onWheel, { passive: false })\r\n return () => {\r\n el.removeEventListener('pointerdown', onDown)\r\n el.removeEventListener('pointermove', onMove)\r\n el.removeEventListener('pointerup', onUp)\r\n el.removeEventListener('pointercancel', onUp)\r\n el.removeEventListener('wheel', onWheel)\r\n }\r\n }, [gl, camera, fitOrbit, locked])\r\n\r\n // 按最后一次拖拽方向将角速度分解到 theta/phi 两个分量(与手动拖拽同约定:拖右 theta -=,拖下 phi -=),\r\n // 未拖拽过则默认绕竖轴(theta)旋转;拖拽含竖直分量时同步带动俯仰旋转——与 ▶ 自动旋转方向完全一致\r\n const applyOrbitRotation = (\r\n o: { theta: number; phi: number },\r\n angVel: number,\r\n delta: number,\r\n ) => {\r\n const d = dragVec.current\r\n const len = Math.hypot(d.x, d.y)\r\n if (len >= 8) {\r\n o.theta -= (d.x / len) * angVel * delta\r\n o.phi -= (d.y / len) * angVel * delta\r\n } else {\r\n o.theta -= angVel * delta\r\n }\r\n }\r\n\r\n // 由球坐标轨道写入相机(位置/up 极点翻转/lookAt):帧循环与 GIF 导出 frameAt 共用,保证画面与 GIF 帧一致\r\n const applyCameraFromOrbit = useCallback((o: { theta: number; phi: number; radius: number; target: THREE.Vector3 }) => {\r\n const sinP = Math.sin(o.phi)\r\n camera.position.set(\r\n o.target.x + o.radius * sinP * Math.sin(o.theta),\r\n o.target.y + o.radius * Math.cos(o.phi),\r\n o.target.z + o.radius * sinP * Math.cos(o.theta)\r\n )\r\n // 越过上下任一极点(sinφ 变号)时翻转 up,保持画面正立连续\r\n camera.up.set(0, sinP >= 0 ? 1 : -1, 0)\r\n camera.lookAt(o.target)\r\n }, [camera])\r\n\r\n // 每帧:手动拖拽的 theta/phi 已在 pointer 处理中直接更新;此处应用自动旋转增量并同步相机。\r\n // 球坐标 phi 无界(可无限翻越上下极点);GIF 导出期间角度由 frameAt 精确驱动,此处仅同步相机\r\n useFrame((_, delta) => {\r\n const o = orbit.current\r\n if (!o.initialized) {\r\n // 初始视角 = 复位适配视角(外接球居中、直径占视口高度 2/3、相机在球外)\r\n o.theta = fitOrbit.theta\r\n o.phi = fitOrbit.phi\r\n o.radius = fitOrbit.radius\r\n o.target.copy(fitOrbit.target)\r\n o.initialized = true\r\n }\r\n if (autoRotate) {\r\n // GIF 导出期间实时循环不受影响:导出相机独立离屏渲染,展示区照常按此速度旋转\r\n applyOrbitRotation(o, displayAngVel(), delta)\r\n }\r\n applyCameraFromOrbit(o)\r\n })\r\n\r\n useEffect(() => {\r\n const el = gl.domElement\r\n const onDoubleClick = () => resetCamera()\r\n el.addEventListener('dblclick', onDoubleClick)\r\n return () => el.removeEventListener('dblclick', onDoubleClick)\r\n }, [gl, resetCamera])\r\n\r\n // 仅主视口(.canvas-viewport 内)的 3D 实例注册到导出桥;浮动窗口实例不注册,避免覆盖\r\n useEffect(() => {\r\n if (!gl.domElement.closest('.canvas-viewport')) return\r\n const api: Cayley3DControlAPI = {\r\n isReady: () => true,\r\n snapshotOrbit: () => {\r\n const o = orbit.current\r\n return { theta: o.theta, phi: o.phi, radius: o.radius, target: o.target.clone() }\r\n },\r\n displayAngVel: () => displayAngVel(),\r\n beginRotation: (radPerSec) => {\r\n // 记录基准角/半径/目标,并创建独立离屏渲染器 + 相机(与实时轨道/相机完全隔离,\r\n // 导出期间展示区照常旋转;offline renderer 的 drawing buffer 与主视口同尺寸)\r\n const o = orbit.current\r\n const renderer = new THREE.WebGLRenderer({ antialias: false, preserveDrawingBuffer: true })\r\n renderer.setSize(gl.domElement.width, gl.domElement.height, false)\r\n const ecam = new THREE.PerspectiveCamera(\r\n (camera as THREE.PerspectiveCamera).fov,\r\n (camera as THREE.PerspectiveCamera).aspect,\r\n camera.near,\r\n camera.far\r\n )\r\n externalRotation.current = {\r\n active: true, radPerSec,\r\n baseTheta: o.theta, basePhi: o.phi,\r\n radius: o.radius, target: o.target.clone(),\r\n renderer, ecam,\r\n }\r\n // 预热渲染一次(编译离屏 GL 着色器并建立绘制流水线),首帧角度与 frameAt(0) 一致\r\n const sinP0 = Math.sin(o.phi)\r\n ecam.position.set(\r\n o.target.x + o.radius * sinP0 * Math.sin(o.theta),\r\n o.target.y + o.radius * Math.cos(o.phi),\r\n o.target.z + o.radius * sinP0 * Math.cos(o.theta)\r\n )\r\n ecam.up.set(0, sinP0 >= 0 ? 1 : -1, 0)\r\n ecam.lookAt(o.target)\r\n renderer.render(scene, ecam)\r\n },\r\n // GIF 导出的第 index 帧:按帧序号与帧延时精确计算角度(与实时渲染耗时无关,\r\n // 方向沿用最后一次拖拽分解),渲染到离屏 canvas 并返回供导出循环采集\r\n frameAt: (index, frameDelayMs) => {\r\n const e = externalRotation.current\r\n if (!e.active || !e.renderer || !e.ecam) return null\r\n const total = (e.radPerSec * index * frameDelayMs) / 1000\r\n const d = dragVec.current\r\n const len = Math.hypot(d.x, d.y)\r\n let theta: number\r\n let phi: number\r\n if (len >= 8) {\r\n theta = e.baseTheta - (d.x / len) * total\r\n phi = e.basePhi - (d.y / len) * total\r\n } else {\r\n theta = e.baseTheta - total\r\n phi = e.basePhi\r\n }\r\n const sinP = Math.sin(phi)\r\n e.ecam.position.set(\r\n e.target.x + e.radius * sinP * Math.sin(theta),\r\n e.target.y + e.radius * Math.cos(phi),\r\n e.target.z + e.radius * sinP * Math.cos(theta)\r\n )\r\n e.ecam.up.set(0, sinP >= 0 ? 1 : -1, 0)\r\n e.ecam.lookAt(e.target)\r\n e.renderer.render(scene, e.ecam)\r\n return e.renderer.domElement\r\n },\r\n endRotation: () => {\r\n // 实时轨道/相机全程未被触碰,无需恢复;仅释放离屏渲染器\r\n const e = externalRotation.current\r\n e.active = false\r\n e.renderer?.dispose()\r\n e.renderer = null\r\n e.ecam = null\r\n },\r\n }\r\n registerCayley3DControls(api)\r\n return () => unregisterCayley3DControls(api)\r\n }, [gl, scene, camera, displayAngVel])\r\n\r\n const elementLookup = useMemo(() => {\r\n const m = new Map<string, GroupElement>()\r\n for (const el of group.elements) m.set(el.id, el)\r\n return m\r\n }, [group])\r\n\r\n const faceOpacity = faceFill?.enabled === false ? 0 : (faceFill?.opacity ?? 0.45)\r\n // 子群陪集面:几何上成面的陪集 → 半透明凸多边形 mesh(fan 三角化,双面渲染)\r\n const faceMeshes = useMemo(() => {\r\n const subgroup = faceFill?.subgroup\r\n if (faceOpacity <= 0 || !subgroup || subgroup.length === 0) return []\r\n const edgeKeys = buildUndirectedEdgeKeys(cayleyEdges.map(e => [e.fromIdx, e.toIdx] as [number, number]))\r\n const faces = subgroupFaces(\r\n group,\r\n subgroup,\r\n positions.map(v => [v.x, v.y, v.z] as [number, number, number]),\r\n edgeKeys,\r\n )\r\n if (!faces || faces.length === 0) return []\r\n const idxOf = new Map(group.elements.map((e, i) => [e.id, i]))\r\n return faces.map((f, i) => {\r\n const pts = f.hullElementIds.map(id => positions[idxOf.get(id)!])\r\n const c = new THREE.Vector3(0, 0, 0)\r\n for (const p of pts) c.add(p)\r\n c.divideScalar(pts.length)\r\n const arr: number[] = []\r\n for (let k = 0; k < pts.length; k++) {\r\n const p0 = pts[k]\r\n const p1 = pts[(k + 1) % pts.length]\r\n arr.push(c.x, c.y, c.z, p0.x, p0.y, p0.z, p1.x, p1.y, p1.z)\r\n }\r\n const geo = new THREE.BufferGeometry()\r\n geo.setAttribute('position', new THREE.Float32BufferAttribute(arr, 3))\r\n geo.computeVertexNormals()\r\n const color = faceFill?.faceColors?.[f.key] ?? FACE_COLOR_PALETTE[i % FACE_COLOR_PALETTE.length]\r\n return { key: f.key, geometry: geo, color }\r\n })\r\n }, [group, faceFill, cayleyEdges, positions, faceOpacity])\r\n\r\n useEffect(() => {\r\n return () => {\r\n for (const fm of faceMeshes) fm.geometry.dispose()\r\n }\r\n }, [faceMeshes])\r\n\r\n const actionLabelMap = useMemo(() => {\r\n const m = new Map<string, string>()\r\n for (const a of actions) {\r\n const el = elementLookup.get(a.elementId)\r\n if (el) m.set(a.elementId, el.label)\r\n }\r\n return m\r\n }, [actions, elementLookup])\r\n\r\n const subsetOf = useMemo(() => {\r\n const m = new Map<string, { color: string }>()\r\n for (const s of subsetHighlights) {\r\n for (const id of s.elementIds) {\r\n if (!m.has(id)) m.set(id, s)\r\n }\r\n }\r\n return m\r\n }, [subsetHighlights])\r\n\r\n const edgeDataMap = useMemo(() => {\r\n const m = new Map<string, EdgeData>()\r\n const edgeBudget = isLargeGroup ? Math.max(60, group.order * 2) : Number.POSITIVE_INFINITY\r\n for (const edge of cayleyEdges) {\r\n if (isLargeGroup && !visibleElementIds.has(edge.fromId) && !visibleElementIds.has(edge.toId)) continue\r\n const key = `${Math.min(edge.fromIdx, edge.toIdx)}|${Math.max(edge.fromIdx, edge.toIdx)}|${edge.actionElementId}`\r\n if (!m.has(key)) {\r\n m.set(key, {\r\n fromIdx: edge.fromIdx,\r\n toIdx: edge.toIdx,\r\n fromId: edge.fromId,\r\n toId: edge.toId,\r\n fromPos: positions[edge.fromIdx],\r\n toPos: positions[edge.toIdx],\r\n gen: {\r\n name: edge.actionElementId,\r\n symbol: elementLookup.get(edge.actionElementId)?.label || '',\r\n color: edge.color,\r\n apply: () => group.elements[0],\r\n inverse: {} as Generator\r\n },\r\n isSelfLoop: edge.isSelfLoop,\r\n isBidirectional: edge.isBidirectional,\r\n })\r\n }\r\n if (m.size >= edgeBudget) break\r\n }\r\n return m\r\n }, [cayleyEdges, positions, group, isLargeGroup, visibleElementIds, elementLookup])\r\n\r\n return (\r\n <>\r\n <ambientLight intensity={0.3} />\r\n <directionalLight position={[10, 15, 10]} intensity={0.8} color=\"#ffffff\" />\r\n <directionalLight position={[-10, -5, -10]} intensity={0.3} color=\"#4488ff\" />\r\n <pointLight position={[0, 0, 0]} intensity={0.3} color=\"#ffffff\" />\r\n\r\n <Html fullscreen position={[0, 0, 0]} style={{ pointerEvents: 'none' }} wrapperClass=\"gv-html-fullscreen\">\r\n <div style={{\r\n position: 'absolute', top: 10, right: 10,\r\n display: 'flex', gap: 6, alignItems: 'center', pointerEvents: 'auto'\r\n }}>\r\n <div style={{\r\n background: 'var(--bg-tooltip)', color: 'var(--text-secondary)',\r\n padding: '6px 12px', borderRadius: 8, fontSize: 13,\r\n fontFamily: 'monospace', pointerEvents: 'none'\r\n }}>\r\n <span style={{ fontWeight: 'bold' }} dangerouslySetInnerHTML={{ __html: renderTex(texify(group.symbol)) }} />\r\n <span style={{ marginLeft: 8, color: 'var(--text-muted)' }}>|G| = {group.order}</span>\r\n </div>\r\n <button\r\n onClick={() => setAutoRotateState(v => !v)}\r\n title={t('cayley3d.autoRotate')}\r\n aria-label={t('cayley3d.autoRotate')}\r\n style={{\r\n background: 'var(--bg-tooltip)',\r\n color: autoRotate ? 'var(--accent-teal)' : 'var(--text-secondary)',\r\n border: autoRotate ? '1px solid var(--accent-teal)' : '1px solid var(--border-primary)',\r\n borderRadius: 8, padding: '6px 10px', fontSize: 13,\r\n cursor: 'pointer', fontFamily: 'monospace'\r\n }}\r\n >\r\n {autoRotate ? '❚❚' : '▶'}\r\n </button>\r\n <button\r\n onClick={resetCamera}\r\n title={t('cayley3d.resetView')}\r\n aria-label={t('cayley3d.resetView')}\r\n style={{\r\n background: 'var(--bg-tooltip)', color: 'var(--text-secondary)',\r\n border: '1px solid var(--border-primary)', borderRadius: 8, padding: '6px 10px',\r\n fontSize: 13, cursor: 'pointer', fontFamily: 'monospace'\r\n }}\r\n >\r\n ⟲\r\n </button>\r\n </div>\r\n </Html>\r\n\r\n {actions.length > 0 && (\r\n <Html fullscreen position={[0, 0, 0]} style={{ pointerEvents: 'none' }} wrapperClass=\"gv-html-fullscreen\">\r\n <div style={{\r\n position: 'absolute', top: 10, left: 10,\r\n background: 'var(--bg-tooltip)', color: 'var(--text-secondary)',\r\n padding: '8px 14px', borderRadius: 8, fontSize: 13,\r\n fontFamily: 'monospace', pointerEvents: 'none'\r\n }}>\r\n <div style={{ fontWeight: 'bold', marginBottom: 4 }}>\r\n {multiplyType === 'right' ? t('cayley3d.multiplyRight') : t('cayley3d.multiplyLeft')}\r\n </div>\r\n {actions.filter(a => a.enabled).map(action => {\r\n const label = actionLabelMap.get(action.elementId) || action.elementId\r\n return (\r\n <div key={action.elementId} style={{ display: 'flex', alignItems: 'center', gap: 6, marginTop: 2 }}>\r\n <span style={{ display: 'inline-block', width: 12, height: 3, background: action.color, borderRadius: 2 }} />\r\n <span dangerouslySetInnerHTML={{ __html: renderTex(texify(label)) }} />\r\n </div>\r\n )\r\n })}\r\n </div>\r\n </Html>\r\n )}\r\n\r\n {faceMeshes.map(fm => (\r\n <mesh key={fm.key} geometry={fm.geometry} renderOrder={-2}>\r\n <meshBasicMaterial color={fm.color} transparent opacity={faceOpacity} side={THREE.DoubleSide} depthWrite={false} />\r\n </mesh>\r\n ))}\r\n\r\n {Array.from(edgeDataMap.values()).map((edge) => {\r\n const fromEl = elementLookup.get(edge.fromId)\r\n const toEl = elementLookup.get(edge.toId)\r\n if (!fromEl || !toEl) return null\r\n const isHighlighted = (\r\n selectedElements.has(fromEl.id) ||\r\n selectedElements.has(toEl.id)\r\n )\r\n return (\r\n <EdgeLine\r\n key={`edge-${edge.fromIdx}-${edge.toIdx}`}\r\n start={edge.fromPos}\r\n end={edge.toPos}\r\n color={edge.gen.color}\r\n isHighlighted={isHighlighted}\r\n isSelfLoop={edge.isSelfLoop}\r\n isBidirectional={edge.isBidirectional}\r\n showArrow={!isLargeGroup}\r\n />\r\n )\r\n })}\r\n\r\n {positions.map((pos, i) => {\r\n const el = group.elements[i]\r\n if (isLargeGroup && !visibleElementIds.has(el.id)) return null\r\n const isSelected = selectedElements.has(el.id)\r\n const parentSubset = subsetOf.get(el.id)\r\n return (\r\n <NodeSphere\r\n key={el.id}\r\n position={pos}\r\n label={el.label}\r\n color={getElementColor(i, group.order, group.isAbelian)}\r\n isSelected={isSelected}\r\n isHovered={hoverElement?.id === el.id}\r\n subsetColor={parentSubset ? parentSubset.color : null}\r\n element={el}\r\n nodeScale={nodeScale}\r\n showLabel={showLabels}\r\n isDark={theme === 'dark'}\r\n onSelectElement={selectElement}\r\n onPointerEnter={setHoverElement}\r\n onPointerLeave={setHoverElement}\r\n />\r\n )\r\n })}\r\n\r\n </>\r\n )\r\n}\r\n\r\n/** 受控 3D 凯莱图(props 驱动;ViewWindow 与测试用)。空群渲染占位,非空渲染 R3F 场景。 */\r\nexport function Cayley3DScene(props: Cayley3DSceneProps) {\r\n const { group, theme: themeProp } = props\r\n const { t } = useTranslation()\r\n const { theme: ctxTheme } = useTheme()\r\n const theme = themeProp ?? ctxTheme\r\n\r\n if (!group) {\r\n return (\r\n <div className=\"view-empty\">\r\n <p>{t('canvas.noGroup')}</p>\r\n </div>\r\n )\r\n }\r\n\r\n const bgColor = theme === 'dark' ? '#0a0a1a' : '#f4f4f7'\r\n\r\n return (\r\n <div style={{ width: '100%', height: '100%', background: bgColor }}>\r\n <Canvas\r\n camera={{ position: [0, 3, 12], fov: 50, near: 0.1, far: 400 }}\r\n gl={{ antialias: true, alpha: false, preserveDrawingBuffer: true }}\r\n style={{ width: '100%', height: '100%' }}\r\n >\r\n <color attach=\"background\" args={[bgColor]} />\r\n <Cayley3DSceneBody {...props} group={group} theme={theme} />\r\n </Canvas>\r\n </div>\r\n )\r\n}\r\n\r\n/** 主应用入口(context 组装壳):从全局 Provider 组装 Cayley3DScene 所需 props(保留原行为) */","import { useLayoutEffect, useMemo, useRef, useState, type ReactNode } from 'react'\r\nimport { useTranslation } from '../../i18n/useTranslation'\r\nimport { useTheme } from '../../theme/useTheme'\r\nimport {\r\n computeSubgroupLattice,\r\n mergeLatticeByConjugacy,\r\n subgroupSetKey,\r\n subgroupStructureSymbol,\r\n getGroupCenter,\r\n type SubgroupLatticeNode,\r\n type SubgroupLatticeEdge,\r\n} from '../../core/algebra/subgroups'\r\nimport {\r\n computeLatticeLayout,\r\n latticeLodTier,\r\n latticeSlotScreenSize,\r\n latticeFitScale,\r\n} from '../../core/algebra/latticeLayout'\r\nimport { texify, renderTex } from '../../utils/texify'\r\nimport { factorizeOrder } from '../../core/algebra/sylow'\r\nimport type { SeriesType, SeriesFactor } from '../../core/algebra/series'\r\nimport type {\r\n CanvasTransform,\r\n Group,\r\n GroupElement,\r\n LatticeLabelDetail,\r\n LatticeLodTier,\r\n Subset,\r\n} from '../../core/types'\r\n\r\nconst SERIES_COLORS: Record<SeriesType, { light: string; dark: string }> = {\r\n derived: { light: '#b8860b', dark: '#ffd93d' },\r\n upperCentral: { light: '#0e7490', dark: '#22d3ee' },\r\n lowerCentral: { light: '#0e7490', dark: '#22d3ee' },\r\n composition: { light: '#7c3aed', dark: '#c084fc' },\r\n}\r\n\r\n/** compact 档胶囊 / dots 档圆点的期望屏幕尺寸(px,被槽位尺寸封顶故永不重叠) */\r\nconst COMPACT_PILL = { w: 104, h: 28, font: 13 }\r\nconst DOT_R = 8\r\nconst ORBIT_FONT = 11\r\n\r\n/** 屏幕恒定 px → 世界单位(受 cap 封顶,cap 用世界单位表示) */\r\nfunction toWorld(screenPx: number, eff: number, cap: number): number {\r\n return Math.min(screenPx / Math.max(eff, 1e-4), cap)\r\n}\r\n\r\n/** 轨道格节点上携带的附加字段(未合并时都不存在) */\r\ninterface OrbitFields {\r\n orbitSize?: number\r\n normalizerOrder?: number\r\n}\r\n\r\nexport interface LatticeData {\r\n nodes: SubgroupLatticeNode[]\r\n edges: SubgroupLatticeEdge[]\r\n}\r\n\r\n/** 子群列(Series)状态:由宿主组装后传入,内核只负责高亮与面板呈现 */\r\nexport interface SublatticeSeriesState {\r\n type: SeriesType\r\n /** 系列项的元素集合;null 表示后端仍在计算 / 超过守卫 */\r\n terms: GroupElement[][] | null\r\n factors?: SeriesFactor[] | null\r\n solvable?: boolean\r\n nilpotent?: boolean\r\n chainCount?: number\r\n truncated?: boolean\r\n loading?: boolean\r\n}\r\n\r\nexport interface SublatticeSceneProps {\r\n group: Group | null\r\n /** 外部提供则优先(大群后端通路);缺省内核对 order ≤ 60 自行枚举 */\r\n lattice?: LatticeData | null\r\n canvasTransform?: CanvasTransform\r\n /** 宿主可用像素尺寸;缺省由 ResizeObserver 实测自身容器 */\r\n availableSize?: { width: number; height: number }\r\n /** 名片细节档,缺省 'auto'(按槽位屏幕宽度自动降级) */\r\n labelDetail?: LatticeLabelDetail\r\n /** 共轭子群合并为轨道节点,缺省 false */\r\n mergeConjugates?: boolean\r\n /** 名片与层距的世界单位乘子,缺省 1 */\r\n nodeScale?: number\r\n /** 底部子群列面板,缺省 true */\r\n showSeriesPanel?: boolean\r\n series?: SublatticeSeriesState | null\r\n /** 群中心元素 id 列表(宿主已算好时传入,省一次本地计算) */\r\n centerIds?: string[]\r\n subsets?: Subset[]\r\n activeNodeIdx?: number | null\r\n onActivateNode?: (idx: number | null, node: SubgroupLatticeNode | null) => void\r\n noGroupText?: string\r\n /** 渲染主题(格取色 palette)。缺省回落到 ThemeContext(无 Provider 时 'dark');\r\n * 主应用壳不传即保持现状(读全局主题),包消费端显式传以与容器主题解耦 */\r\n theme?: 'dark' | 'light'\r\n /** 本地枚举子群格的群阶上限(`order > 该值` 且未显式传 `lattice` 时不枚举、渲染空态);\r\n * 缺省 60(与 `findAllSubgroups` 内建守卫一致)。放开需自行确认性能与后端通路 */\r\n maxEnumerateOrder?: number\r\n}\r\n\r\nfunction buildPalette(theme: string) {\r\n if (theme === 'light') {\r\n return {\r\n edge: '#a9adbc',\r\n edgeOpacity: 0.95,\r\n edgeWidth: 2.5,\r\n pathEdge: '#d4a017',\r\n pathEdgeWidth: 4,\r\n nodeFill: '#eef1f5',\r\n nodeStroke: '#2d8f85',\r\n nodeStrokeNormal: '#7c5cc0',\r\n nodeText: '#1c1c28',\r\n nodeSubText: '#5a5a6a',\r\n pathFill: '#fbf1d0',\r\n pathStroke: '#d4a017',\r\n pathText: '#7a5d00',\r\n pathSubText: '#8a6d00cc',\r\n activeFill: '#d8ecda',\r\n trivialFill: '#e8e8f1',\r\n trivialStroke: '#9a9ab0',\r\n fullFill: '#e7edf7',\r\n fullStroke: '#3a6fb0',\r\n centerFill: '#fdf3c7',\r\n centerStroke: '#b8860b',\r\n sylowText: '#c2410c',\r\n dotPlain: '#8d93a8',\r\n seriesBadgeText: '#fff',\r\n }\r\n }\r\n return {\r\n edge: '#4a4a7a',\r\n edgeOpacity: 0.85,\r\n edgeWidth: 2.5,\r\n pathEdge: '#ffd93d',\r\n pathEdgeWidth: 4,\r\n nodeFill: '#151f1a',\r\n nodeStroke: '#3ea89e',\r\n nodeStrokeNormal: '#8968c8',\r\n nodeText: '#ddd',\r\n nodeSubText: '#777',\r\n pathFill: '#1e3a1e',\r\n pathStroke: '#ffd93d',\r\n pathText: '#ffd93d',\r\n pathSubText: '#ffd93dcc',\r\n activeFill: '#2a4a2a',\r\n trivialFill: '#1a1a2e',\r\n trivialStroke: '#555',\r\n fullFill: '#1a1f30',\r\n fullStroke: '#5588cc',\r\n centerFill: '#3a3020',\r\n centerStroke: '#ffd93d',\r\n sylowText: '#fb923c',\r\n dotPlain: '#6b7280',\r\n seriesBadgeText: '#111',\r\n }\r\n}\r\n\r\n/** 邻接表(无向)——只建一次,路径搜索不再每 pop 扫全边表 */\r\nfunction buildAdjacency(nodeCount: number, edges: SubgroupLatticeEdge[]): number[][] {\r\n const adj: number[][] = Array.from({ length: nodeCount }, () => [])\r\n for (const e of edges) {\r\n if (e.from >= 0 && e.from < nodeCount && e.to >= 0 && e.to < nodeCount) {\r\n adj[e.from].push(e.to)\r\n adj[e.to].push(e.from)\r\n }\r\n }\r\n return adj\r\n}\r\n\r\nfunction findPath(adjacency: number[][], start: number, end: number): number[] | null {\r\n if (start === end) return [start]\r\n const visited = new Set<number>()\r\n const queue: number[][] = [[start]]\r\n while (queue.length > 0) {\r\n const path = queue.shift()!\r\n const last = path[path.length - 1]\r\n if (last === end) return path\r\n if (visited.has(last)) continue\r\n visited.add(last)\r\n for (const nb of adjacency[last] ?? []) {\r\n if (!visited.has(nb)) queue.push([...path, nb])\r\n }\r\n }\r\n return null\r\n}\r\n\r\n// ────────────────────────── Series 面板(纯呈现) ──────────────────────────\r\n\r\ninterface SeriesPanelProps {\r\n group: Group\r\n series: SublatticeSeriesState\r\n color: string | null\r\n /** 渲染主题(徽标深浅色)。缺省回落到 ThemeContext */\r\n theme?: 'dark' | 'light'\r\n}\r\n\r\n/** 子群列链式展示:N₀ ⊵ N₁ ⊵ … + 各级阶 + 因子 + 可解/幂零徽标(由原视图内联 JSX 迁出) */\r\nexport function SeriesPanel({ group, series, color, theme: themeProp }: SeriesPanelProps) {\r\n const { t } = useTranslation()\r\n const { theme: ctxTheme } = useTheme()\r\n const theme = themeProp ?? ctxTheme\r\n const { type, terms, factors, solvable, nilpotent, chainCount, truncated, loading } = series\r\n\r\n const chainTeX = terms\r\n ? terms.map((term, ti) => {\r\n const label = term.length === 1\r\n ? '\\\\langle e \\\\rangle'\r\n : term.length === group.order\r\n ? texify(group.symbol)\r\n : `N_{${ti}}`\r\n return (ti === 0 ? '' : ' \\\\trianglerighteq ') + label\r\n }).join('')\r\n : ''\r\n const ordersTeX = terms\r\n ? terms.map((term, ti) => `|N_{${ti}}| = ${term.length}`).join(',\\\\;')\r\n : ''\r\n const factorsTeX = factors\r\n ? factors.map((f, i) => `N_{${i}}/N_{${i + 1}} \\\\cong ${f.label}`).join(',\\\\;')\r\n : ''\r\n const multisetText = factors\r\n ? [...factors]\r\n .sort((a, b) => a.order - b.order || a.label.localeCompare(b.label))\r\n .map(f => f.label)\r\n .join(', ')\r\n : ''\r\n\r\n const chipSolvable = theme === 'light' ? '#15803d' : '#4ade80'\r\n const chipNilpotent = theme === 'light' ? '#0369a1' : '#38bdf8'\r\n\r\n return (\r\n <div\r\n className=\"series-panel\"\r\n style={{\r\n borderTop: '1px solid var(--border-primary)',\r\n background: 'var(--bg-panel)',\r\n padding: '8px 12px',\r\n fontSize: 12,\r\n overflowX: 'auto',\r\n flexShrink: 0,\r\n }}\r\n >\r\n {terms ? (\r\n <>\r\n <div style={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: '4px 14px' }}>\r\n <span style={{ fontWeight: 600, color: color ?? undefined }}>{t(`series.${type}`)}</span>\r\n <span dangerouslySetInnerHTML={{ __html: renderTex(chainTeX) }} />\r\n </div>\r\n <div style={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: '4px 14px', marginTop: 3 }}>\r\n <span style={{ color: 'var(--text-muted)' }} dangerouslySetInnerHTML={{ __html: renderTex(ordersTeX) }} />\r\n </div>\r\n {factors && factors.length > 0 && (\r\n <div style={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: '4px 14px', marginTop: 3 }}>\r\n <span dangerouslySetInnerHTML={{ __html: renderTex(factorsTeX) }} />\r\n </div>\r\n )}\r\n <div style={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 8, marginTop: 5 }}>\r\n {solvable && (\r\n <span style={{ border: `1px solid ${chipSolvable}`, color: chipSolvable, borderRadius: 10, padding: '1px 8px', fontSize: 11 }}>{t('series.solvable')}</span>\r\n )}\r\n {nilpotent && (\r\n <span style={{ border: `1px solid ${chipNilpotent}`, color: chipNilpotent, borderRadius: 10, padding: '1px 8px', fontSize: 11 }}>{t('series.nilpotent')}</span>\r\n )}\r\n {type === 'composition' && factors && factors.length > 0 && (\r\n <>\r\n <span style={{ color: 'var(--text-muted)' }}>{t('series.factors')}: {multisetText}</span>\r\n <span style={{ color: 'var(--text-muted)' }}>{t('series.jordanHolder')}</span>\r\n </>\r\n )}\r\n {type === 'composition' && chainCount !== undefined && chainCount > 1 && (\r\n <span style={{ color: 'var(--text-muted)' }}>{t('series.alternativeChains', { n: String(chainCount) })}</span>\r\n )}\r\n {type === 'composition' && truncated && (\r\n <span style={{ color: 'var(--accent-yellow-text)' }}>{t('series.truncated')}</span>\r\n )}\r\n </div>\r\n </>\r\n ) : (\r\n <span style={{ color: 'var(--text-muted)' }}>\r\n {loading ? t('series.loading') : t('series.tooLarge')}\r\n </span>\r\n )}\r\n </div>\r\n )\r\n}\r\n\r\n// ────────────────────────── 受控内核 ──────────────────────────\r\n\r\n/**\r\n * 子群格受控内核(FGVE 阶段 2 批次三)。\r\n *\r\n * 小窗口里的可读性靠三件事:\r\n * 1. 布局世界坐标紧贴内容(`computeLatticeLayout`,无 1000×600 下限),适配缩放\r\n * 钳 ≤ 1,故主画布不会被撑大、小窗也不会被 letterbox 到不可读;\r\n * 2. 名片按\"槽位屏幕宽度\"自动降级 full → compact → dots;compact/dots 的几何按\r\n * `1/eff` 反算为屏幕恒定大小,同时被槽位宽封顶,所以在任何密度下都不重叠;\r\n * 3. 省掉的文字不丢——底部 caption 行按 hover ?? 选中给出完整名片;密度真的高时\r\n * 用 `mergeConjugates` 把共轭子群合成一个轨道节点(×n,n = |G : N_G(H)|)。\r\n */\r\nexport function SublatticeScene({\r\n group,\r\n lattice,\r\n canvasTransform,\r\n availableSize,\r\n labelDetail = 'auto',\r\n mergeConjugates = false,\r\n nodeScale = 1,\r\n showSeriesPanel = true,\r\n series = null,\r\n centerIds,\r\n subsets,\r\n activeNodeIdx: activeNodeIdxProp,\r\n onActivateNode,\r\n noGroupText,\r\n theme: themeProp,\r\n maxEnumerateOrder = 60,\r\n}: SublatticeSceneProps) {\r\n const { t } = useTranslation()\r\n const { theme: ctxTheme } = useTheme()\r\n const theme = themeProp ?? ctxTheme\r\n const palette = useMemo(() => buildPalette(theme), [theme])\r\n\r\n // 绘图区可用像素(不含 caption/series 面板):优先外部 availableSize,否则实测 svg 自身。\r\n // svg 必须是宿主的直接 flex 子元素并用 getBoundingClientRect 测量——若外面再包一层\r\n // div,svg 会按 viewBox 宽高比反推自身高度而撑破窗口。测得 0 → fit 视为 1。\r\n const svgHostRef = useRef<SVGSVGElement | null>(null)\r\n const [measured, setMeasured] = useState({ width: 0, height: 0 })\r\n useLayoutEffect(() => {\r\n const el = svgHostRef.current\r\n if (!el) return\r\n const update = () => {\r\n const r = el.getBoundingClientRect()\r\n setMeasured({ width: r.width, height: r.height })\r\n }\r\n update()\r\n if (typeof ResizeObserver === 'undefined') return\r\n const ro = new ResizeObserver(update)\r\n ro.observe(el)\r\n return () => ro.disconnect()\r\n }, [group?.symbol])\r\n const availW = availableSize?.width ?? measured.width\r\n const availH = availableSize?.height ?? measured.height\r\n\r\n const ct: CanvasTransform = canvasTransform ?? { x: 0, y: 0, scale: 1 }\r\n\r\n const baseLattice = useMemo<LatticeData | null>(() => {\r\n if (lattice !== undefined) return lattice\r\n if (!group || group.order > maxEnumerateOrder) return null\r\n return computeSubgroupLattice(group)\r\n }, [group, lattice, maxEnumerateOrder])\r\n\r\n // 共轭轨道合并:mergedOf[原下标] = 轨道格下标(未合并时 null)\r\n const { viewNodes, viewEdges, mergedOf, mergeUnavailable } = useMemo(() => {\r\n if (!baseLattice) {\r\n return {\r\n viewNodes: [] as SubgroupLatticeNode[],\r\n viewEdges: [] as SubgroupLatticeEdge[],\r\n mergedOf: null as number[] | null,\r\n mergeUnavailable: false,\r\n }\r\n }\r\n const identity = {\r\n viewNodes: baseLattice.nodes,\r\n viewEdges: baseLattice.edges,\r\n mergedOf: null as number[] | null,\r\n mergeUnavailable: false,\r\n }\r\n if (!mergeConjugates || !group) return identity\r\n const merged = mergeLatticeByConjugacy(group, baseLattice.nodes, baseLattice.edges)\r\n if (!merged) return { ...identity, mergeUnavailable: true }\r\n return {\r\n viewNodes: merged.nodes as SubgroupLatticeNode[],\r\n viewEdges: merged.edges,\r\n mergedOf: merged.orbitOf,\r\n mergeUnavailable: false,\r\n }\r\n }, [baseLattice, mergeConjugates, group])\r\n\r\n const layout = useMemo(\r\n () => computeLatticeLayout(viewNodes, viewEdges, { nodeScale }),\r\n [viewNodes, viewEdges, nodeScale]\r\n )\r\n\r\n // 疏密/降档推导:一次算好放进同一个 memo,避免逐帧重算的裸值进下游 memo 依赖\r\n const density = useMemo(() => {\r\n const fit = latticeFitScale(availW, availH, layout.viewW, layout.viewH)\r\n const eff = fit * ct.scale\r\n const { slotScreenWidth, rowScreenHeight } = latticeSlotScreenSize(\r\n layout.slotW, layout.rowH, fit, ct.scale\r\n )\r\n const tier: LatticeLodTier = labelDetail === 'auto'\r\n ? latticeLodTier(slotScreenWidth, rowScreenHeight)\r\n : labelDetail\r\n const edgeWidth = tier === 'full'\r\n ? palette.edgeWidth\r\n : toWorld(1.7, eff, layout.nodeRx * 0.1)\r\n return { fit, eff, slotScreenWidth, rowScreenHeight, tier, edgeWidth }\r\n }, [availW, availH, layout, ct.scale, labelDetail, palette])\r\n const { eff, slotScreenWidth, tier, edgeWidth } = density\r\n\r\n const { fullIdx, trivialIdx } = useMemo(() => {\r\n const order = group?.order ?? 0\r\n return {\r\n fullIdx: viewNodes.findIndex(nd => nd.order === order),\r\n trivialIdx: viewNodes.findIndex(nd => nd.order === 1),\r\n }\r\n }, [viewNodes, group])\r\n\r\n const centerSet = useMemo(() => {\r\n if (centerIds) return new Set(centerIds)\r\n if (!group || group.order > maxEnumerateOrder) return null\r\n return new Set(getGroupCenter(group).map(e => e.id))\r\n }, [group, centerIds, maxEnumerateOrder])\r\n\r\n const centerIdx = useMemo(() => {\r\n if (!centerSet || centerSet.size === 0) return -1\r\n return viewNodes.findIndex(nd => {\r\n if (nd.elementIds.length !== centerSet.size) return false\r\n return nd.elementIds.every(id => centerSet.has(id))\r\n })\r\n }, [viewNodes, centerSet])\r\n\r\n const sylowOrderToP = useMemo(() => {\r\n const map = new Map<number, number>()\r\n if (!group) return map\r\n for (const { prime, exponent } of factorizeOrder(group.order)) {\r\n let pPower = 1\r\n for (let i = 0; i < exponent; i++) pPower *= prime\r\n map.set(pPower, prime)\r\n }\r\n return map\r\n }, [group])\r\n\r\n const [activeNodeIdxState, setActiveNodeIdxState] = useState<number | null>(null)\r\n const activeNodeIdx = activeNodeIdxProp ?? activeNodeIdxState\r\n const [hoverIdx, setHoverIdx] = useState<number | null>(null)\r\n\r\n const adjacency = useMemo(\r\n () => buildAdjacency(viewNodes.length, viewEdges),\r\n [viewNodes, viewEdges]\r\n )\r\n\r\n const pathIndices = useMemo(() => {\r\n if (activeNodeIdx === null || viewNodes.length === 0) return new Set<number>()\r\n const set = new Set<number>()\r\n const upPath = fullIdx >= 0 ? findPath(adjacency, activeNodeIdx, fullIdx) : null\r\n const downPath = trivialIdx >= 0 ? findPath(adjacency, activeNodeIdx, trivialIdx) : null\r\n if (upPath) upPath.forEach(i => set.add(i))\r\n if (downPath) downPath.forEach(i => set.add(i))\r\n return set\r\n }, [activeNodeIdx, adjacency, fullIdx, trivialIdx, viewNodes])\r\n\r\n const pathEdgeSet = useMemo(() => {\r\n const set = new Set<number>()\r\n if (pathIndices.size === 0) return set\r\n for (let ei = 0; ei < viewEdges.length; ei++) {\r\n const e = viewEdges[ei]\r\n if (pathIndices.has(e.from) && pathIndices.has(e.to)) set.add(ei)\r\n }\r\n return set\r\n }, [pathIndices, viewEdges])\r\n\r\n const seriesColor = useMemo(() => {\r\n if (!series) return null\r\n const c = SERIES_COLORS[series.type]\r\n return theme === 'light' ? c.light : c.dark\r\n }, [series, theme])\r\n\r\n // 元素集合键 → 视图节点下标:合并态把轨道每个成员的键都指回该轨道节点,\r\n // 于是共轭但非相等的系列项仍能命中(D6)\r\n const keyToNodeIdx = useMemo(() => {\r\n const map = new Map<string, number>()\r\n if (!baseLattice) return map\r\n baseLattice.nodes.forEach((nd, i) => {\r\n const k = subgroupSetKey(nd.elementIds)\r\n if (!map.has(k)) map.set(k, mergedOf ? mergedOf[i] : i)\r\n })\r\n return map\r\n }, [baseLattice, mergedOf])\r\n\r\n const seriesNodeMap = useMemo(() => {\r\n const map = new Map<number, number>()\r\n if (!series?.terms) return map\r\n series.terms.forEach((term, ti) => {\r\n const ni = keyToNodeIdx.get(subgroupSetKey(term.map(e => e.id)))\r\n if (ni !== undefined && !map.has(ni)) map.set(ni, ti)\r\n })\r\n return map\r\n }, [series, keyToNodeIdx])\r\n\r\n const seriesNodeSet = useMemo(() => new Set(seriesNodeMap.keys()), [seriesNodeMap])\r\n\r\n const edgeElements = useMemo(() => {\r\n // 节点实际渲染高度按 tier 选:full 用 layout 默认矩形高度,compact 胶囊和 dots 圆点\r\n // 都是屏幕恒定像素,所以线段 y 偏移要用对应的世界单位——否则 compact/dots 下偏移过大,\r\n // 线段终点落到节点外侧\"线头\",看着像没对齐。\r\n const edgeNodeHalfH = tier === 'compact'\r\n ? toWorld(COMPACT_PILL.h / 2, eff, layout.nodeRy * 0.9)\r\n : tier === 'dots'\r\n ? toWorld(DOT_R, eff, layout.nodeRx * 0.42)\r\n : layout.nodeRy\r\n return viewEdges.map((edge, i) => {\r\n const fromPos = layout.positions[edge.from]\r\n const toPos = layout.positions[edge.to]\r\n if (!fromPos || !toPos) return null\r\n const onPath = pathEdgeSet.has(i)\r\n return (\r\n <line\r\n key={`edge-${i}`}\r\n x1={fromPos.x}\r\n y1={fromPos.y + edgeNodeHalfH}\r\n x2={toPos.x}\r\n y2={toPos.y - edgeNodeHalfH}\r\n stroke={onPath ? palette.pathEdge : palette.edge}\r\n strokeWidth={onPath ? Math.max(palette.pathEdgeWidth, edgeWidth) : edgeWidth}\r\n opacity={onPath ? 1 : tier === 'dots' ? 0.75 : palette.edgeOpacity}\r\n />\r\n )\r\n })\r\n }, [viewEdges, layout, pathEdgeSet, palette, tier, edgeWidth, eff])\r\n\r\n const subsetSets = useMemo(\r\n () => (subsets ?? []).map(s => ({ color: s.color, set: new Set(s.elementIds) })),\r\n [subsets]\r\n )\r\n\r\n const nodeElements = useMemo(() => {\r\n return viewNodes.map((node, i) => {\r\n const pos = layout.positions[i]\r\n if (!pos) return null\r\n\r\n const orbitSize = (node as SubgroupLatticeNode & OrbitFields).orbitSize ?? 1\r\n const onPath = pathIndices.has(i)\r\n const isActive = activeNodeIdx === i\r\n const isTrivial = node.order === 1\r\n const isFull = node.order === (group?.order ?? 0)\r\n const isCenter = i === centerIdx\r\n const sylowP = node.order > 1 ? sylowOrderToP.get(node.order) : undefined\r\n const termIdx = seriesNodeMap.get(i)\r\n const isDimmed = !!series?.terms && termIdx === undefined && !seriesNodeSet.has(i)\r\n\r\n let fillColor = palette.nodeFill\r\n let strokeColor = node.isNormal ? palette.nodeStrokeNormal : palette.nodeStroke\r\n let strokeWidth = 2.5\r\n let textColor = palette.nodeText\r\n\r\n if (onPath && !(termIdx !== undefined && seriesColor)) {\r\n fillColor = palette.pathFill\r\n strokeColor = palette.pathStroke\r\n strokeWidth = 4\r\n textColor = palette.pathText\r\n }\r\n if (isActive) {\r\n fillColor = palette.activeFill\r\n strokeWidth = 4\r\n }\r\n if (isCenter && !onPath) {\r\n fillColor = palette.centerFill\r\n strokeColor = palette.centerStroke\r\n }\r\n if (isTrivial && !onPath) {\r\n fillColor = palette.trivialFill\r\n strokeColor = palette.trivialStroke\r\n strokeWidth = 2\r\n }\r\n if (isFull && !onPath) {\r\n fillColor = palette.fullFill\r\n strokeColor = palette.fullStroke\r\n }\r\n if (termIdx !== undefined && seriesColor) {\r\n strokeColor = seriesColor\r\n strokeWidth = tier === 'full'\r\n ? 4\r\n : Math.max(toWorld(3, eff, layout.nodeRx * 0.1), edgeWidth)\r\n }\r\n\r\n const parentSubset = subsetSets.find(ss => node.elementIds.every(eid => ss.set.has(eid)))\r\n\r\n const handlers = {\r\n onMouseDown: (e: React.MouseEvent) => e.stopPropagation(),\r\n onClick: (e: React.MouseEvent) => {\r\n e.stopPropagation()\r\n if (activeNodeIdx === i) {\r\n setActiveNodeIdxState(null)\r\n onActivateNode?.(null, null)\r\n } else {\r\n setActiveNodeIdxState(i)\r\n onActivateNode?.(i, node)\r\n }\r\n },\r\n onMouseEnter: () => setHoverIdx(i),\r\n onMouseLeave: () => setHoverIdx(cur => (cur === i ? null : cur)),\r\n }\r\n const groupStyle = { cursor: 'pointer', opacity: isDimmed ? 0.22 : 1 }\r\n\r\n // ── dots:屏幕恒定圆点,类别靠颜色编码,×n 与系列命中保留 ──\r\n if (tier === 'dots') {\r\n const r = toWorld(DOT_R, eff, layout.nodeRx * 0.42)\r\n const dotFill = termIdx !== undefined && seriesColor\r\n ? seriesColor\r\n : isCenter\r\n ? palette.centerStroke\r\n : sylowP !== undefined\r\n ? palette.sylowText\r\n : isFull\r\n ? palette.fullStroke\r\n : isTrivial\r\n ? palette.trivialStroke\r\n : node.isNormal\r\n ? palette.nodeStrokeNormal\r\n : palette.dotPlain\r\n return (\r\n <g key={node.id} transform={`translate(${pos.x}, ${pos.y})`} style={groupStyle} data-lattice-node={i} {...handlers}>\r\n <circle cx={0} cy={0} r={toWorld(14, eff, layout.nodeRx)} fill=\"transparent\" stroke=\"none\" />\r\n <circle\r\n cx={0}\r\n cy={0}\r\n r={r}\r\n fill={onPath ? palette.pathFill : dotFill}\r\n stroke={onPath ? palette.pathStroke : dotFill}\r\n strokeWidth={onPath || isActive ? toWorld(2.5, eff, r) : 0}\r\n />\r\n {orbitSize > 1 && (\r\n <text\r\n x={r + toWorld(3, eff, layout.nodeRx * 0.2)}\r\n y={toWorld(-3, eff, layout.nodeRy * 0.5)}\r\n textAnchor=\"start\"\r\n fill={palette.nodeSubText}\r\n fontSize={toWorld(ORBIT_FONT, eff, layout.nodeRx * 0.6)}\r\n fontFamily=\"monospace\"\r\n style={{ pointerEvents: 'none', userSelect: 'none' }}\r\n >\r\n ×{orbitSize}\r\n </text>\r\n )}\r\n </g>\r\n )\r\n }\r\n\r\n // ── compact:屏幕恒定胶囊,只留一行(结构阶数字 / ×n / 顶层群符号) ──\r\n if (tier === 'compact') {\r\n const hw = toWorld(COMPACT_PILL.w / 2, eff, layout.nodeRx * 0.94)\r\n const hh = toWorld(COMPACT_PILL.h / 2, eff, layout.nodeRy * 0.9)\r\n const fs = toWorld(COMPACT_PILL.font, eff, layout.nodeRx * 0.5)\r\n return (\r\n <g key={node.id} transform={`translate(${pos.x}, ${pos.y})`} style={groupStyle} data-lattice-node={i} {...handlers}>\r\n <rect\r\n x={-hw}\r\n y={-hh}\r\n width={hw * 2}\r\n height={hh * 2}\r\n rx={hh}\r\n ry={hh}\r\n fill={fillColor}\r\n stroke={strokeColor}\r\n strokeWidth={strokeWidth}\r\n />\r\n {parentSubset && !onPath && (\r\n <rect x={-hw} y={-hh} width={hw * 2} height={hh * 2} rx={hh} ry={hh} fill={`${parentSubset.color}22`} stroke=\"none\" />\r\n )}\r\n <text\r\n y={fs * 0.36}\r\n textAnchor=\"middle\"\r\n fill={textColor}\r\n fontSize={fs}\r\n fontWeight={isActive ? 'bold' : 'normal'}\r\n fontFamily=\"monospace\"\r\n style={{ pointerEvents: 'none', userSelect: 'none' }}\r\n >\r\n {isTrivial\r\n ? 'e'\r\n : isFull\r\n ? ''\r\n : `${node.order}`}\r\n </text>\r\n {orbitSize > 1 && !isFull && (\r\n <text\r\n x={hw - fs * 0.35}\r\n y={fs * 0.36}\r\n textAnchor=\"end\"\r\n fill={palette.nodeSubText}\r\n fontSize={fs * 0.85}\r\n fontFamily=\"monospace\"\r\n style={{ pointerEvents: 'none', userSelect: 'none' }}\r\n >\r\n ×{orbitSize}\r\n </text>\r\n )}\r\n {isFull && group && (\r\n <foreignObject\r\n x={-hw}\r\n y={-hh}\r\n width={hw * 2}\r\n height={hh * 2}\r\n style={{ pointerEvents: 'none', userSelect: 'none' }}\r\n >\r\n <div\r\n style={{\r\n display: 'flex', alignItems: 'center', justifyContent: 'center',\r\n width: '100%', height: '100%', color: textColor, fontSize: fs,\r\n }}\r\n dangerouslySetInnerHTML={{ __html: renderTex(texify(group.symbol)) }}\r\n />\r\n </foreignObject>\r\n )}\r\n {termIdx !== undefined && seriesColor && (\r\n <circle cx={-hw + hh * 0.55} cy={0} r={hh * 0.3} fill={seriesColor} stroke=\"none\" style={{ pointerEvents: 'none' }} />\r\n )}\r\n {isCenter && (\r\n <circle cx={hw - hh * 0.55} cy={0} r={hh * 0.3} fill={palette.centerStroke} stroke=\"none\" style={{ pointerEvents: 'none' }} />\r\n )}\r\n </g>\r\n )\r\n }\r\n\r\n // ── full:完整名片(与 props 化之前的主画布一致) ──\r\n const nodeRx = layout.nodeRx\r\n const nodeRy = layout.nodeRy\r\n return (\r\n <g key={node.id} transform={`translate(${pos.x}, ${pos.y})`} style={groupStyle} data-lattice-node={i} {...handlers}>\r\n <rect\r\n x={-nodeRx}\r\n y={-nodeRy}\r\n width={nodeRx * 2}\r\n height={nodeRy * 2}\r\n rx={12}\r\n ry={12}\r\n fill={fillColor}\r\n stroke={strokeColor}\r\n strokeWidth={strokeWidth}\r\n />\r\n {parentSubset && !onPath && (\r\n <rect\r\n x={-nodeRx}\r\n y={-nodeRy}\r\n width={nodeRx * 2}\r\n height={nodeRy * 2}\r\n rx={12}\r\n ry={12}\r\n fill={`${parentSubset.color}22`}\r\n stroke=\"none\"\r\n />\r\n )}\r\n <text\r\n y={-8}\r\n textAnchor=\"middle\"\r\n fill={textColor}\r\n fontSize=\"15px\"\r\n fontWeight={isActive ? 'bold' : 'normal'}\r\n fontFamily=\"monospace\"\r\n style={{ pointerEvents: 'none', userSelect: 'none' }}\r\n >\r\n {isTrivial ? '⟨e⟩' : isFull ? '' : orbitSize > 1 ? `|H|=${node.order} ×${orbitSize}` : `|H|=${node.order}`}\r\n </text>\r\n {isCenter && (\r\n <text\r\n x={nodeRx - 6}\r\n y={-nodeRy + 12}\r\n textAnchor=\"end\"\r\n fill={palette.centerStroke}\r\n fontSize={10}\r\n fontWeight=\"bold\"\r\n fontFamily=\"monospace\"\r\n style={{ pointerEvents: 'none', userSelect: 'none' }}\r\n >\r\n Z(G)\r\n </text>\r\n )}\r\n {sylowP !== undefined && (\r\n <text\r\n x={-nodeRx + 6}\r\n y={-nodeRy + 12}\r\n textAnchor=\"start\"\r\n fill={palette.sylowText}\r\n fontSize={10}\r\n fontWeight=\"bold\"\r\n fontFamily=\"monospace\"\r\n style={{ pointerEvents: 'none', userSelect: 'none' }}\r\n >\r\n {t('lattice.sylow', { p: String(sylowP) })}\r\n </text>\r\n )}\r\n {termIdx !== undefined && seriesColor && (\r\n <g style={{ pointerEvents: 'none' }}>\r\n <circle cx={-nodeRx + 12} cy={nodeRy - 12} r={9} fill={seriesColor} stroke=\"none\" />\r\n <text\r\n x={-nodeRx + 12}\r\n y={nodeRy - 8}\r\n textAnchor=\"middle\"\r\n fontSize=\"10\"\r\n fontWeight=\"bold\"\r\n fill={palette.seriesBadgeText}\r\n fontFamily=\"monospace\"\r\n >\r\n {termIdx}\r\n </text>\r\n </g>\r\n )}\r\n {isFull && group && (\r\n <foreignObject\r\n x={-nodeRx + 6}\r\n y={-nodeRy + 2}\r\n width={nodeRx * 2 - 12}\r\n height={nodeRy * 2 - 4}\r\n style={{ pointerEvents: 'none', userSelect: 'none' }}\r\n >\r\n <div\r\n style={{\r\n display: 'flex', alignItems: 'center', justifyContent: 'center',\r\n width: '100%', height: '100%', color: textColor, fontSize: '15px',\r\n }}\r\n dangerouslySetInnerHTML={{ __html: renderTex(texify(group.symbol)) }}\r\n />\r\n </foreignObject>\r\n )}\r\n <text\r\n y={13}\r\n textAnchor=\"middle\"\r\n fill={onPath ? palette.pathSubText : node.isNormal ? palette.nodeStrokeNormal : palette.nodeSubText}\r\n fontSize=\"11px\"\r\n fontFamily=\"monospace\"\r\n style={{ pointerEvents: 'none', userSelect: 'none' }}\r\n >\r\n {isTrivial\r\n ? t('lattice.trivial')\r\n : isFull\r\n ? `|G|=${group?.order ?? ''}`\r\n : node.isNormal\r\n ? `◁ ${t('badge.normal')}`\r\n : t('lattice.subgroup')}\r\n </text>\r\n </g>\r\n )\r\n })\r\n }, [\r\n viewNodes, layout, pathIndices, activeNodeIdx, group, centerIdx, sylowOrderToP,\r\n seriesNodeMap, series, seriesNodeSet, seriesColor, palette, subsetSets, t,\r\n tier, eff, edgeWidth, onActivateNode,\r\n ])\r\n\r\n const seriesLines = useMemo(() => {\r\n if (!seriesColor) return null\r\n const byTerm = [...seriesNodeMap.entries()].sort((a, b) => a[1] - b[1])\r\n const lines: { from: { x: number; y: number }; to: { x: number; y: number } }[] = []\r\n for (let i = 0; i + 1 < byTerm.length; i++) {\r\n const fromPos = layout.positions[byTerm[i][0]]\r\n const toPos = layout.positions[byTerm[i + 1][0]]\r\n if (fromPos && toPos) lines.push({ from: fromPos, to: toPos })\r\n }\r\n return lines\r\n }, [seriesColor, seriesNodeMap, layout])\r\n\r\n // detail:hover 优先、否则选中。结构符号 O(|H|²),memo 即缓存(只在悬停节点变化时重算)\r\n const detailIdx = hoverIdx ?? activeNodeIdx\r\n const detailNode = detailIdx === null ? null : viewNodes[detailIdx] ?? null\r\n const detailSymbol = useMemo(() => {\r\n if (!group || !detailNode || detailNode.order === group.order) return null\r\n return subgroupStructureSymbol(group, detailNode.elementIds)\r\n }, [group, detailNode])\r\n\r\n const detailOrbit = detailNode as (SubgroupLatticeNode & OrbitFields) | null\r\n const detailTermIdx = detailIdx === null ? undefined : seriesNodeMap.get(detailIdx)\r\n\r\n // 就地气泡:屏幕坐标系下贴近 hover/选中节点,与底部 caption 行解耦,不再与 zoom slider 争位\r\n // 关键:foreignObject 内 HTML 用 13/eff 等反缩放字号,保证 ct.scale 变化时字号视觉恒定\r\n const bubble = useMemo(() => {\r\n if (!group || !detailNode || detailIdx === null) return null\r\n const pos = layout.positions[detailIdx]\r\n if (!pos) return null\r\n const nRy = layout.nodeRy\r\n const BUBBLE_PAD_X = 12 / eff\r\n const BUBBLE_PAD_Y = 6 / eff\r\n const BUBBLE_W = 280 / eff\r\n const BUBBLE_LINE_H = 18 / eff\r\n const BUBBLE_GAP = 8 / eff\r\n const lines: ReactNode[] = []\r\n lines.push(\r\n <span key=\"order\" dangerouslySetInnerHTML={{ __html: renderTex(`|H| = ${detailNode.order}`) }} />\r\n )\r\n if (detailSymbol) {\r\n lines.push(\r\n <span key=\"sym\" dangerouslySetInnerHTML={{ __html: renderTex(`\\\\cong ${detailSymbol}`) }} />\r\n )\r\n }\r\n if (detailNode.isNormal && detailNode.order !== group.order) {\r\n lines.push(\r\n <span key=\"normal\" style={{ color: palette.nodeStrokeNormal }}>{`◁ ${t('badge.normal')}`}</span>\r\n )\r\n }\r\n lines.push(\r\n <span key=\"idx\" dangerouslySetInnerHTML={{ __html: renderTex(`[G:H] = ${Math.round(group.order / detailNode.order)}`) }} />\r\n )\r\n if ((detailOrbit?.orbitSize ?? 1) > 1) {\r\n lines.push(\r\n <span key=\"orbit\" style={{ color: 'var(--text-muted)' }}>\r\n {t('lattice.orbitMembers', { n: String(detailOrbit!.orbitSize) })}\r\n {' · '}\r\n <span dangerouslySetInnerHTML={{ __html: renderTex(`|N_G(H)| = ${detailOrbit!.normalizerOrder}`) }} />\r\n </span>\r\n )\r\n }\r\n if (detailNode.label && detailNode.label !== `${detailNode.order}`) {\r\n lines.push(\r\n <span key=\"label\" dangerouslySetInnerHTML={{ __html: renderTex(texify(detailNode.label)) }} />\r\n )\r\n }\r\n if (detailTermIdx !== undefined && series) {\r\n lines.push(\r\n <span key=\"term\" style={{ color: seriesColor ?? undefined }}>{`N_${detailTermIdx} · ${t(`series.${series.type}`)}`}</span>\r\n )\r\n }\r\n const lineCount = lines.length\r\n const BUBBLE_H = BUBBLE_LINE_H * lineCount + BUBBLE_PAD_Y * 2\r\n // 位置策略:上方优先 → 不足则下方 → 上下都贴边则压紧到 viewBox 内\r\n const aboveY = pos.y - nRy - BUBBLE_GAP - BUBBLE_H\r\n const belowY = pos.y + nRy + BUBBLE_GAP\r\n let bubbleY = aboveY\r\n let pointer: 'down' | 'up' = 'down'\r\n if (aboveY < 0 || belowY + BUBBLE_H > layout.viewH) {\r\n // 至少一侧能放下时选空间大的那侧\r\n const aboveRoom = aboveY // 越负越差\r\n const belowRoom = layout.viewH - (belowY + BUBBLE_H) // 越负越差\r\n if (aboveRoom >= belowRoom) {\r\n bubbleY = Math.max(aboveY, 0)\r\n pointer = 'down'\r\n } else {\r\n bubbleY = Math.min(belowY, layout.viewH - BUBBLE_H)\r\n pointer = 'up'\r\n }\r\n }\r\n const idealX = pos.x - BUBBLE_W / 2\r\n const bubbleX = Math.min(Math.max(idealX, 0), Math.max(layout.viewW - BUBBLE_W, 0))\r\n const arrowAnchorX = Math.min(Math.max(pos.x, bubbleX + BUBBLE_PAD_X), bubbleX + BUBBLE_W - BUBBLE_PAD_X)\r\n const arrowTipY = pointer === 'down' ? bubbleY + BUBBLE_H : bubbleY\r\n const arrowBaseY = pointer === 'down' ? bubbleY : bubbleY + BUBBLE_H\r\n return (\r\n <g style={{ pointerEvents: 'none' }} data-testid=\"lattice-bubble\">\r\n <polygon\r\n points={`${arrowAnchorX - 6/eff},${arrowBaseY} ${arrowAnchorX + 6/eff},${arrowBaseY} ${arrowAnchorX},${arrowTipY}`}\r\n fill=\"var(--bg-panel)\"\r\n stroke=\"var(--border-primary)\"\r\n strokeWidth={1 / eff}\r\n />\r\n <foreignObject\r\n x={bubbleX}\r\n y={bubbleY}\r\n width={BUBBLE_W}\r\n height={BUBBLE_H}\r\n style={{ overflow: 'visible' }}\r\n >\r\n <div\r\n style={{\r\n width: '100%',\r\n height: '100%',\r\n padding: `${BUBBLE_PAD_Y}px ${BUBBLE_PAD_X}px`,\r\n border: '1px solid var(--border-primary)',\r\n borderRadius: `${6 / eff}px`,\r\n background: 'var(--bg-panel)',\r\n color: 'var(--text-primary)',\r\n fontSize: `${13 / eff}px`,\r\n lineHeight: 1.4,\r\n boxShadow: '0 2px 8px rgba(0,0,0,0.25)',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n gap: `${2 / eff}px`,\r\n }}\r\n >\r\n {lines.map((ln, idx) => (\r\n <span key={idx} style={{ display: 'inline-flex', alignItems: 'center', gap: `${8 / eff}px` }}>\r\n {ln}\r\n </span>\r\n ))}\r\n </div>\r\n </foreignObject>\r\n </g>\r\n )\r\n }, [detailNode, detailIdx, detailOrbit, detailTermIdx, detailSymbol, layout, eff, group, series, seriesColor, t, palette.nodeStrokeNormal])\r\n\r\n if (!group || !baseLattice || viewNodes.length === 0) {\r\n return (\r\n <div className=\"view-empty\">\r\n <p>{noGroupText ?? (group ? t('lattice.backendOnly') : t('canvas.noGroup'))}</p>\r\n </div>\r\n )\r\n }\r\n\r\n return (\r\n <div\r\n className=\"sublattice-view-wrap\"\r\n data-lattice-tier={tier}\r\n data-lattice-slot-width={Math.round(slotScreenWidth)}\r\n style={{ height: '100%', display: 'flex', flexDirection: 'column' }}\r\n >\r\n {/* 绘图区宿主:svg 绝对定位填满。若让 svg 参与常规流,它的 viewBox 宽高比会\r\n 以 min-content 高度向上撑破固定高度的窗口(Chrome 行为),故这里必须 absolute。 */}\r\n <div style={{ flex: 1, minHeight: 0, position: 'relative' }}>\r\n <svg\r\n ref={svgHostRef}\r\n viewBox={`0 0 ${layout.viewW} ${layout.viewH}`}\r\n className=\"view-svg\"\r\n style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', userSelect: 'none', overflow: 'visible' }}\r\n >\r\n <g transform={`translate(${ct.x}, ${ct.y}) scale(${ct.scale})`}>\r\n {edgeElements}\r\n {seriesLines && seriesLines.map((line, li) => (\r\n <line\r\n key={`series-line-${li}`}\r\n x1={line.from.x}\r\n y1={line.from.y}\r\n x2={line.to.x}\r\n y2={line.to.y}\r\n stroke={seriesColor!}\r\n strokeWidth={tier === 'full' ? 4 : Math.max(toWorld(4, eff, layout.nodeRx * 0.1), edgeWidth)}\r\n strokeLinecap=\"round\"\r\n opacity={0.85}\r\n />\r\n ))}\r\n {nodeElements}\r\n {bubble}\r\n </g>\r\n </svg>\r\n </div>\r\n {mergeUnavailable && (\r\n <div\r\n data-testid=\"lattice-merge-hint\"\r\n style={{ padding: '2px 10px', fontSize: 11, color: 'var(--accent-yellow-text)', flexShrink: 0 }}\r\n >\r\n {t('lattice.mergeTooLarge')}\r\n </div>\r\n )}\r\n {showSeriesPanel && series && <SeriesPanel group={group} series={series} color={seriesColor} theme={theme} />}\r\n </div>\r\n )\r\n}","/**\r\n * SceneWindow — @groupviz/react 通用窗口壳容器(FGVE「壳能力参数化」)。\r\n *\r\n * 定位:ViewWindow(主应用浮动窗壳)与「裸 Scene 直渲」之间的中间形态。壳只管\r\n * 窗口 chrome,children 渲任意 packaged Scene(消费端自持 Scene props,本组件\r\n * 零 Scene 耦合)。两个层次控制壳能力:\r\n *\r\n * shell: 'none' → 裸内容容器(等同 Frame 直嵌,不带任何 chrome)\r\n * 'chrome' → 标题栏 + 能力按钮 + 拖拽/resize + ⚙ View Config 面板 + persist\r\n * capabilities: chrome 形态下逐项露/藏内容;不传 = 全开,显式 false 关闭该项。\r\n *\r\n * 零 context / i18n / zod 依赖:主题用 theme prop(颜色自含 hex,不读 CSS 变量),\r\n * 按钮图标 + 英文 title(与主应用 FloatingViewWindow 一致),持久化 minimal\r\n * localStorage(try/catch 宽容,不引 utils/persistence 的 zod 校验链)。\r\n *\r\n * 约定:parent 需 position:relative;chrome 窗口 absolute 定位可拖可缩;shell:'none'\r\n * 时返回普通块级容器(不脱离文档流)。\r\n */\r\nimport { useCallback, useEffect, useState, type CSSProperties, type ReactNode } from 'react'\r\nimport type { Group } from '../../core/types'\r\n\r\nexport type SceneWindowTheme = 'dark' | 'light'\r\n\r\n/** 窗口级 config(行为开关;Scene 级参数由消费端以 Scene props 直传,不经此壳) */\r\nexport interface SceneWindowConfig {\r\n /** 📌 锁定窗口移动(拖拽禁用) */\r\n locked?: boolean\r\n /** 标题栏 info 区显示群符号/阶/名 */\r\n showInfo?: boolean\r\n /** 8 向 resize 手柄 */\r\n resizable?: boolean\r\n /** 定位用 fixed(视口固定)而非 absolute */\r\n viewportFixed?: boolean\r\n /** 标题栏整组隐藏(插图等专注阅读场景) */\r\n showControls?: boolean\r\n}\r\n\r\n/** chrome 内容裁剪位;缺省全开。false 关某项 */\r\nexport interface SceneWindowCaps {\r\n /** 标题栏本体(含 info 区) */\r\n titlebar?: boolean\r\n /** 标题栏拖拽移动(需 titlebar 且 locked=false) */\r\n drag?: boolean\r\n /** resize 手柄(8 向) */\r\n resize?: boolean\r\n /** 📌 锁定移动按钮 */\r\n lockMove?: boolean\r\n /** i 信息开关按钮 */\r\n toggleInfo?: boolean\r\n /** ⚙ View Config 面板(窗口 config 编辑) */\r\n params?: boolean\r\n /** × 关闭按钮(触发 onClose) */\r\n close?: boolean\r\n /** storageKey 持久化(位置/尺寸/config) */\r\n persist?: boolean\r\n}\r\n\r\ninterface SceneWindowProps {\r\n /** 标题栏主文案;缺省回退 group.symbol */\r\n title?: string\r\n /** 标题/信息兜底源 */\r\n group?: Group | null\r\n /** 窗口主题(背景/边框/文字配色);缺省 'dark' */\r\n theme?: SceneWindowTheme\r\n /** 'chrome' 浮动窗壳(缺省)/ 'none' 裸内容容器 */\r\n shell?: 'none' | 'chrome'\r\n /** chrome 内容裁剪;不传全开 */\r\n capabilities?: SceneWindowCaps\r\n /** 窗口 config(受控传入或非受控初值) */\r\n config?: SceneWindowConfig\r\n onConfigChange?: (c: SceneWindowConfig) => void\r\n /** 持久化键(cap.persist 且给键才读写 localStorage,键空间 gv-sw-*) */\r\n storageKey?: string\r\n defaultPosition?: { x: number; y: number }\r\n defaultSize?: { width: number; height: number }\r\n onClose?: () => void\r\n /** 任意 packaged Scene(或任意内容) */\r\n children: ReactNode\r\n}\r\n\r\nconst TBAR_H = 32\r\nconst MIN_W = 220\r\nconst MIN_H = 160\r\nconst PARAMS_W = 208\r\nconst PARAMS_GAP = 8\r\nlet _swZ = 5000\r\n\r\nconst DEFAULT_POS = { x: 12, y: 12 }\r\nconst DEFAULT_SIZE = { width: 440, height: 320 }\r\nconst DEFAULT_CFG: Required<SceneWindowConfig> = {\r\n locked: false, showInfo: false, resizable: true, viewportFixed: false, showControls: true,\r\n}\r\n\r\ntype ResizeDir = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw'\r\nconst RESIZE_CURSORS: Record<ResizeDir, string> = {\r\n n: 'ns-resize', s: 'ns-resize', e: 'ew-resize', w: 'ew-resize',\r\n ne: 'nesw-resize', sw: 'nesw-resize', nw: 'nwse-resize', se: 'nwse-resize',\r\n}\r\nconst RESIZE_DIRS: ResizeDir[] = ['n', 's', 'e', 'w', 'ne', 'nw', 'se', 'sw']\r\n\r\n// ── 主题色板(不读 CSS 变量,保证包消费端与主应用全局主题解耦) ──\r\nconst PALETTES: Record<SceneWindowTheme, {\r\n tbarBg: string; tbarBorder: string; tbarText: string; dim: string; contentBg: string;\r\n panelBg: string; panelBorder: string; panelText: string; accent: string;\r\n}> = {\r\n dark: {\r\n tbarBg: '#131c2b', tbarBorder: '#24324a', tbarText: '#94a3b8', dim: '#64748b',\r\n contentBg: '#0b1220', panelBg: '#111c2b', panelBorder: '#24324a', panelText: '#cbd5e1',\r\n accent: '#4ecdc4',\r\n },\r\n light: {\r\n tbarBg: '#eef2f7', tbarBorder: '#d0d9e4', tbarText: '#475569', dim: '#8fa0b3',\r\n contentBg: '#f8fafc', panelBg: '#ffffff', panelBorder: '#d0d9e4', panelText: '#334155',\r\n accent: '#0e7490',\r\n },\r\n}\r\n\r\n/** 打包键 → 规范解析(宽容:损坏/缺字段一律回退,不抛) */\r\nfunction loadSw<T>(key: string, schema: (raw: Record<string, unknown>) => T | null): T | null {\r\n try {\r\n const raw = localStorage.getItem(`gv-sw-${key}`)\r\n if (!raw) return null\r\n const parsed = JSON.parse(raw) as Record<string, unknown>\r\n return schema(parsed)\r\n } catch {\r\n return null\r\n }\r\n}\r\nfunction saveSw(key: string, data: unknown) {\r\n try {\r\n localStorage.setItem(`gv-sw-${key}`, JSON.stringify(data))\r\n } catch {\r\n /* 隐私模式/配额:静默 */\r\n }\r\n}\r\n\r\nfunction mergeCfg(base: SceneWindowConfig, extra?: SceneWindowConfig): SceneWindowConfig {\r\n return extra ? { ...base, ...extra } : base\r\n}\r\n\r\n/** 一次读持久化三件套(宽容:缺/坏字段回 undefined,不抛) */\r\nfunction readPersist(key?: string, enabled = true): { pos?: { x: number; y: number }; size?: { width: number; height: number }; cfg?: SceneWindowConfig } | null {\r\n if (!key || !enabled) return null\r\n return loadSw(key, raw => {\r\n const p = raw.pos as { x?: number; y?: number } | undefined\r\n const s = raw.size as { width?: number; height?: number } | undefined\r\n const rc = raw.config as Record<string, unknown> | undefined\r\n return {\r\n pos: p && typeof p.x === 'number' && typeof p.y === 'number' ? { x: p.x, y: p.y } : undefined,\r\n size: s && typeof s.width === 'number' && typeof s.height === 'number'\r\n ? { width: Math.max(MIN_W, s.width), height: Math.max(MIN_H, s.height) } : undefined,\r\n cfg: rc && typeof rc === 'object' ? (rc as SceneWindowConfig) : undefined,\r\n }\r\n })\r\n}\r\n\r\n/** 页面级辅助:stable 空对象引用 */\r\nconst EMPTY = {}\r\n\r\nexport function SceneWindow({\r\n title,\r\n group,\r\n theme = 'dark',\r\n shell = 'chrome',\r\n capabilities,\r\n config: configProp,\r\n onConfigChange,\r\n storageKey,\r\n defaultPosition,\r\n defaultSize,\r\n onClose,\r\n children,\r\n}: SceneWindowProps) {\r\n const P = PALETTES[theme]\r\n // ── 窗口 state(非受控):config + 几何(pos+size);persist 全在 lazy init 合并,effect 只写不读 ──\r\n const persistOn = !!storageKey && capabilities?.persist !== false\r\n const [cfg, setCfg] = useState<SceneWindowConfig>(() => {\r\n const c: SceneWindowConfig = { ...DEFAULT_CFG, ...(configProp ?? EMPTY) }\r\n const saved = readPersist(storageKey, persistOn)\r\n return saved?.cfg ? mergeCfg(c, saved.cfg) : c\r\n })\r\n const updateConfig = useCallback((patch: SceneWindowConfig) => {\r\n setCfg(prev => {\r\n const next = mergeCfg(prev, patch)\r\n onConfigChange?.(next)\r\n return next\r\n })\r\n }, [onConfigChange])\r\n\r\n const [geom, setGeom] = useState(() => {\r\n const saved = readPersist(storageKey, persistOn)\r\n return {\r\n pos: saved?.pos ?? defaultPosition ?? DEFAULT_POS,\r\n size: saved?.size ?? defaultSize ?? DEFAULT_SIZE,\r\n }\r\n })\r\n const { pos, size } = geom\r\n\r\n // 持久化写:几何 + config(cap.persist 且 storageKey)\r\n useEffect(() => {\r\n if (persistOn) saveSw(storageKey as string, { pos, size, config: cfg })\r\n }, [pos, size, cfg, storageKey, persistOn])\r\n\r\n // 置顶(mousedown 时 bring front)\r\n const [z, setZ] = useState(() => ++_swZ)\r\n const bringFront = useCallback(() => setZ(++_swZ), [])\r\n\r\n const [paramsOpen, setParamsOpen] = useState(false)\r\n\r\n // 拖拽(标题栏)\r\n const onDragStart = useCallback((e: React.MouseEvent) => {\r\n if (cfg.locked) return\r\n if ((e.target as HTMLElement).closest('button')) return\r\n e.preventDefault()\r\n bringFront()\r\n const start = { mx: e.clientX, my: e.clientY, ox: pos.x, oy: pos.y }\r\n const move = (ev: MouseEvent) => {\r\n setGeom(g => ({ ...g, pos: { x: start.ox + ev.clientX - start.mx, y: start.oy + ev.clientY - start.my } }))\r\n }\r\n const up = () => {\r\n window.removeEventListener('mousemove', move)\r\n window.removeEventListener('mouseup', up)\r\n }\r\n window.addEventListener('mousemove', move)\r\n window.addEventListener('mouseup', up)\r\n }, [cfg.locked, pos, bringFront])\r\n\r\n // resize(8 向手柄)\r\n const onResizeStart = useCallback((dir: ResizeDir) => (e: React.MouseEvent) => {\r\n e.preventDefault(); e.stopPropagation()\r\n bringFront()\r\n const start = { mx: e.clientX, my: e.clientY, ox: pos.x, oy: pos.y, ow: size.width, oh: size.height }\r\n const move = (ev: MouseEvent) => {\r\n const dx = ev.clientX - start.mx\r\n const dy = ev.clientY - start.my\r\n let { x, y, width, height } = { x: start.ox, y: start.oy, width: start.ow, height: start.oh }\r\n if (dir.includes('e')) width = Math.max(MIN_W, start.ow + dx)\r\n if (dir.includes('s')) height = Math.max(MIN_H, start.oh + dy)\r\n if (dir.includes('w')) { width = Math.max(MIN_W, start.ow - dx); x = start.ox + (start.ow - width) }\r\n if (dir.includes('n')) { height = Math.max(MIN_H, start.oh - dy); y = start.oy + (start.oh - height) }\r\n setGeom({ pos: { x, y }, size: { width, height } })\r\n }\r\n const up = () => {\r\n window.removeEventListener('mousemove', move)\r\n window.removeEventListener('mouseup', up)\r\n }\r\n window.addEventListener('mousemove', move)\r\n window.addEventListener('mouseup', up)\r\n }, [pos, size, bringFront])\r\n\r\n // ── shell:'none':裸内容容器(块级,不脱离文档流,无 chrome) ──\r\n if (shell === 'none') {\r\n return (\r\n <div data-testid=\"sw-none\" style={{ width: '100%', height: '100%', minHeight: 160, background: P.contentBg, overflow: 'hidden', position: 'relative' }}>\r\n {children}\r\n </div>\r\n )\r\n }\r\n\r\n // ── shell:'chrome' ──\r\n const caps = {\r\n titlebar: true, drag: true, resize: true, lockMove: true, toggleInfo: true,\r\n params: true, close: true, persist: true,\r\n ...(capabilities ?? EMPTY),\r\n } as Required<SceneWindowCaps>\r\n const showControls = cfg.showControls !== false\r\n const titleText = title ?? (group ? group.symbol : 'View')\r\n const infoText = cfg.showInfo && group\r\n ? `${group.symbol} · |G|=${group.order} · ${group.name ?? ''}`\r\n : ''\r\n const btnBase: CSSProperties = {\r\n background: 'none', border: 'none', color: P.dim, cursor: 'pointer',\r\n fontSize: 14, padding: '2px 5px', lineHeight: 1, borderRadius: 4,\r\n }\r\n const tglBtn = (on: boolean, color: string): CSSProperties => ({ ...btnBase, color: on ? color : P.dim })\r\n\r\n return (\r\n <div\r\n data-testid=\"sw-chrome\"\r\n style={{ position: cfg.viewportFixed ? 'fixed' : 'absolute', left: pos.x, top: pos.y, zIndex: z }}\r\n onMouseDown={bringFront}\r\n >\r\n {/* 窗身(overflow hidden 收内容;⚙ 面板在 wrapper 外侧不被裁) */}\r\n <div style={{ width: size.width, background: P.contentBg, border: `1px solid ${P.tbarBorder}`, borderRadius: 8, overflow: 'hidden', boxShadow: '0 10px 34px rgba(0,0,0,0.30)' }}>\r\n {/* titlebar */}\r\n {caps.titlebar && showControls && (\r\n <div\r\n style={{\r\n display: 'flex', alignItems: 'center', justifyContent: 'space-between',\r\n padding: '0 6px 0 10px', height: TBAR_H, background: P.tbarBg,\r\n borderBottom: `1px solid ${P.tbarBorder}`, cursor: caps.drag && !cfg.locked ? 'grab' : 'default',\r\n fontSize: 13, color: P.tbarText, userSelect: 'none', flexShrink: 0, gap: 4,\r\n }}\r\n onMouseDown={caps.drag ? onDragStart : undefined}\r\n >\r\n <span style={{ fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>\r\n {titleText}\r\n {infoText && <span style={{ fontWeight: 400, fontSize: 11, color: P.dim, marginLeft: 8 }}>{infoText}</span>}\r\n </span>\r\n <div style={{ display: 'flex', alignItems: 'center', gap: 2 }}>\r\n {caps.lockMove && (\r\n <button title=\"Lock move\" style={tglBtn(!!cfg.locked, '#f97316')}\r\n onClick={() => updateConfig({ locked: !cfg.locked })}>\r\n {cfg.locked ? '📌' : '📍'}\r\n </button>\r\n )}\r\n {caps.toggleInfo && (\r\n <button title=\"Toggle info\" style={tglBtn(!!cfg.showInfo, '#84cc16')}\r\n onClick={() => updateConfig({ showInfo: !cfg.showInfo })}>i</button>\r\n )}\r\n {caps.params && (\r\n <button title=\"Parameters\" style={tglBtn(paramsOpen, '#a78bfa')}\r\n onClick={() => { bringFront(); setParamsOpen(o => !o) }}>⚙</button>\r\n )}\r\n {caps.close && (\r\n <button title=\"Close\" style={btnBase}\r\n onClick={onClose}\r\n onMouseEnter={e => (e.currentTarget.style.color = '#f44')}\r\n onMouseLeave={e => (e.currentTarget.style.color = P.dim)}>×</button>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* content viewport */}\r\n <div style={{ position: 'relative', height: size.height - (caps.titlebar && showControls ? TBAR_H : 0), overflow: 'hidden', background: P.contentBg }}>\r\n {children}\r\n {/* resize handles */}\r\n {caps.resize && cfg.resizable !== false && RESIZE_DIRS.map(dir => {\r\n const s = 8\r\n const c = 20\r\n const base: CSSProperties = { position: 'absolute', zIndex: 10, cursor: RESIZE_CURSORS[dir], background: 'transparent' }\r\n const rect: CSSProperties = (() => {\r\n switch (dir) {\r\n case 'n': return { top: 0, left: s, right: s, height: s }\r\n case 's': return { bottom: 0, left: s, right: s, height: s }\r\n case 'e': return { right: 0, top: s, bottom: s, width: s }\r\n case 'w': return { left: 0, top: s, bottom: s, width: s }\r\n case 'ne': return { top: 0, right: 0, width: c, height: c }\r\n case 'nw': return { top: 0, left: 0, width: c, height: c }\r\n case 'se': return { bottom: 0, right: 0, width: c, height: c }\r\n case 'sw': return { bottom: 0, left: 0, width: c, height: c }\r\n }\r\n })()\r\n return <div key={dir} style={{ ...base, ...rect }} onMouseDown={onResizeStart(dir)} />\r\n })}\r\n </div>\r\n </div>{/* /窗身 */}\r\n\r\n {/* ⚙ View Config panel(窗口外侧,不遮内容) */}\r\n {paramsOpen && caps.params && (\r\n <div\r\n style={{\r\n position: cfg.viewportFixed ? 'fixed' : 'absolute',\r\n left: size.width + PARAMS_GAP, top: 0, width: PARAMS_W,\r\n maxHeight: size.height, overflowY: 'auto', zIndex: z + 1,\r\n background: P.panelBg, border: `1px solid ${P.panelBorder}`, borderRadius: 6,\r\n boxShadow: '0 8px 32px rgba(0,0,0,0.28)', padding: '8px 10px',\r\n fontSize: 12, color: P.panelText,\r\n }}\r\n onMouseDown={bringFront}\r\n >\r\n <div style={{ fontWeight: 600, marginBottom: 6 }}>View Config</div>\r\n {caps.lockMove && (\r\n <label style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 4 }}>\r\n <input type=\"checkbox\" checked={!!cfg.locked} onChange={e => updateConfig({ locked: e.target.checked })} style={{ accentColor: P.accent }} />\r\n Lock move\r\n </label>\r\n )}\r\n {caps.toggleInfo && (\r\n <label style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 4 }}>\r\n <input type=\"checkbox\" checked={!!cfg.showInfo} onChange={e => updateConfig({ showInfo: e.target.checked })} style={{ accentColor: P.accent }} />\r\n Show info\r\n </label>\r\n )}\r\n <label style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 4 }}>\r\n <input type=\"checkbox\" checked={!!cfg.viewportFixed} onChange={e => updateConfig({ viewportFixed: e.target.checked })} style={{ accentColor: P.accent }} />\r\n Fixed to viewport\r\n </label>\r\n <label style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 4 }}>\r\n <input type=\"checkbox\" checked={cfg.showControls !== false} onChange={e => updateConfig({ showControls: e.target.checked })} style={{ accentColor: P.accent }} />\r\n Show controls\r\n </label>\r\n <label style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 4 }}>\r\n <input type=\"checkbox\" checked={cfg.resizable !== false} onChange={e => updateConfig({ resizable: e.target.checked })} style={{ accentColor: P.accent }} />\r\n Resizable\r\n </label>\r\n {/* 说明:Scene 级参数不经本壳,由宿主以 Scene props 直传 */}\r\n <div style={{ marginTop: 6, fontSize: 10, color: P.dim, lineHeight: 1.5 }}>\r\n Scene props are controlled by the host (embed your own <Scene …/> as children).\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n )\r\n}\r\n\r\nexport type { SceneWindowProps }\r\n","import type { CSSProperties } from 'react'\nimport { elementOrder } from '../../core/algebra/elementOrder'\nimport type { Group, GroupElement } from '../../core/types'\n\n/**\n * SceneHoverBubble —— 悬停就地气泡(默认实现)。\n *\n * 配合 `useSceneState().hoverBubble` 使用;也可在自建宿主里独立渲染。\n * 配色读 `theme.css` 的自定义属性(经 `data-theme` 作用域),因此天然跟随视图主题,\n * 不写死颜色;未引入 `theme.css` 时由内联兜底色保证可读。\n *\n * 定位:`anchor` 是元素在容器内的屏幕坐标(Scene 的 `onHover` 第二参),\n * 气泡默认浮在锚点正上方居中。`anchor` 为空(如表格视图不提供锚点)时不渲染。\n */\nexport interface SceneHoverBubbleProps {\n element: GroupElement | null\n anchor?: { x: number; y: number } | null\n /** 缺省 `'dark'`(与 `theme.css` 默认块一致) */\n theme?: 'dark' | 'light'\n /** 传入则在气泡里补一行「阶 = n」(元素阶是排名第一的高频信息) */\n group?: Group | null\n /** 相对锚点的额外偏移;缺省 `{ x: 0, y: -14 }` */\n offset?: { x: number; y: number }\n}\n\nexport function SceneHoverBubble({\n element,\n anchor,\n theme = 'dark',\n group,\n offset,\n}: SceneHoverBubbleProps) {\n if (!element || !anchor) return null\n\n const dx = offset?.x ?? 0\n const dy = offset?.y ?? -14\n const order = group ? elementOrder(group, element) : null\n\n const box: CSSProperties = {\n position: 'absolute',\n left: anchor.x + dx,\n top: anchor.y + dy,\n transform: 'translate(-50%, -100%)',\n pointerEvents: 'none',\n zIndex: 20,\n padding: '5px 9px',\n borderRadius: 6,\n border: '1px solid var(--border-primary, #2d2d4a)',\n background: 'var(--bg-tooltip, rgba(21,21,37,0.95))',\n color: 'var(--text-primary, #e0e0e0)',\n fontSize: 12,\n lineHeight: 1.4,\n whiteSpace: 'nowrap',\n boxShadow: '0 6px 20px rgba(0,0,0,0.35)',\n }\n\n const dim: CSSProperties = { color: 'var(--text-dim, #888888)', fontSize: 10 }\n\n return (\n <div data-theme={theme} style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>\n <div data-testid=\"scene-hover-bubble\" style={box}>\n <div style={{ fontWeight: 600 }}>{element.label}</div>\n {(order !== null || element.id !== element.label) && (\n <div style={dim}>\n {element.id !== element.label && <span>{element.id}</span>}\n {order !== null && (\n <span>{element.id !== element.label ? ' · ' : ''}阶 {order}</span>\n )}\n </div>\n )}\n </div>\n </div>\n )\n}\n","import { createElement, useCallback, useEffect, useMemo, useRef, useState, type CSSProperties, type ReactNode } from 'react'\nimport type { CanvasTransform, Group, GroupElement, NodePosition } from '../core/types'\nimport { SceneHoverBubble } from '../components/Canvas/SceneHoverBubble'\n\n/**\n * useSceneState —— 受控 Scene 的「四件套」便利层。\n *\n * 背景:`SetView` / `CycleView` / `CayleyView` / `CosetStripScene` 都是纯受控内核,\n * 宿主必须自备 `selectedElements` + `canvasTransform` + `viewBoxSize`,再自己接\n * `onSelect` / `onHover` 并渲染 hover 气泡。一个「嵌一张图」的最小用例要写 ~80 行胶水\n * (ResizeObserver 量尺寸、滚轮缩放贴光标、拖拽平移、⊕/Ctrl 多选、悬停锚点气泡)。\n *\n * 本 hook 把这一层收进包里:返回 `hostProps` + `sceneProps` + `hoverBubble`,\n * 宿主只需\n *\n * ```tsx\n * const group = createGroupFromSymbol('S_{4}')\n * const s = useSceneState(group)\n * return (\n * <div {...s.hostProps}>\n * <SetView group={group} {...s.sceneProps} />\n * {s.hoverBubble}\n * </div>\n * )\n * ```\n *\n * 设计要点:\n * - **ref 只以 `hostProps.ref` 嵌套形式出现,绝不作为顶层返回字段**。React Compiler\n * 的 `react-hooks/refs` 规则会把「顶层返回了写 ref 的回调 / 含 RefObject」的 hook\n * 整体判为 ref 载体,此后宿主每一次 `s.xxx` 读取都会报「渲染期访问 ref」\n * (实测:`s.hostProps`、`s.viewBoxSize` 一并中招)。嵌套形式不触发该判定。\n * 代价是宿主**不要自己在 spread 之后再写 `ref`**(会顶掉内建 ref);\n * 需要 DOM 节点时用 `getHostElement()`;\n * - `hostProps` 用 **React 合成事件**(非原生监听)做拖拽平移 —— 与 Scene 内节点的\n * `stopPropagation()` 处于同一套合成冒泡序,拖节点时不会把画布一起拖走;\n * - 滚轮缩放走**原生 non-passive 监听**(React 的 root 级 wheel 是 passive,\n * `preventDefault` 无效),缩放锚定光标下的 viewBox 坐标;\n * - `selectedElements` 可受控(传 `options.selectedElements` + `onSelectionChange`)\n * 或非受控(内部自持);\n * - 节点位置可选共享:把 `getNodePosition` / `onNodePositionChange` 传给 `CycleView`\n * 即可多视图共用一套坐标(不传则 Scene 用自身局部态)。\n */\n\nconst DEFAULT_TRANSFORM: CanvasTransform = { x: 0, y: 0, scale: 1 }\nconst DEFAULT_VIEWBOX = { width: 800, height: 600 }\nconst DEFAULT_MIN_SCALE = 0.25\nconst DEFAULT_MAX_SCALE = 8\nconst NOOP = () => {}\n\nexport interface SceneStateOptions {\n /** 初始平移 / 缩放;缺省 `{ x:0, y:0, scale:1 }` */\n initialTransform?: CanvasTransform\n /** 锁定交互(透传给 Scene 的 `locked`;同时禁用本 hook 的平移缩放) */\n locked?: boolean\n /** 滚轮缩放开关;缺省 `true` */\n enableZoom?: boolean\n /** 拖拽平移开关;缺省 `true` */\n enablePan?: boolean\n /** 缩放下限;缺省 `0.25`(与主画布一致) */\n minScale?: number\n /** 缩放上限;缺省 `8` */\n maxScale?: number\n /** 受控选中集合(传入即受控,配合 `onSelectionChange`) */\n selectedElements?: Set<string>\n /** 选中集合变更回调(受控 / 非受控都会触发,便于宿主记录) */\n onSelectionChange?: (next: Set<string>) => void\n /** ResizeObserver 首帧前的兜底尺寸;缺省 `{ width:800, height:600 }` */\n fallbackViewBoxSize?: { width: number; height: number }\n /** 宿主容器附加样式(与内建样式合并,内建优先保证定位/尺寸) */\n hostStyle?: CSSProperties\n /** hover 气泡主题;缺省 `'dark'` */\n theme?: 'dark' | 'light'\n /** hover 气泡自定义渲染;返回 `null` 表示禁用内建气泡 */\n renderHoverBubble?: (el: GroupElement, anchor: { x: number; y: number } | null) => ReactNode\n}\n\n/** 可直接 spread 到四类 2D Scene 的公共受控 props。 */\nexport interface SceneStateProps {\n selectedElements: Set<string>\n canvasTransform: CanvasTransform\n viewBoxSize: { width: number; height: number }\n onSelect: (elId: string, additive: boolean) => void\n onHover: (el: GroupElement | null, anchor?: { x: number; y: number } | null) => void\n}\n\nexport interface SceneState {\n /** 容器实测尺寸(ResizeObserver;首帧为兜底值) */\n viewBoxSize: { width: number; height: number }\n /**\n * 宿主容器的 props —— **一次 spread 即可**:\n *\n * ```tsx\n * const s = useSceneState(group)\n * <div {...s.hostProps}><SetView group={group} {...s.sceneProps} />{s.hoverBubble}</div>\n * ```\n *\n * 内含 `ref`(回调 ref)、内建样式(定位/尺寸/`touchAction`/光标)与拖拽平移事件。\n *\n * ⚠️ 别在 spread 之后再写 `ref`:那会顶掉内建 ref,尺寸测量与悬浮气泡换算会静默失效。\n * 需要 DOM 节点请用 `getHostElement()`。\n *\n * 设计说明:ref 只以**嵌套**形式出现在 `hostProps` 里,绝不作为顶层字段暴露。\n * React Compiler 的 `react-hooks/refs` 规则会把「顶层返回了写 ref 的回调」的 hook\n * 整体判为 ref 载体,此后宿主每次 `s.xxx` 读取都会报「渲染期访问 ref」;\n * 嵌套形式不触发该判定(实测)。\n */\n hostProps: {\n ref: (el: HTMLDivElement | null) => void\n style: CSSProperties\n onMouseDown: (e: React.MouseEvent) => void\n onMouseMove: (e: React.MouseEvent) => void\n onMouseUp: () => void\n onMouseLeave: () => void\n }\n /** 需要 DOM 节点时用(如导出 SVG):取宿主容器元素 */\n getHostElement: () => HTMLDivElement | null\n canvasTransform: CanvasTransform\n setCanvasTransform: (t: CanvasTransform) => void\n selectedElements: Set<string>\n setSelectedElements: (next: Set<string> | ((prev: Set<string>) => Set<string>)) => void\n /** 选中语义:`additive`(⊕/Ctrl/⌘)→ 切换成员;否则 → 单选替换 */\n select: (elId: string, additive?: boolean) => void\n clearSelection: () => void\n /** 当前悬停元素(`onHover` 自动维护) */\n hovered: GroupElement | null\n /** 悬停锚点(viewBox 坐标系下映射到容器内的屏幕坐标) */\n hoverAnchor: { x: number; y: number } | null\n /** 内建 hover 气泡节点(可直接 `{s.hoverBubble}`;想自己画就用 `renderHoverBubble`) */\n hoverBubble: ReactNode\n /** 直接 spread 给 SetView / CycleView / CayleyView / CosetStripScene */\n sceneProps: SceneStateProps\n /** 复位平移缩放 */\n resetTransform: () => void\n /** 以容器中心为锚缩放(按钮用,`factor > 1` 放大) */\n zoomBy: (factor: number) => void\n /** 是否锁定(= `options.locked`) */\n locked: boolean\n /** 共享节点位置:接 `CycleView.getNodePosition` */\n getNodePosition: (elId: string) => NodePosition | undefined\n /** 共享节点位置:接 `CycleView.onNodePositionChange` */\n onNodePositionChange: (elId: string, x: number, y: number) => void\n /** 清空共享节点位置 */\n resetNodePositions: () => void\n}\n\nexport function useSceneState(group?: Group | null, options: SceneStateOptions = {}): SceneState {\n const {\n initialTransform,\n locked = false,\n enableZoom = true,\n enablePan = true,\n minScale = DEFAULT_MIN_SCALE,\n maxScale = DEFAULT_MAX_SCALE,\n selectedElements: controlledSelection,\n onSelectionChange,\n fallbackViewBoxSize,\n hostStyle,\n theme = 'dark',\n renderHoverBubble,\n } = options\n\n const hostRef = useRef<HTMLDivElement | null>(null)\n /** 对外暴露回调 ref:不在渲染期写 ref,也不把 RefObject 塞进返回体 */\n const setHostRef = useCallback((el: HTMLDivElement | null) => { hostRef.current = el }, [])\n const getHostElement = useCallback(() => hostRef.current, [])\n\n // ── 尺寸:ResizeObserver 实测容器 ──\n const [viewBoxSize, setViewBoxSize] = useState(fallbackViewBoxSize ?? DEFAULT_VIEWBOX)\n useEffect(() => {\n const el = hostRef.current\n if (!el) return\n const measure = () => {\n const rect = el.getBoundingClientRect()\n const width = Math.max(1, Math.round(rect.width))\n const height = Math.max(1, Math.round(rect.height))\n setViewBoxSize(prev => (prev.width === width && prev.height === height ? prev : { width, height }))\n }\n measure()\n if (typeof ResizeObserver === 'undefined') {\n globalThis.addEventListener('resize', measure)\n return () => globalThis.removeEventListener('resize', measure)\n }\n const ro = new ResizeObserver(measure)\n ro.observe(el)\n return () => ro.disconnect()\n }, [])\n\n // ── 平移 / 缩放 ──\n const [canvasTransform, setCanvasTransformState] = useState<CanvasTransform>(initialTransform ?? DEFAULT_TRANSFORM)\n // transformRef 是「权威值」:只在事件回调里同步写(渲染期写 ref 会触发\n // react-hooks/refs)。这样滚轮/拖拽读到的永远是最后一次已应用的值,无陈旧窗口。\n const transformRef = useRef(canvasTransform)\n\n const setCanvasTransform = useCallback((t: CanvasTransform) => {\n transformRef.current = t\n setCanvasTransformState(t)\n }, [])\n\n const resetTransform = useCallback(\n () => setCanvasTransform(initialTransform ?? DEFAULT_TRANSFORM),\n [setCanvasTransform, initialTransform],\n )\n\n // 光标处的 viewBox 坐标(反向映射,缩放锚点用)\n const cursorToViewBox = useCallback((clientX: number, clientY: number) => {\n const el = hostRef.current\n const rect = el?.getBoundingClientRect()\n if (!rect) return { x: 0, y: 0 }\n // 指针坐标缺失 / 非有限(合成事件未带 clientX 等)→ 退回容器中心,\n // 免得 NaN 顺着 anchor 污染 canvasTransform(一旦变 NaN 整张图消失且无法自愈)。\n const cx = Number.isFinite(clientX) && Number.isFinite(clientY)\n ? clientX\n : rect.left + rect.width / 2\n const cy = Number.isFinite(clientX) && Number.isFinite(clientY)\n ? clientY\n : rect.top + rect.height / 2\n const svg = el?.querySelector('svg')\n const vb = svg?.viewBox?.baseVal\n const vw = vb && vb.width > 0 ? vb.width : viewBoxSize.width\n const vh = vb && vb.height > 0 ? vb.height : viewBoxSize.height\n const s = Math.min(rect.width / vw, rect.height / vh) || 1\n const offX = (rect.width - vw * s) / 2\n const offY = (rect.height - vh * s) / 2\n const t = transformRef.current\n const px = (cx - rect.left - offX) / s\n const py = (cy - rect.top - offY) / s\n return { x: (px - t.x) / t.scale, y: (py - t.y) / t.scale }\n }, [viewBoxSize])\n\n const zoomAt = useCallback((factor: number, anchor: { x: number; y: number }) => {\n const t = transformRef.current\n // 锚点非有限 → 放弃本次缩放(宁可不动,也不要把 transform 写成 NaN)\n if (!Number.isFinite(anchor.x) || !Number.isFinite(anchor.y)) return\n const next = Math.min(maxScale, Math.max(minScale, t.scale * factor))\n if (next === t.scale) return\n const k = next / t.scale\n setCanvasTransform({\n x: anchor.x - (anchor.x - t.x) * k,\n y: anchor.y - (anchor.y - t.y) * k,\n scale: next,\n })\n }, [setCanvasTransform, minScale, maxScale])\n\n // 滚轮:原生 non-passive(React root 级 wheel 为 passive,preventDefault 无效)\n useEffect(() => {\n const el = hostRef.current\n if (!el || locked || !enableZoom) return\n const onWheel = (e: WheelEvent) => {\n e.preventDefault()\n zoomAt(e.deltaY > 0 ? 0.9 : 1.1, cursorToViewBox(e.clientX, e.clientY))\n }\n el.addEventListener('wheel', onWheel, { passive: false })\n return () => el.removeEventListener('wheel', onWheel)\n }, [locked, enableZoom, zoomAt, cursorToViewBox])\n\n const zoomBy = useCallback((factor: number) => {\n zoomAt(factor, {\n x: (viewBoxSize.width / 2 - transformRef.current.x) / transformRef.current.scale,\n y: (viewBoxSize.height / 2 - transformRef.current.y) / transformRef.current.scale,\n })\n }, [zoomAt, viewBoxSize])\n\n // 拖拽平移(React 合成事件:Scene 内节点 stopPropagation 时不会触发此处)\n const panRef = useRef<{ active: boolean; startX: number; startY: number; ox: number; oy: number }>({\n active: false, startX: 0, startY: 0, ox: 0, oy: 0,\n })\n const [panning, setPanning] = useState(false)\n const panEnabled = enablePan && !locked\n\n const endPan = useCallback(() => {\n if (!panRef.current.active) return\n panRef.current.active = false\n setPanning(false)\n }, [])\n\n const onMouseDown = useCallback((e: React.MouseEvent) => {\n if (!panEnabled || e.button !== 0) return\n panRef.current = {\n active: true, startX: e.clientX, startY: e.clientY,\n ox: transformRef.current.x, oy: transformRef.current.y,\n }\n setPanning(true)\n }, [panEnabled])\n\n const onMouseMove = useCallback((e: React.MouseEvent) => {\n if (!panRef.current.active) return\n const p = panRef.current\n setCanvasTransform({\n x: p.ox + (e.clientX - p.startX),\n y: p.oy + (e.clientY - p.startY),\n scale: transformRef.current.scale,\n })\n }, [setCanvasTransform])\n\n useEffect(() => {\n if (!panning) return\n globalThis.addEventListener('mouseup', endPan)\n return () => globalThis.removeEventListener('mouseup', endPan)\n }, [panning, endPan])\n\n const hostProps = useMemo(() => ({\n ref: setHostRef,\n style: {\n position: 'relative' as const,\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n touchAction: 'none' as const,\n cursor: panEnabled ? (panning ? 'grabbing' : 'grab') : 'default',\n ...hostStyle,\n },\n onMouseDown,\n onMouseMove,\n onMouseUp: endPan,\n onMouseLeave: endPan,\n }), [setHostRef, hostStyle, panEnabled, panning, onMouseDown, onMouseMove, endPan])\n\n // ── 选中 ──\n const [internalSelection, setInternalSelection] = useState<Set<string>>(() => new Set<string>())\n const selectedElements = controlledSelection ?? internalSelection\n\n const commitSelection = useCallback((next: Set<string>) => {\n if (!controlledSelection) setInternalSelection(next)\n onSelectionChange?.(next)\n }, [controlledSelection, onSelectionChange])\n\n const setSelectedElements = useCallback((next: Set<string> | ((prev: Set<string>) => Set<string>)) => {\n const resolved = typeof next === 'function'\n ? next(controlledSelection ?? internalSelection)\n : next\n commitSelection(resolved)\n }, [controlledSelection, internalSelection, commitSelection])\n\n const select = useCallback((elId: string, additive = false) => {\n const current = controlledSelection ?? internalSelection\n if (additive) {\n const next = new Set(current)\n if (next.has(elId)) next.delete(elId)\n else next.add(elId)\n commitSelection(next)\n } else {\n commitSelection(new Set([elId]))\n }\n }, [controlledSelection, internalSelection, commitSelection])\n\n const clearSelection = useCallback(() => commitSelection(new Set<string>()), [commitSelection])\n\n // ── 悬停 ──\n const [hovered, setHovered] = useState<GroupElement | null>(null)\n const [hoverAnchor, setHoverAnchor] = useState<{ x: number; y: number } | null>(null)\n\n const onHover = useCallback((el: GroupElement | null, anchor?: { x: number; y: number } | null) => {\n setHovered(el)\n if (!el || !anchor) {\n setHoverAnchor(null)\n return\n }\n // Scene 给的 anchor 已是 viewport 内屏幕坐标则直接用;否则按 viewBox 坐标换算。\n // 约定:Scene 传的是屏幕坐标(见 CayleyView 文档),此处直接透传。\n setHoverAnchor(anchor)\n }, [])\n\n const hoverBubble = useMemo<ReactNode>(() => {\n if (!hovered) return null\n if (renderHoverBubble) return renderHoverBubble(hovered, hoverAnchor)\n return createElement(SceneHoverBubble, {\n element: hovered,\n anchor: hoverAnchor,\n theme,\n group: group ?? null,\n })\n }, [hovered, hoverAnchor, renderHoverBubble, theme, group])\n\n // ── 共享节点位置 ──\n const [nodePositions, setNodePositions] = useState<Map<string, NodePosition>>(() => new Map())\n const getNodePosition = useCallback((elId: string) => nodePositions.get(elId), [nodePositions])\n const onNodePositionChange = useCallback((elId: string, x: number, y: number) => {\n setNodePositions(prev => {\n const next = new Map(prev)\n next.set(elId, { x, y })\n return next\n })\n }, [])\n const resetNodePositions = useCallback(() => setNodePositions(new Map()), [])\n\n // 换群 → 清掉上一群的会话态(悬停 / 选中 / 节点位置),避免残留 id 命中新群。\n // 用 React 官方的「渲染期校正 state」模式(Storing information from previous renders)\n // 而非 effect:effect 版本要多提交一次渲染,且那一帧仍带着旧群的残留 id。\n const [sessionGroup, setSessionGroup] = useState(group)\n if (sessionGroup !== group) {\n setSessionGroup(group)\n setHovered(null)\n setHoverAnchor(null)\n setNodePositions(new Map())\n if (!controlledSelection) setInternalSelection(new Set<string>())\n }\n\n const sceneProps = useMemo<SceneStateProps>(() => ({\n selectedElements,\n canvasTransform,\n viewBoxSize,\n onSelect: select,\n onHover,\n }), [selectedElements, canvasTransform, viewBoxSize, select, onHover])\n\n return {\n hostProps,\n viewBoxSize,\n getHostElement,\n canvasTransform,\n setCanvasTransform,\n selectedElements,\n setSelectedElements,\n select,\n clearSelection,\n hovered,\n hoverAnchor,\n hoverBubble,\n sceneProps,\n resetTransform,\n zoomBy,\n locked,\n getNodePosition,\n onNodePositionChange,\n resetNodePositions,\n }\n}\n\n/** 无群 / 无操作时的稳定引用(供宿主做默认值,避免每次新建对象触发重渲染)。 */\nexport const SCENE_STATE_NOOP = NOOP\n"],"mappings":"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"}
|