function getPanelValue()

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;
  }
}