mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Plugins: Introduce new Flame graph panel (#56376)
* Flamegraph * Updated flame graph width/height values * Fix top table rendering issue * Add feature toggle for flamegraph in explore * Update tests * Hide flamegraph from dash panel viz list if feature toggle not enabled * Show table if no flameGraphFrames * Add flame graph to testdata ds * Minor improvement
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
import { colors, fuzzyMatch } from '@grafana/ui';
|
||||
|
||||
import {
|
||||
BAR_BORDER_WIDTH,
|
||||
BAR_TEXT_PADDING_LEFT,
|
||||
COLLAPSE_THRESHOLD,
|
||||
HIDE_THRESHOLD,
|
||||
LABEL_THRESHOLD,
|
||||
PIXELS_PER_LEVEL,
|
||||
} from '../../constants';
|
||||
|
||||
import { ItemWithStart } from './dataTransform';
|
||||
|
||||
type RectData = {
|
||||
width: number;
|
||||
height: number;
|
||||
x: number;
|
||||
y: number;
|
||||
collapsed: boolean;
|
||||
ticks: number;
|
||||
label: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Compute the pixel coordinates for each bar in a level. We need full level of bars so that we can collapse small bars
|
||||
* into bigger rects.
|
||||
* @param level
|
||||
* @param levelIndex
|
||||
* @param totalTicks
|
||||
* @param rangeMin
|
||||
* @param pixelsPerTick
|
||||
*/
|
||||
export function getRectDimensionsForLevel(
|
||||
level: ItemWithStart[],
|
||||
levelIndex: number,
|
||||
totalTicks: number,
|
||||
rangeMin: number,
|
||||
pixelsPerTick: number
|
||||
): RectData[] {
|
||||
const coordinatesLevel = [];
|
||||
for (let barIndex = 0; barIndex < level.length; barIndex += 1) {
|
||||
const item = level[barIndex];
|
||||
const barX = getBarX(item.start, totalTicks, rangeMin, pixelsPerTick);
|
||||
let curBarTicks = item.value;
|
||||
|
||||
// merge very small blocks into big "collapsed" ones for performance
|
||||
const collapsed = curBarTicks * pixelsPerTick <= COLLAPSE_THRESHOLD;
|
||||
if (collapsed) {
|
||||
while (
|
||||
barIndex < level.length - 1 &&
|
||||
item.start + curBarTicks === level[barIndex + 1].start &&
|
||||
level[barIndex + 1].value * pixelsPerTick <= COLLAPSE_THRESHOLD
|
||||
) {
|
||||
barIndex += 1;
|
||||
curBarTicks += level[barIndex].value;
|
||||
}
|
||||
}
|
||||
|
||||
const width = curBarTicks * pixelsPerTick - (collapsed ? 0 : BAR_BORDER_WIDTH * 2);
|
||||
coordinatesLevel.push({
|
||||
width,
|
||||
height: PIXELS_PER_LEVEL,
|
||||
x: barX,
|
||||
y: levelIndex * PIXELS_PER_LEVEL,
|
||||
collapsed,
|
||||
ticks: curBarTicks,
|
||||
label: item.label,
|
||||
});
|
||||
}
|
||||
return coordinatesLevel;
|
||||
}
|
||||
|
||||
export function renderRect(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
rect: RectData,
|
||||
totalTicks: number,
|
||||
rangeMin: number,
|
||||
rangeMax: number,
|
||||
query: string,
|
||||
levelIndex: number,
|
||||
topLevelIndex: number
|
||||
) {
|
||||
if (rect.width < HIDE_THRESHOLD) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.rect(rect.x + (rect.collapsed ? 0 : BAR_BORDER_WIDTH), rect.y, rect.width, rect.height);
|
||||
|
||||
// / (rangeMax - rangeMin) here so when you click a bar it will adjust the top (clicked)bar to the most 'intense' color
|
||||
const intensity = Math.min(1, rect.ticks / totalTicks / (rangeMax - rangeMin));
|
||||
const h = 50 - 50 * intensity;
|
||||
const l = 65 + 7 * intensity;
|
||||
|
||||
const name = rect.label;
|
||||
const queryResult = query && fuzzyMatch(name.toLowerCase(), query.toLowerCase()).found;
|
||||
|
||||
if (!rect.collapsed) {
|
||||
ctx.stroke();
|
||||
|
||||
if (query) {
|
||||
ctx.fillStyle = queryResult ? getBarColor(h, l) : colors[55];
|
||||
} else {
|
||||
ctx.fillStyle = levelIndex > topLevelIndex - 1 ? getBarColor(h, l) : getBarColor(h, l + 15);
|
||||
}
|
||||
} else {
|
||||
ctx.fillStyle = queryResult ? getBarColor(h, l) : colors[55];
|
||||
}
|
||||
ctx.fill();
|
||||
|
||||
if (!rect.collapsed && rect.width >= LABEL_THRESHOLD) {
|
||||
ctx.save();
|
||||
ctx.clip(); // so text does not overflow
|
||||
ctx.fillStyle = '#222';
|
||||
ctx.fillText(`${name}`, Math.max(rect.x, 0) + BAR_TEXT_PADDING_LEFT, rect.y + PIXELS_PER_LEVEL / 2);
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the X position of the bar. totalTicks * rangeMin is to adjust for any current zoom. So if we zoom to a
|
||||
* section of the graph we align and shift the X coordinates accordingly.
|
||||
* @param offset
|
||||
* @param totalTicks
|
||||
* @param rangeMin
|
||||
* @param pixelsPerTick
|
||||
*/
|
||||
export function getBarX(offset: number, totalTicks: number, rangeMin: number, pixelsPerTick: number) {
|
||||
return (offset - totalTicks * rangeMin) * pixelsPerTick;
|
||||
}
|
||||
|
||||
function getBarColor(h: number, l: number) {
|
||||
return `hsl(${h}, 100%, ${l}%)`;
|
||||
}
|
||||
Reference in New Issue
Block a user