chore: hide anno lines & regions for multi-lane, pass options into annoPlugin

This commit is contained in:
Galen 2025-09-25 13:31:17 -05:00
parent fa59ef2b86
commit a40444fd23
No known key found for this signature in database
6 changed files with 58 additions and 54 deletions

View File

@ -323,6 +323,7 @@ export const CandlestickPanel = ({
/>
)}
<AnnotationsPlugin2
annotationsConfig={options.annotations}
annotations={data.annotations ?? []}
config={uplotConfig}
timeZone={timeZone}

View File

@ -235,6 +235,7 @@ export const HeatmapPanel = ({
/>
)}
<AnnotationsPlugin2
annotationsConfig={options.annotations}
annotations={data.annotations ?? []}
config={builder}
timeZone={timeZone}

View File

@ -152,6 +152,7 @@ export const StateTimelinePanel = ({
)}
{alignedFrame.fields[0].config.custom?.axisPlacement !== AxisPlacement.Hidden && (
<AnnotationsPlugin2
annotationsConfig={options.annotations}
annotations={data.annotations ?? []}
config={builder}
timeZone={timeZone}

View File

@ -165,6 +165,7 @@ export const StatusHistoryPanel = ({
)}
{alignedFrame.fields[0].config.custom?.axisPlacement !== AxisPlacement.Hidden && (
<AnnotationsPlugin2
annotationsConfig={options.annotations}
annotations={data.annotations ?? []}
config={builder}
timeZone={timeZone}

View File

@ -193,6 +193,7 @@ export const TimeSeriesPanel = ({
{!isVerticallyOriented && (
<>
<AnnotationsPlugin2
annotationsConfig={options.annotations}
annotations={data.annotations ?? []}
config={uplotConfig}
timeZone={timeZone}

View File

@ -6,7 +6,7 @@ import tinycolor from 'tinycolor2';
import uPlot from 'uplot';
import { arrayToDataFrame, colorManipulator, DataFrame, DataTopic } from '@grafana/data';
import { TimeZone } from '@grafana/schema';
import { TimeZone, VizAnnotations } from '@grafana/schema';
import { DEFAULT_ANNOTATION_COLOR, getPortalContainer, UPlotConfigBuilder, useStyles2, useTheme2 } from '@grafana/ui';
import { AnnotationMarker2 } from './annotations2/AnnotationMarker2';
@ -25,6 +25,7 @@ interface AnnotationsPluginProps {
newRange: TimeRange2 | null;
setNewRange: (newRage: TimeRange2 | null) => void;
canvasRegionRendering?: boolean;
annotationsConfig?: VizAnnotations;
}
// TODO: batch by color, use Path2D objects
@ -58,6 +59,7 @@ function getVals(frame: DataFrame) {
}
export const AnnotationsPlugin2 = ({
annotationsConfig,
annotations,
timeZone,
config,
@ -131,77 +133,73 @@ export const AnnotationsPlugin2 = ({
ctx.rect(u.bbox.left, u.bbox.top, u.bbox.width, u.bbox.height);
ctx.clip();
annos.forEach((frame) => {
let vals = getVals(frame);
// Multi-lane annotations do not support vertical lines or shaded regions
if (!annotationsConfig?.multiLane) {
annos.forEach((frame) => {
let vals = getVals(frame);
if (frame.name === 'xymark') {
// xMin, xMax, yMin, yMax, color, lineWidth, lineStyle, fillOpacity, text
if (frame.name === 'xymark') {
// xMin, xMax, yMin, yMax, color, lineWidth, lineStyle, fillOpacity, text
let xKey = config.scales[0].props.scaleKey;
let yKey = config.scales[1].props.scaleKey;
let xKey = config.scales[0].props.scaleKey;
let yKey = config.scales[1].props.scaleKey;
for (let i = 0; i < frame.length; i++) {
let color = getColorByName(vals.color?.[i] || DEFAULT_ANNOTATION_COLOR_HEX8);
for (let i = 0; i < frame.length; i++) {
let color = getColorByName(vals.color?.[i] || DEFAULT_ANNOTATION_COLOR_HEX8);
let x0 = u.valToPos(vals.xMin[i], xKey, true);
let x1 = u.valToPos(vals.xMax[i], xKey, true);
let y0 = u.valToPos(vals.yMax[i], yKey, true);
let y1 = u.valToPos(vals.yMin[i], yKey, true);
let x0 = u.valToPos(vals.xMin[i], xKey, true);
let x1 = u.valToPos(vals.xMax[i], xKey, true);
let y0 = u.valToPos(vals.yMax[i], yKey, true);
let y1 = u.valToPos(vals.yMin[i], yKey, true);
ctx.fillStyle = colorManipulator.alpha(color, vals.fillOpacity[i]);
ctx.fillRect(x0, y0, x1 - x0, y1 - y0);
ctx.fillStyle = colorManipulator.alpha(color, vals.fillOpacity[i]);
ctx.fillRect(x0, y0, x1 - x0, y1 - y0);
ctx.lineWidth = Math.round(vals.lineWidth[i] * uPlot.pxRatio);
ctx.lineWidth = Math.round(vals.lineWidth[i] * uPlot.pxRatio);
if (vals.lineStyle[i] === 'dash') {
// maybe extract this to vals.lineDash[i] in future?
ctx.setLineDash([5, 5]);
} else {
// solid
ctx.setLineDash([]);
if (vals.lineStyle[i] === 'dash') {
// maybe extract this to vals.lineDash[i] in future?
ctx.setLineDash([5, 5]);
} else {
// solid
ctx.setLineDash([]);
}
ctx.strokeStyle = color;
ctx.strokeRect(x0, y0, x1 - x0, y1 - y0);
}
} else {
let y0 = u.bbox.top;
let y1 = y0 + u.bbox.height;
ctx.strokeStyle = color;
ctx.strokeRect(x0, y0, x1 - x0, y1 - y0);
}
} else {
// if multiple regions, don't shade
// @todo toggle functionality, new annotation config option?
ctx.lineWidth = 2;
ctx.setLineDash([5, 5]);
let y0 = u.bbox.top;
let y1 = y0 + u.bbox.height;
for (let i = 0; i < vals.time.length; i++) {
let color = getColorByName(vals.color?.[i] || DEFAULT_ANNOTATION_COLOR_HEX8);
ctx.lineWidth = 2;
ctx.setLineDash([5, 5]);
let x0 = u.valToPos(vals.time[i], 'x', true);
renderLine(ctx, y0, y1, x0, color);
// @todo Don't render the vertical lines if multi lane is enabled
//@todo Don't render shaded region if multi-lane is enabled
// skipping this loop should do it
// If dataframe does not have end times, let's omit rendering the region for now to prevent runtime error in valToPos
// @todo do we want to fix isRegion to render a point (or use "to" as timeEnd) when we're missing timeEnd?
if (vals.isRegion?.[i] && vals.timeEnd?.[i]) {
let x1 = u.valToPos(vals.timeEnd[i], 'x', true);
renderLine(ctx, y0, y1, x1, color);
for (let i = 0; i < vals.time.length; i++) {
let color = getColorByName(vals.color?.[i] || DEFAULT_ANNOTATION_COLOR_HEX8);
let x0 = u.valToPos(vals.time[i], 'x', true);
renderLine(ctx, y0, y1, x0, color);
// If dataframe does not have end times, let's omit rendering the region for now
// @todo do we want to fix isRegion to render a point when we're missing timeEnd?
if (vals.isRegion?.[i] && vals.timeEnd?.[i]) {
let x1 = u.valToPos(vals.timeEnd[i], 'x', true);
renderLine(ctx, y0, y1, x1, color);
if (canvasRegionRendering) {
ctx.fillStyle = colorManipulator.alpha(color, 0.1);
ctx.fillRect(x0, y0, x1 - x0, u.bbox.height);
if (canvasRegionRendering) {
ctx.fillStyle = colorManipulator.alpha(color, 0.1);
ctx.fillRect(x0, y0, x1 - x0, u.bbox.height);
}
}
}
}
}
});
});
}
ctx.restore();
});
}, [config, canvasRegionRendering, getColorByName]);
}, [config, canvasRegionRendering, getColorByName, annotationsConfig]);
// ensure annos are re-drawn whenever they change
useEffect(() => {
@ -223,7 +221,8 @@ export const AnnotationsPlugin2 = ({
let markers: React.ReactNode[] = [];
const top = frameIdx * ANNOTATION_LANE_SIZE;
// Top offset for multi-lane annotations
const top = annotationsConfig?.multiLane ? frameIdx * ANNOTATION_LANE_SIZE : undefined;
for (let i = 0; i < vals.time.length; i++) {
let color = getColorByName(vals.color?.[i] || DEFAULT_ANNOTATION_COLOR);
let left = Math.round(plot.valToPos(vals.time[i], 'x')) || 0; // handles -0