@grafana/flamegraph
Version:
Grafana flamegraph visualization component
1 lines • 16.9 kB
Source Map (JSON)
{"version":3,"file":"FlameGraphCanvas.mjs","sources":["../../../src/FlameGraph/FlameGraphCanvas.tsx"],"sourcesContent":["import { css } from '@emotion/css';\nimport { MouseEvent as ReactMouseEvent, useCallback, useEffect, useRef, useState } from 'react';\nimport * as React from 'react';\nimport { useMeasure } from 'react-use';\n\nimport { PIXELS_PER_LEVEL } from '../constants';\nimport { ClickedItemData, ColorScheme, ColorSchemeDiff, SelectedView, TextAlign } from '../types';\n\nimport FlameGraphContextMenu, { GetExtraContextMenuButtonsFunction } from './FlameGraphContextMenu';\nimport FlameGraphTooltip from './FlameGraphTooltip';\nimport { CollapsedMap, FlameGraphDataContainer, LevelItem } from './dataTransform';\nimport { getBarX, useFlameRender } from './rendering';\n\ntype Props = {\n data: FlameGraphDataContainer;\n rangeMin: number;\n rangeMax: number;\n matchedLabels: Set<string> | undefined;\n setRangeMin: (range: number) => void;\n setRangeMax: (range: number) => void;\n style?: React.CSSProperties;\n onItemFocused: (data: ClickedItemData) => void;\n focusedItemData?: ClickedItemData;\n textAlign: TextAlign;\n onSandwich: (label: string) => void;\n colorScheme: ColorScheme | ColorSchemeDiff;\n\n root: LevelItem;\n direction: 'children' | 'parents';\n // Depth in number of levels\n depth: number;\n\n totalProfileTicks: number;\n totalProfileTicksRight?: number;\n totalViewTicks: number;\n showFlameGraphOnly?: boolean;\n\n collapsedMap: CollapsedMap;\n setCollapsedMap: (collapsedMap: CollapsedMap) => void;\n collapsing?: boolean;\n getExtraContextMenuButtons?: GetExtraContextMenuButtonsFunction;\n\n selectedView: SelectedView;\n search: string;\n};\n\nconst FlameGraphCanvas = ({\n data,\n rangeMin,\n rangeMax,\n matchedLabels,\n setRangeMin,\n setRangeMax,\n onItemFocused,\n focusedItemData,\n textAlign,\n onSandwich,\n colorScheme,\n totalProfileTicks,\n totalProfileTicksRight,\n totalViewTicks,\n root,\n direction,\n depth,\n showFlameGraphOnly,\n collapsedMap,\n setCollapsedMap,\n collapsing,\n getExtraContextMenuButtons,\n selectedView,\n search,\n}: Props) => {\n const styles = getStyles();\n\n const [sizeRef, { width: wrapperWidth }] = useMeasure<HTMLDivElement>();\n const graphRef = useRef<HTMLCanvasElement>(null);\n const [tooltipItem, setTooltipItem] = useState<LevelItem>();\n\n const [clickedItemData, setClickedItemData] = useState<ClickedItemData>();\n\n useFlameRender({\n canvasRef: graphRef,\n colorScheme,\n data,\n focusedItemData,\n root,\n direction,\n depth,\n rangeMax,\n rangeMin,\n matchedLabels,\n textAlign,\n totalViewTicks,\n // We need this so that if we have a diff profile and are in sandwich view we still show the same diff colors.\n totalColorTicks: data.isDiffFlamegraph() ? totalProfileTicks : totalViewTicks,\n totalTicksRight: totalProfileTicksRight,\n wrapperWidth,\n collapsedMap,\n });\n\n const onGraphClick = useCallback(\n (e: ReactMouseEvent<HTMLCanvasElement>) => {\n setTooltipItem(undefined);\n const pixelsPerTick = graphRef.current!.clientWidth / totalViewTicks / (rangeMax - rangeMin);\n const item = convertPixelCoordinatesToBarCoordinates(\n { x: e.nativeEvent.offsetX, y: e.nativeEvent.offsetY },\n root,\n direction,\n depth,\n pixelsPerTick,\n totalViewTicks,\n rangeMin,\n collapsedMap\n );\n\n // if clicking on a block in the canvas\n if (item) {\n setClickedItemData({\n posY: e.clientY,\n posX: e.clientX,\n item,\n label: data.getLabel(item.itemIndexes[0]),\n });\n } else {\n // if clicking on the canvas but there is no block beneath the cursor\n setClickedItemData(undefined);\n }\n },\n [data, rangeMin, rangeMax, totalViewTicks, root, direction, depth, collapsedMap]\n );\n\n const [mousePosition, setMousePosition] = useState<{ x: number; y: number }>();\n const onGraphMouseMove = useCallback(\n (e: ReactMouseEvent<HTMLCanvasElement>) => {\n if (clickedItemData === undefined) {\n setTooltipItem(undefined);\n setMousePosition(undefined);\n const pixelsPerTick = graphRef.current!.clientWidth / totalViewTicks / (rangeMax - rangeMin);\n const item = convertPixelCoordinatesToBarCoordinates(\n { x: e.nativeEvent.offsetX, y: e.nativeEvent.offsetY },\n root,\n direction,\n depth,\n pixelsPerTick,\n totalViewTicks,\n rangeMin,\n collapsedMap\n );\n\n if (item) {\n setMousePosition({ x: e.clientX, y: e.clientY });\n setTooltipItem(item);\n }\n }\n },\n [rangeMin, rangeMax, totalViewTicks, clickedItemData, setMousePosition, root, direction, depth, collapsedMap]\n );\n\n const onGraphMouseLeave = useCallback(() => {\n setTooltipItem(undefined);\n }, []);\n\n // hide context menu if outside the flame graph canvas is clicked\n useEffect(() => {\n const handleOnClick = (e: MouseEvent) => {\n if (\n e.target instanceof HTMLElement &&\n e.target.parentElement?.id !== 'flameGraphCanvasContainer_clickOutsideCheck'\n ) {\n setClickedItemData(undefined);\n }\n };\n window.addEventListener('click', handleOnClick);\n return () => window.removeEventListener('click', handleOnClick);\n }, [setClickedItemData]);\n\n return (\n <div className={styles.graph}>\n <div className={styles.canvasWrapper} id=\"flameGraphCanvasContainer_clickOutsideCheck\" ref={sizeRef}>\n <canvas\n ref={graphRef}\n data-testid=\"flameGraph\"\n onClick={onGraphClick}\n onMouseMove={onGraphMouseMove}\n onMouseLeave={onGraphMouseLeave}\n />\n </div>\n <FlameGraphTooltip\n position={mousePosition}\n item={tooltipItem}\n data={data}\n totalTicks={totalViewTicks}\n collapseConfig={tooltipItem ? collapsedMap.get(tooltipItem) : undefined}\n />\n {!showFlameGraphOnly && clickedItemData && (\n <FlameGraphContextMenu\n data={data}\n itemData={clickedItemData}\n collapsing={collapsing}\n collapseConfig={collapsedMap.get(clickedItemData.item)}\n onMenuItemClick={() => {\n setClickedItemData(undefined);\n }}\n onItemFocus={() => {\n setRangeMin(clickedItemData.item.start / totalViewTicks);\n setRangeMax((clickedItemData.item.start + clickedItemData.item.value) / totalViewTicks);\n onItemFocused(clickedItemData);\n }}\n onSandwich={() => {\n onSandwich(data.getLabel(clickedItemData.item.itemIndexes[0]));\n }}\n onExpandGroup={() => {\n setCollapsedMap(collapsedMap.setCollapsedStatus(clickedItemData.item, false));\n }}\n onCollapseGroup={() => {\n setCollapsedMap(collapsedMap.setCollapsedStatus(clickedItemData.item, true));\n }}\n onExpandAllGroups={() => {\n setCollapsedMap(collapsedMap.setAllCollapsedStatus(false));\n }}\n onCollapseAllGroups={() => {\n setCollapsedMap(collapsedMap.setAllCollapsedStatus(true));\n }}\n allGroupsCollapsed={Array.from(collapsedMap.values()).every((i) => i.collapsed)}\n allGroupsExpanded={Array.from(collapsedMap.values()).every((i) => !i.collapsed)}\n getExtraContextMenuButtons={getExtraContextMenuButtons}\n selectedView={selectedView}\n search={search}\n />\n )}\n </div>\n );\n};\n\nconst getStyles = () => ({\n graph: css({\n label: 'graph',\n overflow: 'auto',\n flexGrow: 1,\n flexBasis: '50%',\n }),\n canvasContainer: css({\n label: 'canvasContainer',\n display: 'flex',\n }),\n canvasWrapper: css({\n label: 'canvasWrapper',\n cursor: 'pointer',\n flex: 1,\n overflow: 'hidden',\n }),\n sandwichMarker: css({\n label: 'sandwichMarker',\n writingMode: 'vertical-lr',\n transform: 'rotate(180deg)',\n overflow: 'hidden',\n whiteSpace: 'nowrap',\n }),\n sandwichMarkerIcon: css({\n label: 'sandwichMarkerIcon',\n verticalAlign: 'baseline',\n }),\n});\n\nexport const convertPixelCoordinatesToBarCoordinates = (\n // position relative to the start of the graph\n pos: { x: number; y: number },\n root: LevelItem,\n direction: 'children' | 'parents',\n depth: number,\n pixelsPerTick: number,\n totalTicks: number,\n rangeMin: number,\n collapsedMap: CollapsedMap\n): LevelItem | undefined => {\n let next: LevelItem | undefined = root;\n let currentLevel = direction === 'children' ? 0 : depth - 1;\n const levelIndex = Math.floor(pos.y / (PIXELS_PER_LEVEL / window.devicePixelRatio));\n let found = undefined;\n\n while (next) {\n const node: LevelItem = next;\n next = undefined;\n if (currentLevel === levelIndex) {\n found = node;\n break;\n }\n\n const nextList = direction === 'children' ? node.children : node.parents || [];\n\n for (const child of nextList) {\n const xStart = getBarX(child.start, totalTicks, rangeMin, pixelsPerTick);\n const xEnd = getBarX(child.start + child.value, totalTicks, rangeMin, pixelsPerTick);\n if (xStart <= pos.x && pos.x < xEnd) {\n next = child;\n // Check if item is a collapsed item. if so also check if the item is the first collapsed item in the chain,\n // which we render, or a child which we don't render. If it's a child in the chain then don't increase the\n // level end effectively skip it.\n const collapsedConfig = collapsedMap.get(child);\n if (!collapsedConfig || !collapsedConfig.collapsed || collapsedConfig.items[0] === child) {\n currentLevel = currentLevel + (direction === 'children' ? 1 : -1);\n }\n break;\n }\n }\n }\n\n return found;\n};\n\nexport default FlameGraphCanvas;\n"],"names":[],"mappings":"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"}