in packages/charts/src/chart_types/xy_chart/annotations/rect/dimensions.ts [37:174]
export function computeRectAnnotationDimensions(
annotationSpec: RectAnnotationSpec,
yScales: Map<GroupId, ScaleContinuous>,
xScale: ScaleBand | ScaleContinuous,
axesSpecs: AxisSpec[],
smallMultiplesScales: SmallMultipleScales,
chartRotation: Rotation,
getAxisStyle: (id?: AxisId) => AxisStyle,
isHistogram: boolean = false,
): AnnotationRectProps[] | null {
const { dataValues, groupId, outside, id: annotationSpecId } = annotationSpec;
const { xAxis, yAxis } = getAxesSpecForSpecId(axesSpecs, groupId, chartRotation);
const yScale = yScales.get(groupId);
const rectsProps: Omit<AnnotationRectProps, 'id' | 'panel'>[] = [];
const panelSize = getPanelSize(smallMultiplesScales);
dataValues.forEach((datum: RectAnnotationDatum) => {
const { x0: initialX0, x1: initialX1, y0: initialY0, y1: initialY1 } = datum.coordinates;
// if everything is null, return; otherwise we coerce the other coordinates
if (initialX0 === null && initialX1 === null && initialY0 === null && initialY1 === null) {
return;
}
let height: number | undefined;
const [x0, x1] = limitValueToDomainRange(xScale, initialX0, initialX1, isHistogram);
// something is wrong with the data types, don't draw this annotation
if (x0 === null || x1 === null) {
return;
}
let xAndWidth: { x: number; width: number } | null = null;
if (isBandScale(xScale)) {
xAndWidth = scaleXonBandScale(xScale, x0, x1);
} else if (isContinuousScale(xScale)) {
xAndWidth = scaleXonContinuousScale(xScale, x0, x1, isHistogram);
}
// something is wrong with scales, don't draw
if (!xAndWidth) {
return;
}
const hasYValues = isDefined(initialY0) || isDefined(initialY1);
const outsideDim = annotationSpec.outsideDimension ?? getOutsideDimension(getAxisStyle(xAxis?.id ?? yAxis?.id));
if (!yScale) {
if (!hasYValues) {
// only x values present, just fill full height of chart space
const rectDimensions: Rect = {
...xAndWidth,
...(outside
? getXOutsideAnnotationDimensions(panelSize, chartRotation, xAxis?.position ?? 'bottom', outsideDim)
: {
y: 0,
height: isHorizontalRotation(chartRotation) ? panelSize.height : panelSize.width,
}),
};
rectsProps.push({
specId: annotationSpecId,
rect: rectDimensions,
datum,
});
}
return; // cannot scale y values without a scale
}
const hasXValues = isDefined(initialX0) || isDefined(initialX1);
if (outside) {
if (hasXValues && hasYValues) {
Logger.warn(
`The RectAnnotation (${annotationSpecId}) was defined as outside but has both x and y values defined.`,
);
} else if (hasXValues) {
const rectDimensions: Rect = {
...xAndWidth,
...getXOutsideAnnotationDimensions(panelSize, chartRotation, xAxis?.position ?? 'bottom', outsideDim),
};
rectsProps.push({
specId: annotationSpecId,
rect: rectDimensions,
datum,
});
return;
}
}
const [y0, y1] = limitValueToDomainRange(yScale, initialY0, initialY1);
// something is wrong with the data types, don't draw this annotation
if (!Number.isFinite(y0) || !Number.isFinite(y1)) return;
let scaledY1 = yScale.pureScale(y1);
const scaledY0 = yScale.pureScale(y0);
if (Number.isNaN(scaledY1) || Number.isNaN(scaledY0)) return;
height = Math.abs(scaledY0 - scaledY1);
// if the annotation height is 0, override it with the height from chart dimension and if the values in the domain are the same
if (height === 0 && yScale.domain.length === 2 && yScale.domain[0] === yScale.domain[1]) {
// eslint-disable-next-line prefer-destructuring
height = panelSize.height;
scaledY1 = 0;
}
const rectDimensions: Rect = {
...xAndWidth,
y: scaledY1,
height,
...(outside &&
!(hasXValues && hasYValues) &&
getYOutsideAnnotationDimensions(panelSize, chartRotation, yAxis?.position ?? 'left', outsideDim)),
};
rectsProps.push({
specId: annotationSpecId,
rect: rectDimensions,
datum,
});
});
return rectsProps.reduce<AnnotationRectProps[]>((acc, props, i) => {
const duplicated: AnnotationRectProps[] = [];
smallMultiplesScales.vertical.domain.forEach((vDomainValue) => {
smallMultiplesScales.horizontal.domain.forEach((hDomainValue) => {
const id = getAnnotationRectPropsId(annotationSpecId, props.datum, i, vDomainValue, hDomainValue);
const top = smallMultiplesScales.vertical.scale(vDomainValue);
const left = smallMultiplesScales.horizontal.scale(hDomainValue);
if (Number.isNaN(top + left)) return;
const panel = { ...panelSize, top, left };
duplicated.push({ ...props, panel, id });
});
});
return acc.concat(duplicated);
}, []);
}