diff --git a/public/app/plugins/panel/candlestick/CandlestickPanel.tsx b/public/app/plugins/panel/candlestick/CandlestickPanel.tsx
index 4ca3c131c0e..9d890b02bb3 100644
--- a/public/app/plugins/panel/candlestick/CandlestickPanel.tsx
+++ b/public/app/plugins/panel/candlestick/CandlestickPanel.tsx
@@ -323,6 +323,7 @@ export const CandlestickPanel = ({
/>
)}
)}
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