import type { Tree } from 'ml-tree-similarity'; import { createTree } from 'ml-tree-similarity'; import type { CSSProperties } from 'react'; import { Fragment } from 'react'; import { isSpectrum1D } from '../../data/data1d/Spectrum1D/index.js'; import { useChartData } from '../context/ChartContext.js'; import { useScaleChecked } from '../context/ScaleContext.js'; import { useFormatNumberByNucleus } from '../hooks/useFormatNumberByNucleus.js'; import useSpectrum from '../hooks/useSpectrum.js'; const circleSize = 3; const marginTop = circleSize + 10; const lineColor: CSSProperties['color'] = 'black'; const textColor: CSSProperties['color'] = 'black'; const textPadding = circleSize + 2; const textSize = 10; const maxTreeLevels = 25; export default function SimilarityTree() { const { height, view: { spectra: { activeTab, showSimilarityTree }, }, } = useChartData(); const spectrum = useSpectrum(); const format = useFormatNumberByNucleus(activeTab); const { scaleX } = useScaleChecked(); const scaleY = (value: number) => (height * value) / maxTreeLevels; const treeHeadLength = height / maxTreeLevels; if (!spectrum || !showSimilarityTree || !isSpectrum1D(spectrum)) return null; const { data: { x, re }, display: { color }, } = spectrum; const tree = createTree({ x, y: re }); const data = mapTreeToArray(tree, 0); const paths: string[] = []; for (const { level, center, parentCenter, parentLevel } of data) { if (parentCenter === undefined || parentLevel === undefined) continue; const startX = scaleX()(parentCenter); const startY = scaleY(parentLevel); const midY = startY + treeHeadLength / 2; const endX = scaleX()(center); const endY = scaleY(level); const path = `M ${startX} ${startY} L ${startX} ${midY} L ${endX} ${midY} L${endX} ${endY}`; paths.push(path); } return ( ; {data.map(({ level, center }) => { const x = scaleX()(center); const y = scaleY(level); return ( {format(center)} ); })} ); } interface TreeItem { center: number; sum: number; level: number; parentCenter?: number; parentLevel?: number; } function mapTreeToArray( node: Tree | null, level: number, parentCenter: number | null = null, parentLevel = -1, ): TreeItem[] { if (!node) return []; const { center, sum } = node; const result: TreeItem[] = [{ center, sum, level }]; for (const obj of result) { if (parentCenter) { obj.parentCenter = parentCenter; obj.parentLevel = parentLevel; } } const left = mapTreeToArray(node.left, level + 1, center, parentLevel + 1); const right = mapTreeToArray(node.right, level + 1, center, parentLevel + 1); return result.concat(left, right); }