@grafana/flamegraph 11.5.0 → 11.6.0-221763
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/README.md +12 -11
- package/dist/esm/FlameGraph/FlameGraph.js +41 -36
- package/dist/esm/FlameGraph/FlameGraph.js.map +1 -1
- package/dist/esm/FlameGraph/FlameGraphCanvas.js +12 -12
- package/dist/esm/FlameGraph/FlameGraphCanvas.js.map +1 -1
- package/dist/esm/FlameGraph/FlameGraphContextMenu.js +1 -1
- package/dist/esm/FlameGraph/FlameGraphContextMenu.js.map +1 -1
- package/dist/esm/FlameGraph/FlameGraphMetadata.js +13 -10
- package/dist/esm/FlameGraph/FlameGraphMetadata.js.map +1 -1
- package/dist/esm/FlameGraph/colors.js +2 -2
- package/dist/esm/FlameGraph/colors.js.map +1 -1
- package/dist/esm/FlameGraph/dataTransform.js +11 -11
- package/dist/esm/FlameGraph/dataTransform.js.map +1 -1
- package/dist/esm/FlameGraph/rendering.js +4 -4
- package/dist/esm/FlameGraph/rendering.js.map +1 -1
- package/dist/esm/FlameGraph/treeTransforms.js +4 -4
- package/dist/esm/FlameGraph/treeTransforms.js.map +1 -1
- package/dist/esm/FlameGraphContainer.js +40 -12
- package/dist/esm/FlameGraphContainer.js.map +1 -1
- package/dist/esm/TopTable/FlameGraphTopTableContainer.js +4 -4
- package/dist/esm/TopTable/FlameGraphTopTableContainer.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +131 -95
- package/dist/index.js.map +1 -1
- package/package.json +11 -11
package/README.md
CHANGED
@@ -26,17 +26,18 @@ import { Flamegraph } from '@grafana/flamegraph';
|
|
26
26
|
|
27
27
|
#### Props
|
28
28
|
|
29
|
-
| Name
|
30
|
-
|
|
31
|
-
| data
|
32
|
-
| stickyHeader
|
33
|
-
| getTheme
|
34
|
-
| onTableSymbolClick
|
35
|
-
| onViewSelected
|
36
|
-
| onTextAlignSelected
|
37
|
-
| onTableSort
|
38
|
-
| extraHeaderElements
|
39
|
-
| vertical
|
29
|
+
| Name | Type | Description |
|
30
|
+
| --------------------- | ------------------------ | --------------------------------------------------------------------------------------------------------------------------- |
|
31
|
+
| data | DataFrame | DataFrame with the profile data. Optional, if missing or empty the flamegraph is not rendered |
|
32
|
+
| stickyHeader | boolean | Whether the header should be sticky and be always visible on the top when scrolling. |
|
33
|
+
| getTheme | () => GrafanaTheme2 | Provides a theme for the visualization on which colors and some sizes are based. |
|
34
|
+
| onTableSymbolClick | (symbol: string) => void | Interaction hook that can be used to report on the interaction. Fires when user click on a name in the table. |
|
35
|
+
| onViewSelected | (view: string) => void | Interaction hook that can be used to report on the interaction. Fires when user changes the view to show (table/graph/both) |
|
36
|
+
| onTextAlignSelected | (align: string) => void | Interaction hook that can be used to report on the interaction. Fires when user changes the text align. |
|
37
|
+
| onTableSort | (sort: string) => void | Interaction hook that can be used to report on the interaction. Fires when user changes the teble sorting. |
|
38
|
+
| extraHeaderElements | React.ReactNode | Elements that will be shown in the header on the right side of the header buttons. Useful for additional functionality. |
|
39
|
+
| vertical | boolean | If true the flamegraph will be rendered on top of the table. |
|
40
|
+
| keepFocusOnDataChange | boolean | If true any focused block will stay focused when the profile data changes. Same for the sandwich view. |
|
40
41
|
|
41
42
|
##### DataFrame schema
|
42
43
|
|
@@ -40,14 +40,14 @@ const FlameGraph = ({
|
|
40
40
|
if (data) {
|
41
41
|
let levels2 = data.getLevels();
|
42
42
|
let totalProfileTicks2 = levels2.length ? levels2[0][0].value : 0;
|
43
|
-
let totalProfileTicksRight2 = levels2.length ? levels2[0][0].valueRight :
|
43
|
+
let totalProfileTicksRight2 = levels2.length ? levels2[0][0].valueRight : undefined;
|
44
44
|
let totalViewTicks2 = totalProfileTicks2;
|
45
|
-
let levelsCallers2 =
|
45
|
+
let levelsCallers2 = undefined;
|
46
46
|
if (sandwichItem) {
|
47
47
|
const [callers, callees] = data.getSandwichLevels(sandwichItem);
|
48
48
|
levels2 = callees;
|
49
49
|
levelsCallers2 = callers;
|
50
|
-
totalViewTicks2 = (_c = (_b = (_a = callees[0]) == null ?
|
50
|
+
totalViewTicks2 = (_c = (_b = (_a = callees[0]) == null ? undefined : _a[0]) == null ? undefined : _b.value) != null ? _c : 0;
|
51
51
|
}
|
52
52
|
setLevels(levels2);
|
53
53
|
setLevelsCallers(levelsCallers2);
|
@@ -82,40 +82,45 @@ const FlameGraph = ({
|
|
82
82
|
search,
|
83
83
|
selectedView
|
84
84
|
};
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
/* @__PURE__ */
|
85
|
+
let canvas = null;
|
86
|
+
if (levelsCallers == null ? undefined : levelsCallers.length) {
|
87
|
+
canvas = /* @__PURE__ */ jsxs(Fragment, { children: [
|
88
|
+
/* @__PURE__ */ jsxs("div", { className: styles.sandwichCanvasWrapper, children: [
|
89
|
+
/* @__PURE__ */ jsxs("div", { className: styles.sandwichMarker, children: [
|
90
|
+
"Callers",
|
91
|
+
/* @__PURE__ */ jsx(Icon, { className: styles.sandwichMarkerIcon, name: "arrow-down" })
|
92
|
+
] }),
|
93
|
+
/* @__PURE__ */ jsx(
|
94
|
+
FlameGraphCanvas,
|
95
|
+
{
|
96
|
+
...commonCanvasProps,
|
97
|
+
root: levelsCallers[levelsCallers.length - 1][0],
|
98
|
+
depth: levelsCallers.length,
|
99
|
+
direction: "parents",
|
100
|
+
collapsing: false
|
101
|
+
}
|
102
|
+
)
|
90
103
|
] }),
|
91
|
-
/* @__PURE__ */
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
] })
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
root: levels[0][0],
|
112
|
-
depth: levels.length,
|
113
|
-
direction: "children",
|
114
|
-
collapsing: false
|
115
|
-
}
|
116
|
-
)
|
117
|
-
] })
|
118
|
-
] }) : /* @__PURE__ */ jsx(FlameGraphCanvas, { ...commonCanvasProps, root: levels[0][0], depth: levels.length, direction: "children" });
|
104
|
+
/* @__PURE__ */ jsxs("div", { className: styles.sandwichCanvasWrapper, children: [
|
105
|
+
/* @__PURE__ */ jsxs("div", { className: cx(styles.sandwichMarker, styles.sandwichMarkerCalees), children: [
|
106
|
+
/* @__PURE__ */ jsx(Icon, { className: styles.sandwichMarkerIcon, name: "arrow-up" }),
|
107
|
+
"Callees"
|
108
|
+
] }),
|
109
|
+
/* @__PURE__ */ jsx(
|
110
|
+
FlameGraphCanvas,
|
111
|
+
{
|
112
|
+
...commonCanvasProps,
|
113
|
+
root: levels[0][0],
|
114
|
+
depth: levels.length,
|
115
|
+
direction: "children",
|
116
|
+
collapsing: false
|
117
|
+
}
|
118
|
+
)
|
119
|
+
] })
|
120
|
+
] });
|
121
|
+
} else if (levels == null ? undefined : levels.length) {
|
122
|
+
canvas = /* @__PURE__ */ jsx(FlameGraphCanvas, { ...commonCanvasProps, root: levels[0][0], depth: levels.length, direction: "children" });
|
123
|
+
}
|
119
124
|
return /* @__PURE__ */ jsxs("div", { className: styles.graph, children: [
|
120
125
|
/* @__PURE__ */ jsx(
|
121
126
|
FlameGraphMetadata,
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"FlameGraph.js","sources":["../../../src/FlameGraph/FlameGraph.tsx"],"sourcesContent":["// This component is based on logic from the flamebearer project\n// https://github.com/mapbox/flamebearer\n\n// ISC License\n\n// Copyright (c) 2018, Mapbox\n\n// Permission to use, copy, modify, and/or distribute this software for any purpose\n// with or without fee is hereby granted, provided that the above copyright notice\n// and this permission notice appear in all copies.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\n// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND\n// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\n// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS\n// OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER\n// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF\n// THIS SOFTWARE.\nimport { css, cx } from '@emotion/css';\nimport { useEffect, useState } from 'react';\nimport * as React from 'react';\n\nimport { Icon } from '@grafana/ui';\n\nimport { PIXELS_PER_LEVEL } from '../constants';\nimport { ClickedItemData, ColorScheme, ColorSchemeDiff, SelectedView, TextAlign } from '../types';\n\nimport FlameGraphCanvas from './FlameGraphCanvas';\nimport { GetExtraContextMenuButtonsFunction } from './FlameGraphContextMenu';\nimport FlameGraphMetadata from './FlameGraphMetadata';\nimport { CollapsedMap, FlameGraphDataContainer, LevelItem } from './dataTransform';\n\ntype Props = {\n data: FlameGraphDataContainer;\n rangeMin: number;\n rangeMax: number;\n matchedLabels?: Set<string>;\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 sandwichItem?: string;\n onSandwich: (label: string) => void;\n onFocusPillClick: () => void;\n onSandwichPillClick: () => void;\n colorScheme: ColorScheme | ColorSchemeDiff;\n showFlameGraphOnly?: boolean;\n getExtraContextMenuButtons?: GetExtraContextMenuButtonsFunction;\n collapsing?: boolean;\n selectedView: SelectedView;\n search: string;\n collapsedMap: CollapsedMap;\n setCollapsedMap: (collapsedMap: CollapsedMap) => void;\n};\n\nconst FlameGraph = ({\n data,\n rangeMin,\n rangeMax,\n matchedLabels,\n setRangeMin,\n setRangeMax,\n onItemFocused,\n focusedItemData,\n textAlign,\n onSandwich,\n sandwichItem,\n onFocusPillClick,\n onSandwichPillClick,\n colorScheme,\n showFlameGraphOnly,\n getExtraContextMenuButtons,\n collapsing,\n selectedView,\n search,\n collapsedMap,\n setCollapsedMap,\n}: Props) => {\n const styles = getStyles();\n\n const [levels, setLevels] = useState<LevelItem[][]>();\n const [levelsCallers, setLevelsCallers] = useState<LevelItem[][]>();\n const [totalProfileTicks, setTotalProfileTicks] = useState<number>(0);\n const [totalProfileTicksRight, setTotalProfileTicksRight] = useState<number>();\n const [totalViewTicks, setTotalViewTicks] = useState<number>(0);\n\n useEffect(() => {\n if (data) {\n let levels = data.getLevels();\n let totalProfileTicks = levels.length ? levels[0][0].value : 0;\n let totalProfileTicksRight = levels.length ? levels[0][0].valueRight : undefined;\n let totalViewTicks = totalProfileTicks;\n let levelsCallers = undefined;\n\n if (sandwichItem) {\n const [callers, callees] = data.getSandwichLevels(sandwichItem);\n levels = callees;\n levelsCallers = callers;\n // We need this separate as in case of diff profile we want to compute diff colors based on the original ticks.\n totalViewTicks = callees[0]?.[0]?.value ?? 0;\n }\n setLevels(levels);\n setLevelsCallers(levelsCallers);\n setTotalProfileTicks(totalProfileTicks);\n setTotalProfileTicksRight(totalProfileTicksRight);\n setTotalViewTicks(totalViewTicks);\n }\n }, [data, sandwichItem]);\n\n if (!levels) {\n return null;\n }\n\n const commonCanvasProps = {\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 showFlameGraphOnly,\n collapsedMap,\n setCollapsedMap,\n getExtraContextMenuButtons,\n collapsing,\n search,\n selectedView,\n };\n const canvas = levelsCallers ? (\n <>\n <div className={styles.sandwichCanvasWrapper}>\n <div className={styles.sandwichMarker}>\n Callers\n <Icon className={styles.sandwichMarkerIcon} name={'arrow-down'} />\n </div>\n <FlameGraphCanvas\n {...commonCanvasProps}\n root={levelsCallers[levelsCallers.length - 1][0]}\n depth={levelsCallers.length}\n direction={'parents'}\n // We do not support collapsing in sandwich view for now.\n collapsing={false}\n />\n </div>\n\n <div className={styles.sandwichCanvasWrapper}>\n <div className={cx(styles.sandwichMarker, styles.sandwichMarkerCalees)}>\n <Icon className={styles.sandwichMarkerIcon} name={'arrow-up'} />\n Callees\n </div>\n <FlameGraphCanvas\n {...commonCanvasProps}\n root={levels[0][0]}\n depth={levels.length}\n direction={'children'}\n collapsing={false}\n />\n </div>\n </>\n ) : (\n <FlameGraphCanvas {...commonCanvasProps} root={levels[0][0]} depth={levels.length} direction={'children'} />\n );\n\n return (\n <div className={styles.graph}>\n <FlameGraphMetadata\n data={data}\n focusedItem={focusedItemData}\n sandwichedLabel={sandwichItem}\n totalTicks={totalViewTicks}\n onFocusPillClick={onFocusPillClick}\n onSandwichPillClick={onSandwichPillClick}\n />\n {canvas}\n </div>\n );\n};\n\nconst getStyles = () => ({\n graph: css({\n label: 'graph',\n overflow: 'auto',\n flexGrow: 1,\n flexBasis: '50%',\n }),\n sandwichCanvasWrapper: css({\n label: 'sandwichCanvasWrapper',\n display: 'flex',\n marginBottom: `${PIXELS_PER_LEVEL / window.devicePixelRatio}px`,\n }),\n sandwichMarker: css({\n label: 'sandwichMarker',\n writingMode: 'vertical-lr',\n transform: 'rotate(180deg)',\n overflow: 'hidden',\n whiteSpace: 'nowrap',\n }),\n sandwichMarkerCalees: css({\n label: 'sandwichMarkerCalees',\n textAlign: 'right',\n }),\n sandwichMarkerIcon: css({\n label: 'sandwichMarkerIcon',\n verticalAlign: 'baseline',\n }),\n});\n\nexport default FlameGraph;\n"],"names":["levels","totalProfileTicks","totalProfileTicksRight","totalViewTicks","levelsCallers"],"mappings":"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"}
|
1
|
+
{"version":3,"file":"FlameGraph.js","sources":["../../../src/FlameGraph/FlameGraph.tsx"],"sourcesContent":["// This component is based on logic from the flamebearer project\n// https://github.com/mapbox/flamebearer\n\n// ISC License\n\n// Copyright (c) 2018, Mapbox\n\n// Permission to use, copy, modify, and/or distribute this software for any purpose\n// with or without fee is hereby granted, provided that the above copyright notice\n// and this permission notice appear in all copies.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\n// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND\n// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\n// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS\n// OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER\n// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF\n// THIS SOFTWARE.\nimport { css, cx } from '@emotion/css';\nimport { useEffect, useState } from 'react';\nimport * as React from 'react';\n\nimport { Icon } from '@grafana/ui';\n\nimport { PIXELS_PER_LEVEL } from '../constants';\nimport { ClickedItemData, ColorScheme, ColorSchemeDiff, SelectedView, TextAlign } from '../types';\n\nimport FlameGraphCanvas from './FlameGraphCanvas';\nimport { GetExtraContextMenuButtonsFunction } from './FlameGraphContextMenu';\nimport FlameGraphMetadata from './FlameGraphMetadata';\nimport { CollapsedMap, FlameGraphDataContainer, LevelItem } from './dataTransform';\n\ntype Props = {\n data: FlameGraphDataContainer;\n rangeMin: number;\n rangeMax: number;\n matchedLabels?: Set<string>;\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 sandwichItem?: string;\n onSandwich: (label: string) => void;\n onFocusPillClick: () => void;\n onSandwichPillClick: () => void;\n colorScheme: ColorScheme | ColorSchemeDiff;\n showFlameGraphOnly?: boolean;\n getExtraContextMenuButtons?: GetExtraContextMenuButtonsFunction;\n collapsing?: boolean;\n selectedView: SelectedView;\n search: string;\n collapsedMap: CollapsedMap;\n setCollapsedMap: (collapsedMap: CollapsedMap) => void;\n};\n\nconst FlameGraph = ({\n data,\n rangeMin,\n rangeMax,\n matchedLabels,\n setRangeMin,\n setRangeMax,\n onItemFocused,\n focusedItemData,\n textAlign,\n onSandwich,\n sandwichItem,\n onFocusPillClick,\n onSandwichPillClick,\n colorScheme,\n showFlameGraphOnly,\n getExtraContextMenuButtons,\n collapsing,\n selectedView,\n search,\n collapsedMap,\n setCollapsedMap,\n}: Props) => {\n const styles = getStyles();\n\n const [levels, setLevels] = useState<LevelItem[][]>();\n const [levelsCallers, setLevelsCallers] = useState<LevelItem[][]>();\n const [totalProfileTicks, setTotalProfileTicks] = useState<number>(0);\n const [totalProfileTicksRight, setTotalProfileTicksRight] = useState<number>();\n const [totalViewTicks, setTotalViewTicks] = useState<number>(0);\n\n useEffect(() => {\n if (data) {\n let levels = data.getLevels();\n let totalProfileTicks = levels.length ? levels[0][0].value : 0;\n let totalProfileTicksRight = levels.length ? levels[0][0].valueRight : undefined;\n let totalViewTicks = totalProfileTicks;\n let levelsCallers = undefined;\n\n if (sandwichItem) {\n const [callers, callees] = data.getSandwichLevels(sandwichItem);\n levels = callees;\n levelsCallers = callers;\n // We need this separate as in case of diff profile we want to compute diff colors based on the original ticks.\n totalViewTicks = callees[0]?.[0]?.value ?? 0;\n }\n setLevels(levels);\n setLevelsCallers(levelsCallers);\n setTotalProfileTicks(totalProfileTicks);\n setTotalProfileTicksRight(totalProfileTicksRight);\n setTotalViewTicks(totalViewTicks);\n }\n }, [data, sandwichItem]);\n\n if (!levels) {\n return null;\n }\n\n const commonCanvasProps = {\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 showFlameGraphOnly,\n collapsedMap,\n setCollapsedMap,\n getExtraContextMenuButtons,\n collapsing,\n search,\n selectedView,\n };\n let canvas = null;\n\n if (levelsCallers?.length) {\n canvas = (\n <>\n <div className={styles.sandwichCanvasWrapper}>\n <div className={styles.sandwichMarker}>\n Callers\n <Icon className={styles.sandwichMarkerIcon} name={'arrow-down'} />\n </div>\n <FlameGraphCanvas\n {...commonCanvasProps}\n root={levelsCallers[levelsCallers.length - 1][0]}\n depth={levelsCallers.length}\n direction={'parents'}\n // We do not support collapsing in sandwich view for now.\n collapsing={false}\n />\n </div>\n\n <div className={styles.sandwichCanvasWrapper}>\n <div className={cx(styles.sandwichMarker, styles.sandwichMarkerCalees)}>\n <Icon className={styles.sandwichMarkerIcon} name={'arrow-up'} />\n Callees\n </div>\n <FlameGraphCanvas\n {...commonCanvasProps}\n root={levels[0][0]}\n depth={levels.length}\n direction={'children'}\n collapsing={false}\n />\n </div>\n </>\n );\n } else if (levels?.length) {\n canvas = (\n <FlameGraphCanvas {...commonCanvasProps} root={levels[0][0]} depth={levels.length} direction={'children'} />\n );\n }\n\n return (\n <div className={styles.graph}>\n <FlameGraphMetadata\n data={data}\n focusedItem={focusedItemData}\n sandwichedLabel={sandwichItem}\n totalTicks={totalViewTicks}\n onFocusPillClick={onFocusPillClick}\n onSandwichPillClick={onSandwichPillClick}\n />\n {canvas}\n </div>\n );\n};\n\nconst getStyles = () => ({\n graph: css({\n label: 'graph',\n overflow: 'auto',\n flexGrow: 1,\n flexBasis: '50%',\n }),\n sandwichCanvasWrapper: css({\n label: 'sandwichCanvasWrapper',\n display: 'flex',\n marginBottom: `${PIXELS_PER_LEVEL / window.devicePixelRatio}px`,\n }),\n sandwichMarker: css({\n label: 'sandwichMarker',\n writingMode: 'vertical-lr',\n transform: 'rotate(180deg)',\n overflow: 'hidden',\n whiteSpace: 'nowrap',\n }),\n sandwichMarkerCalees: css({\n label: 'sandwichMarkerCalees',\n textAlign: 'right',\n }),\n sandwichMarkerIcon: css({\n label: 'sandwichMarkerIcon',\n verticalAlign: 'baseline',\n }),\n});\n\nexport default FlameGraph;\n"],"names":["levels","totalProfileTicks","totalProfileTicksRight","totalViewTicks","levelsCallers"],"mappings":"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"}
|
@@ -59,7 +59,7 @@ const FlameGraphCanvas = ({
|
|
59
59
|
});
|
60
60
|
const onGraphClick = useCallback(
|
61
61
|
(e) => {
|
62
|
-
setTooltipItem(
|
62
|
+
setTooltipItem(undefined);
|
63
63
|
const pixelsPerTick = graphRef.current.clientWidth / totalViewTicks / (rangeMax - rangeMin);
|
64
64
|
const item = convertPixelCoordinatesToBarCoordinates(
|
65
65
|
{ x: e.nativeEvent.offsetX, y: e.nativeEvent.offsetY },
|
@@ -79,7 +79,7 @@ const FlameGraphCanvas = ({
|
|
79
79
|
label: data.getLabel(item.itemIndexes[0])
|
80
80
|
});
|
81
81
|
} else {
|
82
|
-
setClickedItemData(
|
82
|
+
setClickedItemData(undefined);
|
83
83
|
}
|
84
84
|
},
|
85
85
|
[data, rangeMin, rangeMax, totalViewTicks, root, direction, depth, collapsedMap]
|
@@ -87,9 +87,9 @@ const FlameGraphCanvas = ({
|
|
87
87
|
const [mousePosition, setMousePosition] = useState();
|
88
88
|
const onGraphMouseMove = useCallback(
|
89
89
|
(e) => {
|
90
|
-
if (clickedItemData ===
|
91
|
-
setTooltipItem(
|
92
|
-
setMousePosition(
|
90
|
+
if (clickedItemData === undefined) {
|
91
|
+
setTooltipItem(undefined);
|
92
|
+
setMousePosition(undefined);
|
93
93
|
const pixelsPerTick = graphRef.current.clientWidth / totalViewTicks / (rangeMax - rangeMin);
|
94
94
|
const item = convertPixelCoordinatesToBarCoordinates(
|
95
95
|
{ x: e.nativeEvent.offsetX, y: e.nativeEvent.offsetY },
|
@@ -110,13 +110,13 @@ const FlameGraphCanvas = ({
|
|
110
110
|
[rangeMin, rangeMax, totalViewTicks, clickedItemData, setMousePosition, root, direction, depth, collapsedMap]
|
111
111
|
);
|
112
112
|
const onGraphMouseLeave = useCallback(() => {
|
113
|
-
setTooltipItem(
|
113
|
+
setTooltipItem(undefined);
|
114
114
|
}, []);
|
115
115
|
useEffect(() => {
|
116
116
|
const handleOnClick = (e) => {
|
117
117
|
var _a;
|
118
|
-
if (e.target instanceof HTMLElement && ((_a = e.target.parentElement) == null ?
|
119
|
-
setClickedItemData(
|
118
|
+
if (e.target instanceof HTMLElement && ((_a = e.target.parentElement) == null ? undefined : _a.id) !== "flameGraphCanvasContainer_clickOutsideCheck") {
|
119
|
+
setClickedItemData(undefined);
|
120
120
|
}
|
121
121
|
};
|
122
122
|
window.addEventListener("click", handleOnClick);
|
@@ -140,7 +140,7 @@ const FlameGraphCanvas = ({
|
|
140
140
|
item: tooltipItem,
|
141
141
|
data,
|
142
142
|
totalTicks: totalViewTicks,
|
143
|
-
collapseConfig: tooltipItem ? collapsedMap.get(tooltipItem) :
|
143
|
+
collapseConfig: tooltipItem ? collapsedMap.get(tooltipItem) : undefined
|
144
144
|
}
|
145
145
|
),
|
146
146
|
!showFlameGraphOnly && clickedItemData && /* @__PURE__ */ jsx(
|
@@ -151,7 +151,7 @@ const FlameGraphCanvas = ({
|
|
151
151
|
collapsing,
|
152
152
|
collapseConfig: collapsedMap.get(clickedItemData.item),
|
153
153
|
onMenuItemClick: () => {
|
154
|
-
setClickedItemData(
|
154
|
+
setClickedItemData(undefined);
|
155
155
|
},
|
156
156
|
onItemFocus: () => {
|
157
157
|
setRangeMin(clickedItemData.item.start / totalViewTicks);
|
@@ -215,10 +215,10 @@ const convertPixelCoordinatesToBarCoordinates = (pos, root, direction, depth, pi
|
|
215
215
|
let next = root;
|
216
216
|
let currentLevel = direction === "children" ? 0 : depth - 1;
|
217
217
|
const levelIndex = Math.floor(pos.y / (PIXELS_PER_LEVEL / window.devicePixelRatio));
|
218
|
-
let found =
|
218
|
+
let found = undefined;
|
219
219
|
while (next) {
|
220
220
|
const node = next;
|
221
|
-
next =
|
221
|
+
next = undefined;
|
222
222
|
if (currentLevel === levelIndex) {
|
223
223
|
found = node;
|
224
224
|
break;
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"FlameGraphCanvas.js","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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"}
|
1
|
+
{"version":3,"file":"FlameGraphCanvas.js","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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"}
|
@@ -20,7 +20,7 @@ const FlameGraphContextMenu = ({
|
|
20
20
|
search
|
21
21
|
}) => {
|
22
22
|
function renderItems() {
|
23
|
-
const extraButtons = (getExtraContextMenuButtons == null ?
|
23
|
+
const extraButtons = (getExtraContextMenuButtons == null ? undefined : getExtraContextMenuButtons(itemData, data.data, {
|
24
24
|
selectedView,
|
25
25
|
isDiff: data.isDiffFlamegraph(),
|
26
26
|
search,
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"FlameGraphContextMenu.js","sources":["../../../src/FlameGraph/FlameGraphContextMenu.tsx"],"sourcesContent":["import { DataFrame } from '@grafana/data';\nimport { MenuItem, MenuGroup, ContextMenu, IconName } from '@grafana/ui';\n\nimport { ClickedItemData, SelectedView } from '../types';\n\nimport { CollapseConfig, FlameGraphDataContainer } from './dataTransform';\n\nexport type GetExtraContextMenuButtonsFunction = (\n clickedItemData: ClickedItemData,\n data: DataFrame,\n state: { selectedView: SelectedView; isDiff: boolean; search: string; collapseConfig?: CollapseConfig }\n) => ExtraContextMenuButton[];\n\nexport type ExtraContextMenuButton = {\n label: string;\n icon: IconName;\n onClick: () => void;\n};\n\ntype Props = {\n data: FlameGraphDataContainer;\n itemData: ClickedItemData;\n onMenuItemClick: () => void;\n onItemFocus: () => void;\n onSandwich: () => void;\n onExpandGroup: () => void;\n onCollapseGroup: () => void;\n onExpandAllGroups: () => void;\n onCollapseAllGroups: () => void;\n getExtraContextMenuButtons?: GetExtraContextMenuButtonsFunction;\n collapseConfig?: CollapseConfig;\n collapsing?: boolean;\n allGroupsCollapsed?: boolean;\n allGroupsExpanded?: boolean;\n selectedView: SelectedView;\n search: string;\n};\n\nconst FlameGraphContextMenu = ({\n data,\n itemData,\n onMenuItemClick,\n onItemFocus,\n onSandwich,\n collapseConfig,\n onExpandGroup,\n onCollapseGroup,\n onExpandAllGroups,\n onCollapseAllGroups,\n getExtraContextMenuButtons,\n collapsing,\n allGroupsExpanded,\n allGroupsCollapsed,\n selectedView,\n search,\n}: Props) => {\n function renderItems() {\n const extraButtons =\n getExtraContextMenuButtons?.(itemData, data.data, {\n selectedView,\n isDiff: data.isDiffFlamegraph(),\n search,\n collapseConfig,\n }) || [];\n return (\n <>\n <MenuItem\n label=\"Focus block\"\n icon={'eye'}\n onClick={() => {\n onItemFocus();\n onMenuItemClick();\n }}\n />\n <MenuItem\n label=\"Copy function name\"\n icon={'copy'}\n onClick={() => {\n navigator.clipboard.writeText(itemData.label).then(() => {\n onMenuItemClick();\n });\n }}\n />\n <MenuItem\n label=\"Sandwich view\"\n icon={'gf-show-context'}\n onClick={() => {\n onSandwich();\n onMenuItemClick();\n }}\n />\n {extraButtons.map(({ label, icon, onClick }) => {\n return <MenuItem label={label} icon={icon} onClick={() => onClick()} key={label} />;\n })}\n {collapsing && (\n <MenuGroup label={'Grouping'}>\n {collapseConfig ? (\n collapseConfig.collapsed ? (\n <MenuItem\n label=\"Expand group\"\n icon={'angle-double-down'}\n onClick={() => {\n onExpandGroup();\n onMenuItemClick();\n }}\n />\n ) : (\n <MenuItem\n label=\"Collapse group\"\n icon={'angle-double-up'}\n onClick={() => {\n onCollapseGroup();\n onMenuItemClick();\n }}\n />\n )\n ) : null}\n {!allGroupsExpanded && (\n <MenuItem\n label=\"Expand all groups\"\n icon={'angle-double-down'}\n onClick={() => {\n onExpandAllGroups();\n onMenuItemClick();\n }}\n />\n )}\n {!allGroupsCollapsed && (\n <MenuItem\n label=\"Collapse all groups\"\n icon={'angle-double-up'}\n onClick={() => {\n onCollapseAllGroups();\n onMenuItemClick();\n }}\n />\n )}\n </MenuGroup>\n )}\n </>\n );\n }\n\n return (\n <div data-testid=\"contextMenu\">\n <ContextMenu\n renderMenuItems={renderItems}\n x={itemData.posX + 10}\n y={itemData.posY}\n focusOnOpen={false}\n ></ContextMenu>\n </div>\n );\n};\n\nexport default FlameGraphContextMenu;\n"],"names":[],"mappings":";;;AAsCA,MAAM,wBAAwB,CAAC;AAAA,EAC7B,IAAA;AAAA,EACA,QAAA;AAAA,EACA,eAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,eAAA;AAAA,EACA,iBAAA;AAAA,EACA,mBAAA;AAAA,EACA,0BAAA;AAAA,EACA,UAAA;AAAA,EACA,iBAAA;AAAA,EACA,kBAAA;AAAA,EACA,YAAA;AAAA,EACA;AACF,CAAa,KAAA;AACX,EAAA,SAAS,WAAc,GAAA;AACrB,IAAA,MAAM,YACJ,GAAA,CAAA,0BAAA,IAAA,IAAA,GAAA,
|
1
|
+
{"version":3,"file":"FlameGraphContextMenu.js","sources":["../../../src/FlameGraph/FlameGraphContextMenu.tsx"],"sourcesContent":["import { DataFrame } from '@grafana/data';\nimport { MenuItem, MenuGroup, ContextMenu, IconName } from '@grafana/ui';\n\nimport { ClickedItemData, SelectedView } from '../types';\n\nimport { CollapseConfig, FlameGraphDataContainer } from './dataTransform';\n\nexport type GetExtraContextMenuButtonsFunction = (\n clickedItemData: ClickedItemData,\n data: DataFrame,\n state: { selectedView: SelectedView; isDiff: boolean; search: string; collapseConfig?: CollapseConfig }\n) => ExtraContextMenuButton[];\n\nexport type ExtraContextMenuButton = {\n label: string;\n icon: IconName;\n onClick: () => void;\n};\n\ntype Props = {\n data: FlameGraphDataContainer;\n itemData: ClickedItemData;\n onMenuItemClick: () => void;\n onItemFocus: () => void;\n onSandwich: () => void;\n onExpandGroup: () => void;\n onCollapseGroup: () => void;\n onExpandAllGroups: () => void;\n onCollapseAllGroups: () => void;\n getExtraContextMenuButtons?: GetExtraContextMenuButtonsFunction;\n collapseConfig?: CollapseConfig;\n collapsing?: boolean;\n allGroupsCollapsed?: boolean;\n allGroupsExpanded?: boolean;\n selectedView: SelectedView;\n search: string;\n};\n\nconst FlameGraphContextMenu = ({\n data,\n itemData,\n onMenuItemClick,\n onItemFocus,\n onSandwich,\n collapseConfig,\n onExpandGroup,\n onCollapseGroup,\n onExpandAllGroups,\n onCollapseAllGroups,\n getExtraContextMenuButtons,\n collapsing,\n allGroupsExpanded,\n allGroupsCollapsed,\n selectedView,\n search,\n}: Props) => {\n function renderItems() {\n const extraButtons =\n getExtraContextMenuButtons?.(itemData, data.data, {\n selectedView,\n isDiff: data.isDiffFlamegraph(),\n search,\n collapseConfig,\n }) || [];\n return (\n <>\n <MenuItem\n label=\"Focus block\"\n icon={'eye'}\n onClick={() => {\n onItemFocus();\n onMenuItemClick();\n }}\n />\n <MenuItem\n label=\"Copy function name\"\n icon={'copy'}\n onClick={() => {\n navigator.clipboard.writeText(itemData.label).then(() => {\n onMenuItemClick();\n });\n }}\n />\n <MenuItem\n label=\"Sandwich view\"\n icon={'gf-show-context'}\n onClick={() => {\n onSandwich();\n onMenuItemClick();\n }}\n />\n {extraButtons.map(({ label, icon, onClick }) => {\n return <MenuItem label={label} icon={icon} onClick={() => onClick()} key={label} />;\n })}\n {collapsing && (\n <MenuGroup label={'Grouping'}>\n {collapseConfig ? (\n collapseConfig.collapsed ? (\n <MenuItem\n label=\"Expand group\"\n icon={'angle-double-down'}\n onClick={() => {\n onExpandGroup();\n onMenuItemClick();\n }}\n />\n ) : (\n <MenuItem\n label=\"Collapse group\"\n icon={'angle-double-up'}\n onClick={() => {\n onCollapseGroup();\n onMenuItemClick();\n }}\n />\n )\n ) : null}\n {!allGroupsExpanded && (\n <MenuItem\n label=\"Expand all groups\"\n icon={'angle-double-down'}\n onClick={() => {\n onExpandAllGroups();\n onMenuItemClick();\n }}\n />\n )}\n {!allGroupsCollapsed && (\n <MenuItem\n label=\"Collapse all groups\"\n icon={'angle-double-up'}\n onClick={() => {\n onCollapseAllGroups();\n onMenuItemClick();\n }}\n />\n )}\n </MenuGroup>\n )}\n </>\n );\n }\n\n return (\n <div data-testid=\"contextMenu\">\n <ContextMenu\n renderMenuItems={renderItems}\n x={itemData.posX + 10}\n y={itemData.posY}\n focusOnOpen={false}\n ></ContextMenu>\n </div>\n );\n};\n\nexport default FlameGraphContextMenu;\n"],"names":[],"mappings":"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"}
|
@@ -2,7 +2,7 @@ import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { css } from '@emotion/css';
|
3
3
|
import { memo } from 'react';
|
4
4
|
import { getValueFormat } from '@grafana/data';
|
5
|
-
import { useStyles2, Icon, IconButton } from '@grafana/ui';
|
5
|
+
import { useStyles2, Tooltip, Icon, IconButton } from '@grafana/ui';
|
6
6
|
|
7
7
|
const FlameGraphMetadata = memo(
|
8
8
|
({ data, focusedItem, totalTicks, sandwichedLabel, onFocusPillClick, onSandwichPillClick }) => {
|
@@ -30,7 +30,7 @@ const FlameGraphMetadata = memo(
|
|
30
30
|
);
|
31
31
|
if (sandwichedLabel) {
|
32
32
|
parts.push(
|
33
|
-
/* @__PURE__ */ jsxs("
|
33
|
+
/* @__PURE__ */ jsx(Tooltip, { content: sandwichedLabel, placement: "top", children: /* @__PURE__ */ jsxs("div", { children: [
|
34
34
|
/* @__PURE__ */ jsx(Icon, { size: "sm", name: "angle-right" }),
|
35
35
|
/* @__PURE__ */ jsxs("div", { className: styles.metadataPill, children: [
|
36
36
|
/* @__PURE__ */ jsx(Icon, { size: "sm", name: "gf-show-context" }),
|
@@ -48,17 +48,18 @@ const FlameGraphMetadata = memo(
|
|
48
48
|
}
|
49
49
|
)
|
50
50
|
] })
|
51
|
-
] }, "sandwich")
|
51
|
+
] }) }, "sandwich")
|
52
52
|
);
|
53
53
|
}
|
54
54
|
if (focusedItem) {
|
55
|
-
const percentValue = Math.round(1e4 * (focusedItem.item.value / totalTicks)) / 100;
|
55
|
+
const percentValue = totalTicks > 0 ? Math.round(1e4 * (focusedItem.item.value / totalTicks)) / 100 : 0;
|
56
|
+
const iconName = percentValue > 0 ? "eye" : "exclamation-circle";
|
56
57
|
parts.push(
|
57
|
-
/* @__PURE__ */ jsxs("
|
58
|
+
/* @__PURE__ */ jsx(Tooltip, { content: focusedItem.label, placement: "top", children: /* @__PURE__ */ jsxs("div", { children: [
|
58
59
|
/* @__PURE__ */ jsx(Icon, { size: "sm", name: "angle-right" }),
|
59
60
|
/* @__PURE__ */ jsxs("div", { className: styles.metadataPill, children: [
|
60
|
-
/* @__PURE__ */ jsx(Icon, { size: "sm", name:
|
61
|
-
"
|
61
|
+
/* @__PURE__ */ jsx(Icon, { size: "sm", name: iconName }),
|
62
|
+
"\xA0",
|
62
63
|
percentValue,
|
63
64
|
"% of total",
|
64
65
|
/* @__PURE__ */ jsx(
|
@@ -73,7 +74,7 @@ const FlameGraphMetadata = memo(
|
|
73
74
|
}
|
74
75
|
)
|
75
76
|
] })
|
76
|
-
] }, "focus")
|
77
|
+
] }) }, "focus")
|
77
78
|
);
|
78
79
|
}
|
79
80
|
return /* @__PURE__ */ jsx("div", { className: styles.metadata, children: parts });
|
@@ -99,8 +100,10 @@ const getStyles = (theme) => ({
|
|
99
100
|
margin: theme.spacing(0, 0.5)
|
100
101
|
}),
|
101
102
|
metadata: css({
|
102
|
-
|
103
|
-
|
103
|
+
display: "flex",
|
104
|
+
alignItems: "center",
|
105
|
+
justifyContent: "center",
|
106
|
+
margin: "8px 0"
|
104
107
|
}),
|
105
108
|
metadataPillName: css({
|
106
109
|
label: "metadataPillName",
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"FlameGraphMetadata.js","sources":["../../../src/FlameGraph/FlameGraphMetadata.tsx"],"sourcesContent":["import { css } from '@emotion/css';\nimport { memo, ReactNode } from 'react';\n\nimport { getValueFormat, GrafanaTheme2 } from '@grafana/data';\nimport { Icon, IconButton, useStyles2 } from '@grafana/ui';\n\nimport { ClickedItemData } from '../types';\n\nimport { FlameGraphDataContainer } from './dataTransform';\n\ntype Props = {\n data: FlameGraphDataContainer;\n totalTicks: number;\n onFocusPillClick: () => void;\n onSandwichPillClick: () => void;\n focusedItem?: ClickedItemData;\n sandwichedLabel?: string;\n};\n\nconst FlameGraphMetadata = memo(\n ({ data, focusedItem, totalTicks, sandwichedLabel, onFocusPillClick, onSandwichPillClick }: Props) => {\n const styles = useStyles2(getStyles);\n const parts: ReactNode[] = [];\n const ticksVal = getValueFormat('short')(totalTicks);\n\n const displayValue = data.valueDisplayProcessor(totalTicks);\n let unitValue = displayValue.text + displayValue.suffix;\n const unitTitle = data.getUnitTitle();\n if (unitTitle === 'Count') {\n if (!displayValue.suffix) {\n // Makes sure we don't show 123undefined or something like that if suffix isn't defined\n unitValue = displayValue.text;\n }\n }\n\n parts.push(\n <div className={styles.metadataPill} key={'default'}>\n {unitValue} | {ticksVal.text}\n {ticksVal.suffix} samples ({unitTitle})\n </div>\n );\n\n if (sandwichedLabel) {\n parts.push(\n <
|
1
|
+
{"version":3,"file":"FlameGraphMetadata.js","sources":["../../../src/FlameGraph/FlameGraphMetadata.tsx"],"sourcesContent":["import { css } from '@emotion/css';\nimport { memo, ReactNode } from 'react';\n\nimport { getValueFormat, GrafanaTheme2 } from '@grafana/data';\nimport { Icon, IconButton, Tooltip, useStyles2 } from '@grafana/ui';\n\nimport { ClickedItemData } from '../types';\n\nimport { FlameGraphDataContainer } from './dataTransform';\n\ntype Props = {\n data: FlameGraphDataContainer;\n totalTicks: number;\n onFocusPillClick: () => void;\n onSandwichPillClick: () => void;\n focusedItem?: ClickedItemData;\n sandwichedLabel?: string;\n};\n\nconst FlameGraphMetadata = memo(\n ({ data, focusedItem, totalTicks, sandwichedLabel, onFocusPillClick, onSandwichPillClick }: Props) => {\n const styles = useStyles2(getStyles);\n const parts: ReactNode[] = [];\n const ticksVal = getValueFormat('short')(totalTicks);\n\n const displayValue = data.valueDisplayProcessor(totalTicks);\n let unitValue = displayValue.text + displayValue.suffix;\n const unitTitle = data.getUnitTitle();\n if (unitTitle === 'Count') {\n if (!displayValue.suffix) {\n // Makes sure we don't show 123undefined or something like that if suffix isn't defined\n unitValue = displayValue.text;\n }\n }\n\n parts.push(\n <div className={styles.metadataPill} key={'default'}>\n {unitValue} | {ticksVal.text}\n {ticksVal.suffix} samples ({unitTitle})\n </div>\n );\n\n if (sandwichedLabel) {\n parts.push(\n <Tooltip key={'sandwich'} content={sandwichedLabel} placement=\"top\">\n <div>\n <Icon size={'sm'} name={'angle-right'} />\n <div className={styles.metadataPill}>\n <Icon size={'sm'} name={'gf-show-context'} />{' '}\n <span className={styles.metadataPillName}>\n {sandwichedLabel.substring(sandwichedLabel.lastIndexOf('/') + 1)}\n </span>\n <IconButton\n className={styles.pillCloseButton}\n name={'times'}\n size={'sm'}\n onClick={onSandwichPillClick}\n tooltip={'Remove sandwich view'}\n aria-label={'Remove sandwich view'}\n />\n </div>\n </div>\n </Tooltip>\n );\n }\n\n if (focusedItem) {\n const percentValue = totalTicks > 0 ? Math.round(10000 * (focusedItem.item.value / totalTicks)) / 100 : 0;\n const iconName = percentValue > 0 ? 'eye' : 'exclamation-circle';\n\n parts.push(\n <Tooltip key={'focus'} content={focusedItem.label} placement=\"top\">\n <div>\n <Icon size={'sm'} name={'angle-right'} />\n <div className={styles.metadataPill}>\n <Icon size={'sm'} name={iconName} />\n {percentValue}% of total\n <IconButton\n className={styles.pillCloseButton}\n name={'times'}\n size={'sm'}\n onClick={onFocusPillClick}\n tooltip={'Remove focus'}\n aria-label={'Remove focus'}\n />\n </div>\n </div>\n </Tooltip>\n );\n }\n\n return <div className={styles.metadata}>{parts}</div>;\n }\n);\n\nFlameGraphMetadata.displayName = 'FlameGraphMetadata';\n\nconst getStyles = (theme: GrafanaTheme2) => ({\n metadataPill: css({\n label: 'metadataPill',\n display: 'inline-flex',\n alignItems: 'center',\n background: theme.colors.background.secondary,\n borderRadius: theme.shape.borderRadius(8),\n padding: theme.spacing(0.5, 1),\n fontSize: theme.typography.bodySmall.fontSize,\n fontWeight: theme.typography.fontWeightMedium,\n lineHeight: theme.typography.bodySmall.lineHeight,\n color: theme.colors.text.secondary,\n }),\n pillCloseButton: css({\n label: 'pillCloseButton',\n verticalAlign: 'text-bottom',\n margin: theme.spacing(0, 0.5),\n }),\n metadata: css({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n margin: '8px 0',\n }),\n metadataPillName: css({\n label: 'metadataPillName',\n maxWidth: '200px',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n marginLeft: theme.spacing(0.5),\n }),\n});\n\nexport default FlameGraphMetadata;\n"],"names":[],"mappings":"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"}
|
@@ -90,10 +90,10 @@ function getPackageName(name) {
|
|
90
90
|
for (const [_, matcher] of matchers) {
|
91
91
|
const match = name.match(matcher);
|
92
92
|
if (match) {
|
93
|
-
return ((_a = match.groups) == null ?
|
93
|
+
return ((_a = match.groups) == null ? undefined : _a.packageName) || "";
|
94
94
|
}
|
95
95
|
}
|
96
|
-
return
|
96
|
+
return undefined;
|
97
97
|
}
|
98
98
|
|
99
99
|
export { byPackageGradient, byValueGradient, diffColorBlindColors, diffColorBlindGradient, diffDefaultColors, diffDefaultGradient, getBarColorByDiff, getBarColorByPackage, getBarColorByValue };
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"colors.js","sources":["../../../src/FlameGraph/colors.ts"],"sourcesContent":["import { scaleLinear } from 'd3';\nimport color from 'tinycolor2';\n\nimport { GrafanaTheme2 } from '@grafana/data';\n\nimport { ColorSchemeDiff } from '../types';\n\nimport murmurhash3_32_gc from './murmur3';\n\n// Colors taken from pyroscope, they should be from Grafana originally, but I didn't find from where exactly.\nconst packageColors = [\n color({ h: 24, s: 69, l: 60 }),\n color({ h: 34, s: 65, l: 65 }),\n color({ h: 194, s: 52, l: 61 }),\n color({ h: 163, s: 45, l: 55 }),\n color({ h: 211, s: 48, l: 60 }),\n color({ h: 246, s: 40, l: 65 }),\n color({ h: 305, s: 63, l: 79 }),\n color({ h: 47, s: 100, l: 73 }),\n\n color({ r: 183, g: 219, b: 171 }),\n color({ r: 244, g: 213, b: 152 }),\n color({ r: 78, g: 146, b: 249 }),\n color({ r: 249, g: 186, b: 143 }),\n color({ r: 242, g: 145, b: 145 }),\n color({ r: 130, g: 181, b: 216 }),\n color({ r: 229, g: 168, b: 226 }),\n color({ r: 174, g: 162, b: 224 }),\n color({ r: 154, g: 196, b: 138 }),\n color({ r: 242, g: 201, b: 109 }),\n color({ r: 101, g: 197, b: 219 }),\n color({ r: 249, g: 147, b: 78 }),\n color({ r: 234, g: 100, b: 96 }),\n color({ r: 81, g: 149, b: 206 }),\n color({ r: 214, g: 131, b: 206 }),\n color({ r: 128, g: 110, b: 183 }),\n];\n\nconst byValueMinColor = getBarColorByValue(1, 100, 0, 1);\nconst byValueMaxColor = getBarColorByValue(100, 100, 0, 1);\nexport const byValueGradient = `linear-gradient(90deg, ${byValueMinColor} 0%, ${byValueMaxColor} 100%)`;\n\n// Handpicked some vaguely rainbow-ish colors\nexport const byPackageGradient = `linear-gradient(90deg, ${packageColors[0]} 0%, ${packageColors[2]} 30%, ${packageColors[6]} 50%, ${packageColors[7]} 70%, ${packageColors[8]} 100%)`;\n\nexport function getBarColorByValue(value: number, totalTicks: number, rangeMin: number, rangeMax: number) {\n // / (rangeMax - rangeMin) here so when you click a bar it will adjust the top (clicked)bar to the most 'intense' color\n const intensity = Math.min(1, value / totalTicks / (rangeMax - rangeMin));\n const h = 50 - 50 * intensity;\n const l = 65 + 7 * intensity;\n\n return color({ h, s: 100, l });\n}\n\nexport function getBarColorByPackage(label: string, theme: GrafanaTheme2) {\n const packageName = getPackageName(label);\n // TODO: similar thing happens in trace view with selecting colors of the spans, so maybe this could be unified.\n const hash = murmurhash3_32_gc(packageName || '', 0);\n const colorIndex = hash % packageColors.length;\n let packageColor = packageColors[colorIndex].clone();\n if (theme.isLight) {\n packageColor = packageColor.brighten(15);\n }\n return packageColor;\n}\n\n// green to red\nexport const diffDefaultColors = ['rgb(0, 170, 0)', 'rgb(148, 142, 142)', 'rgb(200, 0, 0)'];\nexport const diffDefaultGradient = `linear-gradient(90deg, ${diffDefaultColors[0]} 0%, ${diffDefaultColors[1]} 50%, ${diffDefaultColors[2]} 100%)`;\nexport const diffColorBlindColors = ['rgb(26, 133, 255)', 'rgb(148, 142, 142)', 'rgb(220, 50, 32)'];\nexport const diffColorBlindGradient = `linear-gradient(90deg, ${diffColorBlindColors[0]} 0%, ${diffColorBlindColors[1]} 50%, ${diffColorBlindColors[2]} 100%)`;\n\nexport function getBarColorByDiff(\n ticks: number,\n ticksRight: number,\n totalTicks: number,\n totalTicksRight: number,\n colorScheme: ColorSchemeDiff\n) {\n const range = colorScheme === ColorSchemeDiff.Default ? diffDefaultColors : diffColorBlindColors;\n const colorScale = scaleLinear()\n .domain([-100, 0, 100])\n // TODO types from DefinitelyTyped seem to mismatch\n // @ts-ignore\n .range(range);\n\n const ticksLeft = ticks - ticksRight;\n const totalTicksLeft = totalTicks - totalTicksRight;\n\n if (totalTicksRight === 0 || totalTicksLeft === 0) {\n // TODO types from DefinitelyTyped seem to mismatch\n // @ts-ignore\n const rgbString: string = colorScale(0);\n // Fallback to neutral color as we probably have no data for one of the sides.\n return color(rgbString);\n }\n\n const percentageLeft = Math.round((10000 * ticksLeft) / totalTicksLeft) / 100;\n const percentageRight = Math.round((10000 * ticksRight) / totalTicksRight) / 100;\n\n const diff = ((percentageRight - percentageLeft) / percentageLeft) * 100;\n\n // TODO types from DefinitelyTyped seem to mismatch\n // @ts-ignore\n const rgbString: string = colorScale(diff);\n return color(rgbString);\n}\n\n// const getColors = memoizeOne((theme) => getFilteredColors(colors, theme));\n\n// Different regexes to get the package name and function name from the label. We may at some point get an info about\n// the language from the backend and use the right regex but right now we just try all of them from most to least\n// specific.\nconst matchers = [\n ['phpspy', /^(?<packageName>([^\\/]*\\/)*)(?<filename>.*\\.php+)(?<line_info>.*)$/],\n ['pyspy', /^(?<packageName>([^\\/]*\\/)*)(?<filename>.*\\.py+)(?<line_info>.*)$/],\n ['rbspy', /^(?<packageName>([^\\/]*\\/)*)(?<filename>.*\\.rb+)(?<line_info>.*)$/],\n [\n 'nodespy',\n /^(\\.\\/node_modules\\/)?(?<packageName>[^/]*)(?<filename>.*\\.?(jsx?|tsx?)?):(?<functionName>.*):(?<line_info>.*)$/,\n ],\n ['gospy', /^(?<packageName>.*?\\/.*?\\.|.*?\\.|.+)(?<functionName>.*)$/], // also 'scrape'\n ['javaspy', /^(?<packageName>.+\\/)(?<filename>.+\\.)(?<functionName>.+)$/],\n ['dotnetspy', /^(?<packageName>.+)\\.(.+)\\.(.+)\\(.*\\)$/],\n ['tracing', /^(?<packageName>.+?):.*$/],\n ['pyroscope-rs', /^(?<packageName>[^::]+)/],\n ['ebpfspy', /^(?<packageName>.+)$/],\n ['unknown', /^(?<packageName>.+)$/],\n];\n\n// Get the package name from the symbol. Try matchers from the list and return first one that matches.\nfunction getPackageName(name: string): string | undefined {\n for (const [_, matcher] of matchers) {\n const match = name.match(matcher);\n if (match) {\n return match.groups?.packageName || '';\n }\n }\n return undefined;\n}\n"],"names":["rgbString"],"mappings":"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"}
|
1
|
+
{"version":3,"file":"colors.js","sources":["../../../src/FlameGraph/colors.ts"],"sourcesContent":["import { scaleLinear } from 'd3';\nimport color from 'tinycolor2';\n\nimport { GrafanaTheme2 } from '@grafana/data';\n\nimport { ColorSchemeDiff } from '../types';\n\nimport murmurhash3_32_gc from './murmur3';\n\n// Colors taken from pyroscope, they should be from Grafana originally, but I didn't find from where exactly.\nconst packageColors = [\n color({ h: 24, s: 69, l: 60 }),\n color({ h: 34, s: 65, l: 65 }),\n color({ h: 194, s: 52, l: 61 }),\n color({ h: 163, s: 45, l: 55 }),\n color({ h: 211, s: 48, l: 60 }),\n color({ h: 246, s: 40, l: 65 }),\n color({ h: 305, s: 63, l: 79 }),\n color({ h: 47, s: 100, l: 73 }),\n\n color({ r: 183, g: 219, b: 171 }),\n color({ r: 244, g: 213, b: 152 }),\n color({ r: 78, g: 146, b: 249 }),\n color({ r: 249, g: 186, b: 143 }),\n color({ r: 242, g: 145, b: 145 }),\n color({ r: 130, g: 181, b: 216 }),\n color({ r: 229, g: 168, b: 226 }),\n color({ r: 174, g: 162, b: 224 }),\n color({ r: 154, g: 196, b: 138 }),\n color({ r: 242, g: 201, b: 109 }),\n color({ r: 101, g: 197, b: 219 }),\n color({ r: 249, g: 147, b: 78 }),\n color({ r: 234, g: 100, b: 96 }),\n color({ r: 81, g: 149, b: 206 }),\n color({ r: 214, g: 131, b: 206 }),\n color({ r: 128, g: 110, b: 183 }),\n];\n\nconst byValueMinColor = getBarColorByValue(1, 100, 0, 1);\nconst byValueMaxColor = getBarColorByValue(100, 100, 0, 1);\nexport const byValueGradient = `linear-gradient(90deg, ${byValueMinColor} 0%, ${byValueMaxColor} 100%)`;\n\n// Handpicked some vaguely rainbow-ish colors\nexport const byPackageGradient = `linear-gradient(90deg, ${packageColors[0]} 0%, ${packageColors[2]} 30%, ${packageColors[6]} 50%, ${packageColors[7]} 70%, ${packageColors[8]} 100%)`;\n\nexport function getBarColorByValue(value: number, totalTicks: number, rangeMin: number, rangeMax: number) {\n // / (rangeMax - rangeMin) here so when you click a bar it will adjust the top (clicked)bar to the most 'intense' color\n const intensity = Math.min(1, value / totalTicks / (rangeMax - rangeMin));\n const h = 50 - 50 * intensity;\n const l = 65 + 7 * intensity;\n\n return color({ h, s: 100, l });\n}\n\nexport function getBarColorByPackage(label: string, theme: GrafanaTheme2) {\n const packageName = getPackageName(label);\n // TODO: similar thing happens in trace view with selecting colors of the spans, so maybe this could be unified.\n const hash = murmurhash3_32_gc(packageName || '', 0);\n const colorIndex = hash % packageColors.length;\n let packageColor = packageColors[colorIndex].clone();\n if (theme.isLight) {\n packageColor = packageColor.brighten(15);\n }\n return packageColor;\n}\n\n// green to red\nexport const diffDefaultColors = ['rgb(0, 170, 0)', 'rgb(148, 142, 142)', 'rgb(200, 0, 0)'];\nexport const diffDefaultGradient = `linear-gradient(90deg, ${diffDefaultColors[0]} 0%, ${diffDefaultColors[1]} 50%, ${diffDefaultColors[2]} 100%)`;\nexport const diffColorBlindColors = ['rgb(26, 133, 255)', 'rgb(148, 142, 142)', 'rgb(220, 50, 32)'];\nexport const diffColorBlindGradient = `linear-gradient(90deg, ${diffColorBlindColors[0]} 0%, ${diffColorBlindColors[1]} 50%, ${diffColorBlindColors[2]} 100%)`;\n\nexport function getBarColorByDiff(\n ticks: number,\n ticksRight: number,\n totalTicks: number,\n totalTicksRight: number,\n colorScheme: ColorSchemeDiff\n) {\n const range = colorScheme === ColorSchemeDiff.Default ? diffDefaultColors : diffColorBlindColors;\n const colorScale = scaleLinear()\n .domain([-100, 0, 100])\n // TODO types from DefinitelyTyped seem to mismatch\n // @ts-ignore\n .range(range);\n\n const ticksLeft = ticks - ticksRight;\n const totalTicksLeft = totalTicks - totalTicksRight;\n\n if (totalTicksRight === 0 || totalTicksLeft === 0) {\n // TODO types from DefinitelyTyped seem to mismatch\n // @ts-ignore\n const rgbString: string = colorScale(0);\n // Fallback to neutral color as we probably have no data for one of the sides.\n return color(rgbString);\n }\n\n const percentageLeft = Math.round((10000 * ticksLeft) / totalTicksLeft) / 100;\n const percentageRight = Math.round((10000 * ticksRight) / totalTicksRight) / 100;\n\n const diff = ((percentageRight - percentageLeft) / percentageLeft) * 100;\n\n // TODO types from DefinitelyTyped seem to mismatch\n // @ts-ignore\n const rgbString: string = colorScale(diff);\n return color(rgbString);\n}\n\n// const getColors = memoizeOne((theme) => getFilteredColors(colors, theme));\n\n// Different regexes to get the package name and function name from the label. We may at some point get an info about\n// the language from the backend and use the right regex but right now we just try all of them from most to least\n// specific.\nconst matchers = [\n ['phpspy', /^(?<packageName>([^\\/]*\\/)*)(?<filename>.*\\.php+)(?<line_info>.*)$/],\n ['pyspy', /^(?<packageName>([^\\/]*\\/)*)(?<filename>.*\\.py+)(?<line_info>.*)$/],\n ['rbspy', /^(?<packageName>([^\\/]*\\/)*)(?<filename>.*\\.rb+)(?<line_info>.*)$/],\n [\n 'nodespy',\n /^(\\.\\/node_modules\\/)?(?<packageName>[^/]*)(?<filename>.*\\.?(jsx?|tsx?)?):(?<functionName>.*):(?<line_info>.*)$/,\n ],\n ['gospy', /^(?<packageName>.*?\\/.*?\\.|.*?\\.|.+)(?<functionName>.*)$/], // also 'scrape'\n ['javaspy', /^(?<packageName>.+\\/)(?<filename>.+\\.)(?<functionName>.+)$/],\n ['dotnetspy', /^(?<packageName>.+)\\.(.+)\\.(.+)\\(.*\\)$/],\n ['tracing', /^(?<packageName>.+?):.*$/],\n ['pyroscope-rs', /^(?<packageName>[^::]+)/],\n ['ebpfspy', /^(?<packageName>.+)$/],\n ['unknown', /^(?<packageName>.+)$/],\n];\n\n// Get the package name from the symbol. Try matchers from the list and return first one that matches.\nfunction getPackageName(name: string): string | undefined {\n for (const [_, matcher] of matchers) {\n const match = name.match(matcher);\n if (match) {\n return match.groups?.packageName || '';\n }\n }\n return undefined;\n}\n"],"names":["rgbString"],"mappings":"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"}
|