github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/packages/pyroscope-flamegraph/src/Tooltip/TableTooltip.tsx (about) 1 import React, { useCallback, RefObject, Dispatch, SetStateAction } from 'react'; 2 import { Units } from '@pyroscope/models/src/units'; 3 4 import type { FlamegraphPalette } from '../FlameGraph/FlameGraphComponent/colorPalette'; 5 import { Tooltip, TooltipData } from './Tooltip'; 6 import { formatDouble } from './FlamegraphTooltip'; 7 import { getFormatter } from '../format/format'; 8 9 export interface TableTooltipProps { 10 tableBodyRef: RefObject<HTMLTableSectionElement>; 11 numTicks: number; 12 sampleRate: number; 13 units: Units; 14 palette: FlamegraphPalette; 15 } 16 17 export default function TableTooltip({ 18 numTicks, 19 sampleRate, 20 units, 21 tableBodyRef, 22 palette, 23 }: TableTooltipProps) { 24 const formatter = getFormatter(numTicks, sampleRate, units); 25 const totalFlamebearer = formatter.format(numTicks, sampleRate); 26 27 const setTooltipContent = useCallback( 28 ( 29 setContent: Dispatch< 30 SetStateAction<{ 31 title: { 32 text: string; 33 diff: { 34 text: string; 35 color: string; 36 }; 37 }; 38 tooltipData: TooltipData[]; 39 }> 40 >, 41 onMouseOut: () => void, 42 e: MouseEvent 43 ) => { 44 const tableRowElementData = (e.target as Element).closest('tr')?.dataset 45 .row; 46 47 if (!tableRowElementData) { 48 onMouseOut(); 49 return; 50 } 51 const [format, functionName, ...rowValues] = 52 tableRowElementData.split(';'); 53 54 switch (format) { 55 case 'single': { 56 const [self, total] = rowValues; 57 const selfFormatted = formatter.format( 58 parseInt(self, 10), 59 sampleRate 60 ); 61 const totalFormated = formatter.format( 62 parseInt(total, 10), 63 sampleRate 64 ); 65 // todo: i think it will be good to decrease number of calculations here 66 const totalFlamebearerSplitted = totalFlamebearer.split(' '); 67 const totalFlamebearerNoUnitsValue = 68 totalFlamebearerSplitted[0] === '<' 69 ? totalFlamebearerSplitted[1] 70 : totalFlamebearerSplitted[0]; 71 72 const selfSplitted = selfFormatted.split(' '); 73 const selfNoUnitsValue = 74 selfSplitted[0] === '<' ? selfSplitted[1] : selfSplitted[0]; 75 76 const totalSplitted = totalFormated.split(' '); 77 const totalNoUnitsValue = 78 totalSplitted[0] === '<' ? totalSplitted[1] : totalSplitted[0]; 79 80 const newContent: TooltipData = { 81 units, 82 self: `${selfFormatted}(${( 83 (parseFloat(selfNoUnitsValue) / 84 parseFloat(totalFlamebearerNoUnitsValue)) * 85 100 86 ).toFixed(2)}%)`, 87 total: `${totalFormated}(${( 88 (parseFloat(totalNoUnitsValue) / 89 parseFloat(totalFlamebearerNoUnitsValue)) * 90 100 91 ).toFixed(2)}%)`, 92 tooltipType: 'table', 93 }; 94 95 setContent({ 96 title: { 97 text: functionName, 98 diff: { 99 text: '', 100 color: '', 101 }, 102 }, 103 tooltipData: [newContent], 104 }); 105 break; 106 } 107 case 'double': { 108 const [totalLeft, leftTicks, totalRight, rightTicks] = rowValues; 109 const d = formatDouble( 110 { 111 formatter, 112 sampleRate, 113 totalLeft: parseInt(totalLeft, 10), 114 leftTicks: parseInt(leftTicks, 10), 115 totalRight: parseInt(totalRight, 10), 116 rightTicks: parseInt(rightTicks, 10), 117 title: functionName, 118 units, 119 }, 120 palette 121 ); 122 123 setContent({ 124 title: d.title, 125 tooltipData: d.tooltipData, 126 }); 127 128 break; 129 } 130 default: 131 break; 132 } 133 }, 134 [tableBodyRef, numTicks, formatter, sampleRate] 135 ); 136 137 return ( 138 <Tooltip 139 dataSourceRef={tableBodyRef} 140 shouldShowTitle={false} 141 clickInfoSide="left" 142 setTooltipContent={setTooltipContent} 143 /> 144 ); 145 }