From df4609a59f88389b74805d20cae2713ae2aeec64 Mon Sep 17 00:00:00 2001 From: Zxilly Date: Tue, 16 Jul 2024 20:36:08 +0800 Subject: [PATCH] perf: enhance performance while using with large binary Signed-off-by: Zxilly --- ui/src/Node.tsx | 4 - ui/src/TreeMap.tsx | 257 +- ui/src/__snapshots__/Treemap.test.tsx.snap | 3990 ++++++-------------- ui/src/tool/copy.ts | 4 + ui/src/tool/useMouse.ts | 60 + ui/vite.config.ts | 11 +- 6 files changed, 1400 insertions(+), 2926 deletions(-) create mode 100644 ui/src/tool/copy.ts create mode 100644 ui/src/tool/useMouse.ts diff --git a/ui/src/Node.tsx b/ui/src/Node.tsx index 8d43d1ee95..550c689151 100644 --- a/ui/src/Node.tsx +++ b/ui/src/Node.tsx @@ -83,10 +83,6 @@ export const Node: React.FC = React.memo(( textRef.current.setAttribute("transform", `scale(${scale.toFixed(2)})`); }, [hasChildren, height, width]); - if (width === 0 || height === 0) { - return null; - } - return ( { - return hierarchy(entry, e => e.getChildren()); + return hierarchy(entry, e => e.getChildren()) + .sum((e) => { + if (e.getChildren().length === 0) { + return e.getSize(); + } + return 0; + }) + .sort((a, b) => a.data.getSize() - b.data.getSize()); }, [entry]); - const getModuleColor = useMemo(() => { + const rawHierarchyID = useMemo(() => { + const cache = new Map>(); + rawHierarchy.descendants().forEach((node) => { + cache.set(node.data.getID(), node); + }); + return cache; + }, [rawHierarchy]); + + const getModuleColorRaw = useMemo(() => { return createRainbowColor(rawHierarchy); }, [rawHierarchy]); + const getModuleColor = useCallback((id: number) => { + return getModuleColorRaw(rawHierarchyID.get(id)!); + }, [getModuleColorRaw, rawHierarchyID]); + const layout = useMemo(() => { return treemap() .size([width, height]) - .paddingInner(2) + .paddingInner(1) .paddingTop(20) .round(true) .tile(treemapSquarify); @@ -64,66 +85,66 @@ function TreeMap({ entry }: TreeMapProps) { cur = found; } - return cur; + return cur.data.getID(); }, [entry, rawHierarchy]); - const [selectedNode, setSelectedNode] = useState | null>(loadNodeFromHash); - const selectedNodeLeaveIDSet = useMemo(() => { - if (selectedNode === null) { - return new Set(); + const [selectedNodeID, setSelectedNodeID] = useState(loadNodeFromHash); + + const layoutRoot = useMemo(() => { + let root: HierarchyNode | null; + if (!selectedNodeID || selectedNodeID === rawHierarchy.data.getID()) { + root = rawHierarchy; } + else { + const selectedNode = rawHierarchyID.get(selectedNodeID)!; + const ancestors = selectedNode.ancestors().reverse(); - return new Set(selectedNode.leaves().map(d => d.data.getID())); - }, [selectedNode]); + function writeValue(n: HierarchyNode, value?: number) { + // @ts-expect-error write to readonly + // noinspection JSConstantReassignment + n.value = value; + } - const root = useMemo(() => { - const rootWithSizesAndSorted = rawHierarchy - .sum((node) => { - if (node.getChildren().length === 0) { - if (selectedNode) { - if (!selectedNodeLeaveIDSet.has(node.getID())) { - return 0; - } - } + root = shallowCopy(rawHierarchy); + writeValue(root, selectedNode.value); - return node.getSize(); - } - return 0; - }) - .sort((a, b) => a.data.getSize() - b.data.getSize()); + let cur = root; + for (let i = 1; i < ancestors.length; i++) { + // use shallowCopy + const node = shallowCopy(ancestors[i]); + writeValue(node, selectedNode.value); + cur.children = [node]; + cur = node; + } + } - return layout(rootWithSizesAndSorted); - }, [layout, rawHierarchy, selectedNode, selectedNodeLeaveIDSet]); + return layout(root!); + }, [layout, rawHierarchy, rawHierarchyID, selectedNodeID]); - const nestedData = useMemo(() => { - const nestedDataMap = group( - root.descendants(), + const layers = useMemo(() => { + const layerMap = group( + layoutRoot.descendants(), (d: HierarchyNode) => d.height, ); - const nested = Array.from(nestedDataMap, ([key, values]) => ({ + const layerArray = Array.from(layerMap, ([key, values]) => ({ key, values, })); - nested.sort((a, b) => b.key - a.key); - return nested; - }, [root]); - - const allNodes = useMemo(() => { - const cache = new Map>(); - root.descendants().forEach((node) => { - cache.set(node.data.getID(), node); - }); - return cache; - }, [root]); + layerArray.sort((a, b) => b.key - a.key); + return layerArray; + }, [layoutRoot]); useEffect(() => { - if (selectedNode === null) { + if (selectedNodeID === null) { if (location.hash !== "") { history.replaceState(null, "", " "); } return; } - + const selectedNode = rawHierarchyID.get(selectedNodeID); + if (!selectedNode) { + return; + } const path = `#${selectedNode .ancestors() .map((d) => { @@ -135,27 +156,21 @@ function TreeMap({ entry }: TreeMapProps) { if (location.hash !== path) { history.replaceState(null, "", path); } - }, [selectedNode]); + }, [rawHierarchyID, selectedNodeID]); - const [showTooltip, setShowTooltip] = useState(false); - const [tooltipPosition, setTooltipPosition] = useState<[number, number]>([0, 0]); const [tooltipNode, setTooltipNode] - = useState | undefined>(undefined); - - const onMouseEnter = useCallback(() => { - setShowTooltip(true); - }, []); - - const onMouseLeave = useCallback(() => { - setShowTooltip(false); - }, []); - - const getTargetNode = useCallback((e: React.MouseEvent) => { - if (!e.target) { - return null; - } - - const target = (e.target as SVGElement).parentNode; + = useState(undefined); + const svgRef = useRef(null); + + const { + clientX, + clientY, + isOver, + eventTarget: mouseEventTarget, + } = useMouse(svgRef); + + const getTargetNode = useCallback((e: EventTarget) => { + const target = (e as SVGElement).parentNode; if (!target) { return null; } @@ -167,85 +182,83 @@ function TreeMap({ entry }: TreeMapProps) { const dataId = Number.parseInt(dataIdStr); - return allNodes.get(dataId) ?? null; - }, [allNodes]); - - const onMouseMove = useCallback((e: React.MouseEvent) => { - setTooltipPosition([e.clientX, e.clientY]); + return rawHierarchyID.get(dataId)?.data ?? null; + }, [rawHierarchyID]); - const node = getTargetNode(e); + const onClick = useCallback((e: React.MouseEvent) => { + const node = getTargetNode(e.target); if (node === null) { - setTooltipNode(undefined); return; } - setTooltipNode(node); - }, [getTargetNode]); - const onClick = useCallback((e: React.MouseEvent) => { - const node = getTargetNode(e); - if (node === null) { + if (e.ctrlKey) { + console.log(node); return; } - if (selectedNode?.data.getID() === node.data.getID()) { - setSelectedNode(null); + if (selectedNodeID === node.getID()) { + setSelectedNodeID(null); } else { - setSelectedNode(node); + setSelectedNodeID(node.getID()); } - }, [getTargetNode, selectedNode]); + }, [getTargetNode, selectedNodeID]); + + const tooltipVisible = useMemo(() => { + return isOver && tooltipNode; + }, [isOver, tooltipNode]); + + useEffect(() => { + if (!mouseEventTarget) { + return; + } + const node = getTargetNode(mouseEventTarget); + if (node) { + setTooltipNode(node); + } + }, [getTargetNode, mouseEventTarget]); const nodes = useMemo(() => { - const selectedID = selectedNode?.data.getID(); - - return ( - nestedData.map(({ key, values }) => { - return ( - - {values.map((node) => { - const { backgroundColor, fontColor } = getModuleColor(node); - - if (node.x0 === node.x1 || node.y0 === node.y1) { - return null; - } - - return ( - - ); - }).filter(Boolean)} - - ); - }) - ); - }, [getModuleColor, nestedData, selectedNode]); + return layers.map(({ key, values }) => { + return ( + + {values.map((node) => { + const { backgroundColor, fontColor } = getModuleColor(node.data.getID()); + + if (node.x1 - node.x0 < 6 || node.y1 - node.y0 < 6) { + return null; + } - const tooltipVisible = useMemo(() => { - return showTooltip && tooltipNode && tooltipPosition.every(v => v > 0); - }, [showTooltip, tooltipNode, tooltipPosition]); + return ( + + ); + }).filter(Boolean)} + + ); + }); + }, [getModuleColor, layers, selectedNodeID]); return ( <> - {(tooltipVisible) && } + {(tooltipVisible) && } {nodes} diff --git a/ui/src/__snapshots__/Treemap.test.tsx.snap b/ui/src/__snapshots__/Treemap.test.tsx.snap index 0ce87ee677..660d7dadfe 100644 --- a/ui/src/__snapshots__/Treemap.test.tsx.snap +++ b/ui/src/__snapshots__/Treemap.test.tsx.snap @@ -40,14 +40,14 @@ exports[`treeMap > render snapshot 1`] = ` render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="274.5" + x="275" y="11" > Std Packages Size @@ -71,8 +71,8 @@ exports[`treeMap > render snapshot 1`] = ` transform="translate(0,20)" > render snapshot 1`] = ` text-anchor="middle" transform="scale(1.00)" x="236.5" - y="7" + y="7.5" > Generated Packages Size @@ -95,8 +95,8 @@ exports[`treeMap > render snapshot 1`] = ` transform="translate(0,36)" > render snapshot 1`] = ` text-anchor="middle" transform="scale(1.00)" x="236.5" - y="8" + y="8.5" > Main Packages Size - - - - math - - render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="19.5" + x="20.5" y="11" > unicode @@ -164,14 +140,14 @@ exports[`treeMap > render snapshot 1`] = ` render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="62" + x="62.5" y="11" > io @@ -191,11 +167,11 @@ exports[`treeMap > render snapshot 1`] = ` transform="translate(508,65)" > render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="17" + x="17.5" y="11" > sync @@ -212,14 +188,14 @@ exports[`treeMap > render snapshot 1`] = ` render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="274.5" + x="275" y="11" > runtime @@ -243,7 +219,7 @@ exports[`treeMap > render snapshot 1`] = ` transform="translate(0,54)" > render snapshot 1`] = ` Unknown Sections Size - - - - os/signal - - - - - - path - - render snapshot 1`] = ` render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="5" + x="6" y="11" > internal/itoa @@ -363,11 +291,11 @@ exports[`treeMap > render snapshot 1`] = ` transform="translate(511,40)" > render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="6" + x="6.5" y="11" > errors @@ -387,8 +315,8 @@ exports[`treeMap > render snapshot 1`] = ` transform="translate(525,40)" > render snapshot 1`] = ` transform="translate(591,40)" > render snapshot 1`] = ` render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="31.5" + x="32.5" y="11" > strconv @@ -459,8 +387,8 @@ exports[`treeMap > render snapshot 1`] = ` transform="translate(721,40)" > render snapshot 1`] = ` render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="49" + x="49.5" y="11" > internal/abi @@ -504,14 +432,14 @@ exports[`treeMap > render snapshot 1`] = ` render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="15.5" + x="16.5" y="11" > embed @@ -531,11 +459,11 @@ exports[`treeMap > render snapshot 1`] = ` transform="translate(544,65)" > render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="23.5" + x="24" y="11" > syscall @@ -555,8 +483,8 @@ exports[`treeMap > render snapshot 1`] = ` transform="translate(593,65)" > render snapshot 1`] = ` render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="166.5" + x="167" y="11" > time @@ -599,135 +527,139 @@ exports[`treeMap > render snapshot 1`] = ` - bits + atomic - utf8 + internal/sys - fs + debug - atomic + internal/syscall - internal/sys + internal/atomic + + render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="2.5" - y="9" + x="10.5" + y="46.5" > - debug + .data render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="8" - y="9" + x="28" + y="46.5" > - internal/syscall + .debug_ranges render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="32.5" - y="11" + x="64.5" + y="46.5" > - internal/atomic + .debug_frame - - render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="2" - y="1" + x="132" + y="46.5" > - .debug_gdb_scripts + .symtab render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="3.5" - y="1" + x="64.5" + y="97.5" > - .itablink + .strtab render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="4" - y="1" + x="84.5" + y="97.5" > - .note.go.buildid + .debug_line render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="9.5" - y="1" + x="86.5" + y="97.5" > - .shstrtab + .debug_loc - - .go.buildinfo - - - - - - .debug_abbrev - - - - - - .typelink - - - - - - .noptrdata - - - - - - .data - - - - - - .debug_ranges - - - - - - .debug_frame - - - - - - .symtab - - - - - - .strtab - - - - - - .debug_line - - - - - - .debug_loc - - - - - - .rodata - - - - - - .gopclntab - - - - - - .debug_info - - - - - - sigqueue.go - - - - - - match.go - - - - - - errors.go - - - - - - itoa.go - - - - - - errors.go - - - - - - index_amd64.go - - - - - - equal_amd64.s - - - - - - indexbyte_amd64.s - - - - - - compare_amd64.s - - - - - - casetables.go - - - - - - runtime1.go - - - - - - <autogenerated> - - - - - - type.go - - - - - - atof.go - - - - - - itoa.go - - - - - - cpu_x86.s - - - - - - cpu.go - - - - - - cpu_x86.go - - - - - - unsafestring_go120.go - - - - - - <autogenerated> - - - - - - type.go - - - - - - io.go - - - - - - embed.go - - - - - - <autogenerated> - - - - - - runtime.go - - - - - - mgc.go - - - - - - map.go - - - - - - mprof.go - - - - - - panic.go - - - - - - proc.go - - - - - - rwmutex.go - - - - - - pool.go - - - - - - sema.go - - - - - - once.go - - - - - - mutex.go - - - - - - syscall_linux.go - - - - - - rlimit_stub.go - - - - - - runtime.go - - - - - - rlimit.go - - - - - - <autogenerated> - - - - - - syscall_unix.go - - - - - - syscall.go - - - - - - syscall_linux.go - - - - - - errors - - - - - - env_unix.go - - - - - - zsyscall_linux_amd64.go - - - - - - mbitmap.go - - - - - - abi.go - - - - - - runtime1.go - - - - render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="19.5" - y="4.5" + x="149" + y="99" > - <autogenerated> + .rodata render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="19.5" - y="38" + x="149" + y="100.5" > - type.go + .gopclntab render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="25.5" - y="43.5" + x="87" + y="200" > - value.go + .debug_info - utcLoc + embed.go - localLoc + mprof.go - zoneinfo_goroot.go + panic.go - time_linux_amd64.s + proc.go - time.go + rwmutex.go - <autogenerated> + pool.go - sys_unix.go + sema.go - format_rfc3339.go + once.go - zoneinfo_unix.go + mutex.go - time.go + runtime.go - zoneinfo.go + rlimit.go - zoneinfo_read.go + <autogenerated> - format.go + syscall_unix.go - nbpipe_pipe2.go + syscall.go - write_err.go + syscall_linux.go - cpuflags_amd64.go + errors - lockrank.go + env_unix.go - modinfo.string + zsyscall_linux_amd64.go - retry.go + <autogenerated> - sys_x86.go + type.go - size_to_class128 + value.go - sigprofCallers + zoneinfo_goroot.go - stackpool + time_linux_amd64.s - handlingSig + time.go - fastlog2Table + <autogenerated> - fastlog2.go + sys_unix.go - class_to_divmagic + format_rfc3339.go - equal_amd64.s + zoneinfo_unix.go - os_nonopenbsd.go + time.go - preempt_nonwindows.go + zoneinfo.go - security_linux.go + zoneinfo_read.go - histogram.go + format.go msize.go @@ -3268,23 +1684,23 @@ exports[`treeMap > render snapshot 1`] = ` atomic_pointer.go @@ -3292,23 +1708,23 @@ exports[`treeMap > render snapshot 1`] = ` gcController @@ -3316,23 +1732,23 @@ exports[`treeMap > render snapshot 1`] = ` g0 @@ -3340,23 +1756,23 @@ exports[`treeMap > render snapshot 1`] = ` extern.go @@ -3364,23 +1780,23 @@ exports[`treeMap > render snapshot 1`] = ` time_nofake.go @@ -3388,23 +1804,23 @@ exports[`treeMap > render snapshot 1`] = ` tagptr_64bit.go @@ -3412,23 +1828,23 @@ exports[`treeMap > render snapshot 1`] = ` printBacklog @@ -3436,23 +1852,23 @@ exports[`treeMap > render snapshot 1`] = ` waitReasonStrings @@ -3460,23 +1876,23 @@ exports[`treeMap > render snapshot 1`] = ` fwdSig @@ -3484,23 +1900,23 @@ exports[`treeMap > render snapshot 1`] = ` os_linux_generic.go @@ -3508,23 +1924,23 @@ exports[`treeMap > render snapshot 1`] = ` preempt_amd64.s @@ -3532,23 +1948,23 @@ exports[`treeMap > render snapshot 1`] = ` stackLarge @@ -3556,23 +1972,23 @@ exports[`treeMap > render snapshot 1`] = ` runtime.go @@ -3580,23 +1996,23 @@ exports[`treeMap > render snapshot 1`] = ` work @@ -3604,23 +2020,23 @@ exports[`treeMap > render snapshot 1`] = ` utf8.go @@ -3628,23 +2044,23 @@ exports[`treeMap > render snapshot 1`] = ` firstmoduledata @@ -3652,23 +2068,23 @@ exports[`treeMap > render snapshot 1`] = ` cgo_sigaction.go @@ -3676,23 +2092,23 @@ exports[`treeMap > render snapshot 1`] = ` env_posix.go @@ -3700,23 +2116,23 @@ exports[`treeMap > render snapshot 1`] = ` sigqueue.go @@ -3724,23 +2140,23 @@ exports[`treeMap > render snapshot 1`] = ` pagetrace_off.go @@ -3748,23 +2164,23 @@ exports[`treeMap > render snapshot 1`] = ` float.go @@ -3772,23 +2188,23 @@ exports[`treeMap > render snapshot 1`] = ` exithook.go @@ -3796,23 +2212,23 @@ exports[`treeMap > render snapshot 1`] = ` memclr_amd64.s @@ -3820,23 +2236,23 @@ exports[`treeMap > render snapshot 1`] = ` mfixalloc.go @@ -3844,23 +2260,23 @@ exports[`treeMap > render snapshot 1`] = ` cgocall.go @@ -3868,23 +2284,23 @@ exports[`treeMap > render snapshot 1`] = ` m0 @@ -3892,23 +2308,23 @@ exports[`treeMap > render snapshot 1`] = ` cgo_mmap.go @@ -3916,23 +2332,23 @@ exports[`treeMap > render snapshot 1`] = ` zeroVal @@ -3940,23 +2356,23 @@ exports[`treeMap > render snapshot 1`] = ` auxvreadbuf @@ -3964,23 +2380,23 @@ exports[`treeMap > render snapshot 1`] = ` pinner.go @@ -3988,23 +2404,23 @@ exports[`treeMap > render snapshot 1`] = ` unsafe.go @@ -4012,23 +2428,23 @@ exports[`treeMap > render snapshot 1`] = ` arena.go @@ -4036,23 +2452,23 @@ exports[`treeMap > render snapshot 1`] = ` mfinal.go @@ -4060,23 +2476,23 @@ exports[`treeMap > render snapshot 1`] = ` rwmutex.go @@ -4084,23 +2500,23 @@ exports[`treeMap > render snapshot 1`] = ` mbarrier.go @@ -4108,23 +2524,23 @@ exports[`treeMap > render snapshot 1`] = ` mcheckmark.go @@ -4132,23 +2548,23 @@ exports[`treeMap > render snapshot 1`] = ` security_unix.go @@ -4156,23 +2572,23 @@ exports[`treeMap > render snapshot 1`] = ` netpoll.go @@ -4180,22 +2596,22 @@ exports[`treeMap > render snapshot 1`] = ` stubs.go @@ -4204,23 +2620,23 @@ exports[`treeMap > render snapshot 1`] = ` cpuprof.go @@ -4228,23 +2644,23 @@ exports[`treeMap > render snapshot 1`] = ` lfstack.go @@ -4252,23 +2668,23 @@ exports[`treeMap > render snapshot 1`] = ` duff_amd64.s @@ -4276,22 +2692,22 @@ exports[`treeMap > render snapshot 1`] = ` sigtable @@ -4300,23 +2716,23 @@ exports[`treeMap > render snapshot 1`] = ` symtabinl.go @@ -4324,23 +2740,23 @@ exports[`treeMap > render snapshot 1`] = ` sched @@ -4348,22 +2764,22 @@ exports[`treeMap > render snapshot 1`] = ` mstats.go @@ -4372,23 +2788,23 @@ exports[`treeMap > render snapshot 1`] = ` mem.go @@ -4396,22 +2812,22 @@ exports[`treeMap > render snapshot 1`] = ` lockrank_off.go @@ -4420,23 +2836,23 @@ exports[`treeMap > render snapshot 1`] = ` mwbbuf.go @@ -4444,23 +2860,23 @@ exports[`treeMap > render snapshot 1`] = ` netpoll_epoll.go @@ -4468,22 +2884,22 @@ exports[`treeMap > render snapshot 1`] = ` memmove_amd64.s @@ -4492,23 +2908,23 @@ exports[`treeMap > render snapshot 1`] = ` staticuint64s @@ -4516,23 +2932,23 @@ exports[`treeMap > render snapshot 1`] = ` hash64.go @@ -4540,23 +2956,23 @@ exports[`treeMap > render snapshot 1`] = ` runtime2.go @@ -4564,23 +2980,23 @@ exports[`treeMap > render snapshot 1`] = ` mgcstack.go @@ -4588,23 +3004,23 @@ exports[`treeMap > render snapshot 1`] = ` mpagecache.go @@ -4612,23 +3028,23 @@ exports[`treeMap > render snapshot 1`] = ` slice.go @@ -4636,23 +3052,23 @@ exports[`treeMap > render snapshot 1`] = ` mcentral.go @@ -4660,23 +3076,23 @@ exports[`treeMap > render snapshot 1`] = ` signal_amd64.go @@ -4684,22 +3100,22 @@ exports[`treeMap > render snapshot 1`] = ` mem_linux.go @@ -4711,19 +3127,19 @@ exports[`treeMap > render snapshot 1`] = ` transform="translate(509,222)" > stkframe.go @@ -4735,7 +3151,7 @@ exports[`treeMap > render snapshot 1`] = ` transform="translate(534,222)" > render snapshot 1`] = ` /> render snapshot 1`] = ` map_fast64.go @@ -4780,22 +3196,22 @@ exports[`treeMap > render snapshot 1`] = ` debugcall.go @@ -4804,22 +3220,22 @@ exports[`treeMap > render snapshot 1`] = ` lock_futex.go @@ -4831,7 +3247,7 @@ exports[`treeMap > render snapshot 1`] = ` transform="translate(645,222)" > render snapshot 1`] = ` /> render snapshot 1`] = ` mpagealloc_64bit.go @@ -4876,22 +3292,22 @@ exports[`treeMap > render snapshot 1`] = ` map_fast32.go @@ -4900,22 +3316,22 @@ exports[`treeMap > render snapshot 1`] = ` vdso_linux.go @@ -4924,22 +3340,22 @@ exports[`treeMap > render snapshot 1`] = ` itabTableInit @@ -4948,22 +3364,22 @@ exports[`treeMap > render snapshot 1`] = ` profbuf.go @@ -4972,22 +3388,22 @@ exports[`treeMap > render snapshot 1`] = ` signal_linux_amd64.go @@ -4996,22 +3412,22 @@ exports[`treeMap > render snapshot 1`] = ` alg.go @@ -5023,19 +3439,19 @@ exports[`treeMap > render snapshot 1`] = ` transform="translate(907,222)" > mspanset.go @@ -5047,7 +3463,7 @@ exports[`treeMap > render snapshot 1`] = ` transform="translate(944,222)" > render snapshot 1`] = ` /> render snapshot 1`] = ` sema.go @@ -5092,23 +3508,23 @@ exports[`treeMap > render snapshot 1`] = ` runtime1.go @@ -5119,20 +3535,20 @@ exports[`treeMap > render snapshot 1`] = ` transform="translate(509,305)" > print.go @@ -5143,7 +3559,7 @@ exports[`treeMap > render snapshot 1`] = ` transform="translate(509,338)" > render snapshot 1`] = ` /> render snapshot 1`] = ` iface.go @@ -5188,23 +3604,23 @@ exports[`treeMap > render snapshot 1`] = ` string.go @@ -5212,23 +3628,23 @@ exports[`treeMap > render snapshot 1`] = ` mranges.go @@ -5236,23 +3652,23 @@ exports[`treeMap > render snapshot 1`] = ` map_faststr.go @@ -5260,23 +3676,23 @@ exports[`treeMap > render snapshot 1`] = ` mpallocbits.go @@ -5284,23 +3700,23 @@ exports[`treeMap > render snapshot 1`] = ` sys_linux_amd64.s @@ -5311,7 +3727,7 @@ exports[`treeMap > render snapshot 1`] = ` transform="translate(509,638)" > render snapshot 1`] = ` /> render snapshot 1`] = ` error.go @@ -5356,23 +3772,23 @@ exports[`treeMap > render snapshot 1`] = ` chan.go @@ -5380,23 +3796,23 @@ exports[`treeMap > render snapshot 1`] = ` cpuprof @@ -5404,23 +3820,23 @@ exports[`treeMap > render snapshot 1`] = ` type.go @@ -5428,23 +3844,23 @@ exports[`treeMap > render snapshot 1`] = ` memstats @@ -5452,23 +3868,23 @@ exports[`treeMap > render snapshot 1`] = ` asm_amd64.s @@ -5476,23 +3892,23 @@ exports[`treeMap > render snapshot 1`] = ` os_linux.go @@ -5500,23 +3916,23 @@ exports[`treeMap > render snapshot 1`] = ` mprof.go @@ -5524,23 +3940,23 @@ exports[`treeMap > render snapshot 1`] = ` malloc.go @@ -5548,23 +3964,23 @@ exports[`treeMap > render snapshot 1`] = ` time.go @@ -5572,23 +3988,23 @@ exports[`treeMap > render snapshot 1`] = ` map.go @@ -5596,23 +4012,23 @@ exports[`treeMap > render snapshot 1`] = ` mgcsweep.go @@ -5620,23 +4036,23 @@ exports[`treeMap > render snapshot 1`] = ` mgcpacer.go @@ -5644,23 +4060,23 @@ exports[`treeMap > render snapshot 1`] = ` signal_unix.go @@ -5668,23 +4084,23 @@ exports[`treeMap > render snapshot 1`] = ` mpagealloc.go @@ -5692,22 +4108,22 @@ exports[`treeMap > render snapshot 1`] = ` mbitmap.go @@ -5716,23 +4132,23 @@ exports[`treeMap > render snapshot 1`] = ` mgcscavenge.go @@ -5740,23 +4156,23 @@ exports[`treeMap > render snapshot 1`] = ` stack.go @@ -5764,23 +4180,23 @@ exports[`treeMap > render snapshot 1`] = ` symtab.go @@ -5788,23 +4204,23 @@ exports[`treeMap > render snapshot 1`] = ` trace.go @@ -5812,23 +4228,23 @@ exports[`treeMap > render snapshot 1`] = ` mgc.go @@ -5836,23 +4252,23 @@ exports[`treeMap > render snapshot 1`] = ` semtable @@ -5860,23 +4276,23 @@ exports[`treeMap > render snapshot 1`] = ` mgcmark.go @@ -5884,23 +4300,23 @@ exports[`treeMap > render snapshot 1`] = ` panic.go @@ -5908,23 +4324,23 @@ exports[`treeMap > render snapshot 1`] = ` mheap.go @@ -5932,23 +4348,23 @@ exports[`treeMap > render snapshot 1`] = ` traceback.go @@ -5956,23 +4372,23 @@ exports[`treeMap > render snapshot 1`] = ` trace @@ -5980,23 +4396,23 @@ exports[`treeMap > render snapshot 1`] = ` proc.go @@ -6004,38 +4420,14 @@ exports[`treeMap > render snapshot 1`] = ` - - - mheap_ - - - render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="1" - y="8.5" + x="60" + y="155" > - atomic_pointer.go + mheap_ render snapshot 1`] = ` font-size="0.8em" text-anchor="middle" transform="scale(1.00)" - x="30.5" - y="8.5" + x="31" + y="9.5" > types.go diff --git a/ui/src/tool/copy.ts b/ui/src/tool/copy.ts new file mode 100644 index 0000000000..e78b748166 --- /dev/null +++ b/ui/src/tool/copy.ts @@ -0,0 +1,4 @@ +export function shallowCopy(obj: T): T { + const copy = Object.create(Object.getPrototypeOf(obj)); + return Object.assign(copy, obj); +} diff --git a/ui/src/tool/useMouse.ts b/ui/src/tool/useMouse.ts new file mode 100644 index 0000000000..64ea5f41f0 --- /dev/null +++ b/ui/src/tool/useMouse.ts @@ -0,0 +1,60 @@ +import type { RefObject } from "react"; +import { useCallback, useState } from "react"; +import { useLifecycles } from "react-use"; + +export interface useMouseResult { + clientX: number | null; + clientY: number | null; + isOver: boolean; + eventTarget: EventTarget | null; +} + +export function useMouse(ref: RefObject): useMouseResult { + const [clientX, setClientX] = useState(null); + const [clientY, setClientY] = useState(null); + const [eventTarget, setEventTarget] = useState(null); + + const [isOver, setIsOver] = useState(false); + + const onMouseMove = useCallback((e: MouseEvent) => { + setClientX(e.clientX); + setClientY(e.clientY); + + if (e.target !== eventTarget) { + setEventTarget(e.target); + } + }, [eventTarget]); + + const onMouseOver = useCallback(() => { + setIsOver(true); + }, []); + + const onMouseOut = useCallback(() => { + setIsOver(false); + }, []); + + const mount = useCallback(() => { + if (ref.current) { + ref.current.addEventListener("mousemove", onMouseMove); + ref.current.addEventListener("mouseover", onMouseOver); + ref.current.addEventListener("mouseout", onMouseOut); + } + }, [onMouseMove, onMouseOut, onMouseOver, ref]); + + const unmount = useCallback(() => { + if (ref.current) { + ref.current.removeEventListener("mousemove", onMouseMove); + ref.current.removeEventListener("mouseover", onMouseOver); + ref.current.removeEventListener("mouseout", onMouseOut); + } + }, [onMouseMove, onMouseOut, onMouseOver, ref]); + + useLifecycles(mount, unmount); + + return { + clientX, + clientY, + isOver, + eventTarget, + }; +} diff --git a/ui/vite.config.ts b/ui/vite.config.ts index 2911099c19..f9afd457f4 100644 --- a/ui/vite.config.ts +++ b/ui/vite.config.ts @@ -14,8 +14,17 @@ function getPlaceHolder(): string { } try { + let target: URL; + + if (fs.existsSync("../data.json")) { + target = new URL("../data.json", import.meta.url); + } + else { + target = new URL("../testdata/result.json", import.meta.url); + } + return fs.readFileSync( - new URL("../testdata/result.json", import.meta.url), + target, "utf-8", ); }