in packages/charts/src/chart_types/bullet_graph/selectors/get_active_value.ts [67:168]
function getPanelValue(
panel: BulletPanelDimensions,
pointer: Point,
spec: BulletSpec,
): Pick<ActiveValueDetails, 'value' | 'snapValue' | 'color' | 'pixelValue'> | undefined {
const { graphArea, scale } = panel;
const [min, max] = sortNumbers(scale.domain()) as ContinuousDomain;
const isWithinDomain = isBetween(min, max);
switch (spec.subtype) {
case BulletSubtype.circle:
case BulletSubtype.halfCircle:
case BulletSubtype.twoThirdsCircle: {
const { radius } = getAngledChartSizing(graphArea.size, spec.subtype);
const center = {
x: graphArea.center.x,
y: radius + TARGET_SIZE / 2,
};
const { x, y } = pointer;
const normalizedPointer = {
x: x - center.x - graphArea.origin.x - GRAPH_PADDING.left,
y: y - center.y - graphArea.origin.y - GRAPH_PADDING.top,
};
const distance = Math.sqrt(Math.pow(normalizedPointer.x, 2) + Math.pow(normalizedPointer.y, 2));
const outerLimit = radius + BULLET_SIZE / 2 + HOVER_SLOP;
const innerLimit = radius - BULLET_SIZE / 2 - HOVER_SLOP;
if (distance <= outerLimit && distance >= innerLimit) {
// TODO find why to determine angle between origin and point
// The angle goes from -π in Quadrant 2 to +π in Quadrant 3
// This angle offset is a temporary fix
const angleOffset = normalizedPointer.x < 0 && normalizedPointer.y > 0 ? -TAU : 0;
const angle: Radian = Math.atan2(normalizedPointer.y, normalizedPointer.x) + angleOffset;
const value = scale.invert(angle);
const snapValue = spec.tickSnapStep ? roundTo(value, spec.tickSnapStep) : value;
if (isWithinDomain(snapValue)) {
return {
value,
snapValue,
color: panel.colorScale(snapValue).hex(),
pixelValue: angle,
};
}
}
break;
}
case BulletSubtype.horizontal: {
const yCenterOffset = Math.abs(pointer.y - graphArea.origin.y - TARGET_SIZE / 2);
if (yCenterOffset > TARGET_SIZE / 2 + HOVER_SLOP) return;
const relativeX = pointer.x - GRAPH_PADDING.left;
const [min, max] = scale.range() as Range;
if (relativeX < min || relativeX > max) break;
const value = panel.scale.invert(relativeX);
const snapValue = spec.tickSnapStep ? roundTo(value, spec.tickSnapStep) : value;
if (isWithinDomain(snapValue)) {
return {
value,
snapValue,
color: panel.colorScale(snapValue).hex(),
pixelValue: relativeX,
};
}
break;
}
case BulletSubtype.vertical: {
const xCenterOffset = Math.abs(pointer.x - graphArea.center.x - GRAPH_PADDING.left);
if (xCenterOffset > TARGET_SIZE / 2 + HOVER_SLOP) return;
const relativeY = panel.panel.height - pointer.y - GRAPH_PADDING.bottom;
const [min, max] = scale.range() as Range;
if (relativeY < min || relativeY > max) break;
const value = panel.scale.invert(relativeY);
const snapValue = spec.tickSnapStep ? roundTo(value, spec.tickSnapStep) : value;
if (isWithinDomain(snapValue)) {
return {
value,
snapValue,
color: panel.colorScale(snapValue).hex(),
pixelValue: relativeY,
};
}
break;
}
default:
return;
}
}