function getTooltipAndHighlightFromValue()

in packages/charts/src/chart_types/xy_chart/state/selectors/get_tooltip_values_highlighted_geoms.ts [77:208]


function getTooltipAndHighlightFromValue(
  seriesSpecs: BasicSeriesSpec[],
  axesSpecs: AxisSpec[],
  settings: SettingsSpec,
  projectedPointerPosition: Point,
  orientedProjectedPointerPosition: Point,
  chartRotation: Rotation,
  hasSingleSeries: boolean,
  scales: ComputedScales,
  matchingGeoms: IndexedGeometry[],
  seriesIdentifierDataSeriesMap: Record<string, DataSeries>,
  externalPointerEvent: PointerEvent | null,
  tooltip: TooltipSpec,
): TooltipAndHighlightedGeoms {
  if (!scales.xScale || !scales.yScales) {
    return EMPTY_VALUES;
  }

  let { x, y } = orientedProjectedPointerPosition;
  let tooltipType = getTooltipType(tooltip, settings);
  if (isValidPointerOverEvent(scales.xScale, externalPointerEvent)) {
    tooltipType = getTooltipType(tooltip, settings, true);
    if (isNil(externalPointerEvent.x)) {
      return EMPTY_VALUES;
    }
    const scaledX = scales.xScale.pureScale(externalPointerEvent.x);

    if (Number.isNaN(scaledX)) {
      return EMPTY_VALUES;
    }

    x = scaledX;
    y = 0;
  } else if (projectedPointerPosition.x === -1 || projectedPointerPosition.y === -1) {
    return EMPTY_VALUES;
  }

  if (tooltipType === TooltipType.None && !externalPointerEvent) {
    return EMPTY_VALUES;
  }

  if (matchingGeoms.length === 0) {
    return EMPTY_VALUES;
  }

  // build the tooltip value list
  let header: PointerValue | null = null;
  const highlightedGeometries: IndexedGeometry[] = [];
  const xValues = new Set<any>();
  const hideNullValues = !tooltip.showNullValues;
  const values = matchingGeoms
    .slice()
    .sort((a, b) => {
      // presort matchingGeoms to group by series then y value to prevent flipping
      return b.seriesIdentifier.key.localeCompare(a.seriesIdentifier.key) || b.value.y - a.value.y;
    })
    .reduce<TooltipValue[]>((acc, indexedGeometry) => {
      if (hideNullValues && indexedGeometry.value.y === null) {
        return acc;
      }
      const {
        seriesIdentifier: { specId },
      } = indexedGeometry;
      const spec = getSpecsById<BasicSeriesSpec>(seriesSpecs, specId);

      // safe guard check
      if (!spec) {
        return acc;
      }
      const { xAxis, yAxis } = getAxesSpecForSpecId(axesSpecs, spec.groupId, chartRotation);

      // yScales is ensured by the enclosing if
      const yScale = scales.yScales.get(getSpecDomainGroupId(spec));
      if (!yScale) {
        return acc;
      }

      // check if the pointer is on the geometry (avoid checking if using external pointer event)
      let isHighlighted = false;
      if (
        (!externalPointerEvent || isPointerOutEvent(externalPointerEvent)) &&
        isPointOnGeometry(x, y, indexedGeometry, settings.pointBuffer)
      ) {
        isHighlighted = true;
        highlightedGeometries.push(indexedGeometry);
      }

      // format the tooltip values
      const formattedTooltip = formatTooltipValue(
        indexedGeometry,
        spec,
        isHighlighted,
        hasSingleSeries,
        isBandedSpec(spec),
        yAxis,
      );

      // format only one time the x value
      if (!header) {
        // if we have a tooltipHeaderFormatter, then don't pass in the xAxis as the user will define a formatter
        const formatterAxis = tooltip.headerFormatter ? undefined : xAxis;
        header = formatTooltipHeader(indexedGeometry, spec, formatterAxis);
      }

      xValues.add(indexedGeometry.value.x);

      return [...acc, formattedTooltip];
    }, []);

  if (values.length > 1 && xValues.size === values.length) {
    // TODO: remove after tooltip redesign
    header = null;
  }

  const baseTooltipSortFn: SeriesCompareFn = (a, b) => {
    const aDs = seriesIdentifierDataSeriesMap[a.key];
    const bDs = seriesIdentifierDataSeriesMap[b.key];
    return defaultXYLegendSeriesSort(aDs, bDs);
  };
  const tooltipSortFn = tooltip.sort ?? settings.legendSort ?? baseTooltipSortFn;
  const sortedTooltipValues = values.sort((a, b) => {
    return tooltipSortFn(a.seriesIdentifier, b.seriesIdentifier);
  });

  return {
    tooltip: {
      header,
      values: sortedTooltipValues,
    },
    highlightedGeometries,
  };
}