import { pointBisector , getDataBeforeDate } from '../common/dataFilters' ; import { DataPoint , DataStream , Primitive } from '../../../utils/dataTypes' ; import { sortTooltipPoints } from '../sc-tooltip/sort' ; import { getDataPoints } from '../../../utils/getDataPoints' ; import { DATA_ALIGNMENT } from '../common/constants' ; export type ActivePoint < T extends Primitive > = { streamId : string ; label ? : string ; point ? : DataPoint < T > ; } ; /**
 * To differentiate between points that come from data streams and points that come from trend lines
 */ export const enum POINT_TYPE { DATA = 'data' , TREND = 'trend' } export type ActivePointWithType < T extends Primitive > = ActivePoint < T > & { type : POINT_TYPE ; } ; param maxDistance export const closestPoint = < T extends Primitive > ( dataPoints , date , dataAlignment , maxDistance ? ) : DataPoint < T > | undefined => { const idx = pointBisector . left ( dataPoints , date ) ; const leftPoint = dataPoints [ idx - 1 ] ; const rightPoint = dataPoints [ idx ] ; /**
     * If a point falls on our point of time, return it immediately regardless of 'data alignment'.
     */ if ( leftPoint && leftPoint . x === date . getTime ( ) ) { return leftPoint ; } if ( rightPoint && rightPoint . x === date . getTime ( ) ) { return rightPoint ; } /** Right Alignment */ if ( dataAlignment === DATA_ALIGNMENT . RIGHT ) { if ( ! rightPoint ) { return undefined ; } if ( maxDistance == null ) { return rightPoint ; } return rightPoint . x - date . getTime ( ) <= maxDistance ? rightPoint : undefined ; } /** Left Alignment */ if ( dataAlignment === DATA_ALIGNMENT . LEFT ) { if ( ! leftPoint ) { return undefined ; } if ( maxDistance == null ) { return leftPoint ; } return date . getTime ( ) - leftPoint . x <= maxDistance ? leftPoint : undefined ; } /** Either Alignment */ if ( ! leftPoint || ! rightPoint ) { return leftPoint || rightPoint ; } return rightPoint ; } ; /**
 * Get Active Points
 *
 * Returns at most one point per data stream - for each data stream, it finds the point which is
 * 1. within the given view port
 * 2. closest to the provided `selectedDate`
 *
 * Additionally, if `allowMultipleDates` is false, it will only return the points which are the closest
 * to the `selectedDate`. i.e. if you have 10 points that are all equally distant from the `selectedDate`,
 * all 10 are returned.
 *
 * However if you have 10 points of different dates, only the closest point would be returned.
 */ export const activePoints = < T extends Primitive > ( { viewport , dataStreams , selectedDate , allowMultipleDates , dataAlignment , maxDurationFromDate , } ) : ActivePoint < T > [ ] => { const dataStreamUtilizedData = dataStreams . map ( stream => ( { streamId : stream . id , dataPoints : getDataBeforeDate ( getDataPoints ( stream , stream . resolution ) , viewport . end ) , } ) ) ; const selectedTimestamp = selectedDate . getTime ( ) ; const points = dataStreamUtilizedData . map ( ( { streamId , dataPoints } ) => ( { streamId , point : closestPoint ( dataPoints , selectedDate , dataAlignment , maxDurationFromDate ) , } ) ) ; if ( allowMultipleDates ) { return points ; } const distanceFromDate = ( p ) : number => Math . abs ( p . x - selectedTimestamp ) ; const sortedPoints = points . sort ( sortTooltipPoints ( distanceFromDate ) ) ; if ( sortedPoints . length === 0 ) { return [ ] ; } const topPoint = sortedPoints [ sortedPoints . length - 1 ] . point ; if ( topPoint == null ) { return sortedPoints ; } return sortedPoints . filter ( p => p . point && p . point . x === topPoint . x ) ; } ;