Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ import {
import { ChartState } from '../../models/chart';
import { UseChartCartesianAxisSignature } from './useChartCartesianAxis.types';
import { ComputeResult } from './computeAxisValue';
import {
selectorChartsKeyboardXAxisIndex,
selectorChartsKeyboardYAxisIndex,
} from '../useChartKeyboardNavigation/useChartKeyboardNavigation.selectors';
import { selectorChartsLastInteraction } from '../useChartInteraction/useChartInteraction.selectors';
import { InteractionUpdateSource } from '../useChartInteraction/useChartInteraction.types';

const selectorChartControlledCartesianAxisHighlight = (
state: ChartState<[], [UseChartCartesianAxisSignature]>,
Expand Down Expand Up @@ -48,19 +54,48 @@ const selectAxisHighlightWithValue = (
computedIndex: number | null,
computedValue: number | Date | null,
axis: ComputeResult<ChartsAxisProps>,
axisItems: AxisItemIdentifier[] | undefined,
controlledAxisItems: AxisItemIdentifier[] | undefined,
keyboardAxisItem: AxisItemIdentifier | undefined,
lastInteractionUpdate: InteractionUpdateSource | undefined,
) => {
if (axisItems !== undefined) {
return axisItems
if (controlledAxisItems !== undefined) {
return controlledAxisItems
.map((item) => ({
...item,
value: axis.axis[item.axisId]?.data?.[item.dataIndex],
}))
.filter(({ value }) => value !== undefined);
}
return computedValue === null
? []
: [{ axisId: axis.axisIds[0], dataIndex: computedIndex, value: computedValue }];

const pointerHighlight = computedValue !== null && {
axisId: axis.axisIds[0],
dataIndex: computedIndex,
value: computedValue,
};
const keyboardValue =
keyboardAxisItem && axis.axis[keyboardAxisItem.axisId]?.data?.[keyboardAxisItem.dataIndex];
const keyboardHighlight = keyboardAxisItem &&
keyboardValue != null && { ...keyboardAxisItem, value: keyboardValue };

if (lastInteractionUpdate === 'pointer') {
if (pointerHighlight) {
return [pointerHighlight];
}
if (keyboardHighlight) {
return [keyboardHighlight];
}
}

if (lastInteractionUpdate === 'keyboard') {
if (keyboardHighlight) {
return [keyboardHighlight];
}
if (pointerHighlight) {
return [pointerHighlight];
}
}

return [];
};

export const selectorChartsHighlightXAxisValue = createSelector(
Expand All @@ -69,6 +104,8 @@ export const selectorChartsHighlightXAxisValue = createSelector(
selectorChartsInteractionXAxisValue,
selectorChartXAxis,
selectorChartControlledCartesianAxisHighlight,
selectorChartsKeyboardXAxisIndex,
selectorChartsLastInteraction,
],
selectAxisHighlightWithValue,
);
Expand All @@ -79,6 +116,8 @@ export const selectorChartsHighlightYAxisValue = createSelector(
selectorChartsInteractionYAxisValue,
selectorChartYAxis,
selectorChartControlledCartesianAxisHighlight,
selectorChartsKeyboardYAxisIndex,
selectorChartsLastInteraction,
],
selectAxisHighlightWithValue,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,8 @@ export const selectorChartsInteractionItemIsDefined = createSelector(
[selectorChartsInteractionItem],
(item) => item !== null,
);

export const selectorChartsLastInteraction = createSelector(
[selectInteraction],
(interaction) => interaction?.lastUpdate,
);
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const useChartInteraction: ChartPlugin<UseChartInteractionSignature> = ({
store.update((prev) => {
return {
...prev,
interaction: { pointer: null, item: null },
interaction: { ...prev.interaction, pointer: null, item: null },
};
});
});
Expand Down Expand Up @@ -85,6 +85,7 @@ export const useChartInteraction: ChartPlugin<UseChartInteractionSignature> = ({
interaction: {
...prev.interaction,
pointer: coordinate,
lastUpdate: coordinate !== null ? 'pointer' : prev.interaction.lastUpdate,
},
}));
});
Expand All @@ -100,7 +101,7 @@ export const useChartInteraction: ChartPlugin<UseChartInteractionSignature> = ({
};

useChartInteraction.getInitialState = () => ({
interaction: { item: null, pointer: null },
interaction: { item: null, pointer: null, lastUpdate: 'pointer' },
});

useChartInteraction.params = {};
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {

export type Coordinate = { x: number; y: number };

export type InteractionUpdateSource = 'pointer' | 'keyboard';

export interface UseChartInteractionInstance {
/**
* Remove all interaction.
Expand Down Expand Up @@ -39,6 +41,11 @@ export interface UseChartInteractionState {
* The x/y SVG coordinate of the "main" pointer
*/
pointer: Coordinate | null;
/**
* The last interaction highlight update.
* Used to decide if highlight should be based on pointer position or keyboard navigation.
*/
lastUpdate: InteractionUpdateSource;
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import { ChartOptionalRootSelector, createSelector } from '../../utils/selectors';
import { UseChartKeyboardNavigationSignature } from './useChartKeyboardNavigation.types';
import { ProcessedSeries, selectorChartSeriesProcessed } from '../../corePlugins/useChartSeries';
import {
selectorChartXAxis,
selectorChartYAxis,
} from '../useChartCartesianAxis/useChartCartesianAxisRendering.selectors';
import { ComputeResult } from '../useChartCartesianAxis/computeAxisValue';
import { ChartSeriesType } from '../../../../models/seriesType/config';
import { SeriesId } from '../../../../models/seriesType/common';
import { AxisId, AxisItemIdentifier, ChartsAxisProps } from '../../../../models/axis';

const selectKeyboardNavigation: ChartOptionalRootSelector<UseChartKeyboardNavigationSignature> = (
state,
Expand Down Expand Up @@ -29,3 +38,59 @@ export const selectorChartsIsKeyboardNavigationEnabled = createSelector(
[selectKeyboardNavigation],
(keyboardNavigationState) => !!keyboardNavigationState?.enableKeyboardNavigation,
);

/**
* Selectors to override highlight behavior.
*/

const createSelectAxisHighlight =
(direction: 'x' | 'y') =>
<T extends ChartSeriesType>(
type: T | undefined,
seriesId: SeriesId | undefined,
dataIndex: number | undefined,
axis: ComputeResult<ChartsAxisProps>,
series: ProcessedSeries<T>,
): AxisItemIdentifier | undefined => {
if (type === undefined || seriesId === undefined || dataIndex === undefined) {
return undefined;
}

const seriesConfig = series[type]?.series[seriesId];
if (!seriesConfig) {
return undefined;
}

let axisId: AxisId | false | undefined =
direction === 'x'
? 'xAxisId' in seriesConfig && seriesConfig.xAxisId
: 'yAxisId' in seriesConfig && seriesConfig.yAxisId;

if (axisId === undefined || axisId === false) {
axisId = axis.axisIds[0];
}

return { axisId, dataIndex };
};

export const selectorChartsKeyboardXAxisIndex = createSelector(
[
selectorChartsFocusedSeriesType,
selectorChartsFocusedSeriesId,
selectorChartsFocusedDataIndex,
selectorChartXAxis,
selectorChartSeriesProcessed,
],
createSelectAxisHighlight('x'),
);

export const selectorChartsKeyboardYAxisIndex = createSelector(
[
selectorChartsFocusedSeriesType,
selectorChartsFocusedSeriesId,
selectorChartsFocusedDataIndex,
selectorChartYAxis,
selectorChartSeriesProcessed,
],
createSelectAxisHighlight('y'),
);
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ export const useChartKeyboardNavigation: ChartPlugin<UseChartKeyboardNavigationS

return {
...state,
...(state.interaction
? { interaction: { ...state.interaction, lastUpdate: 'keyboard' } }
: {}),
keyboardNavigation: {
...state.keyboardNavigation,
item: {
Expand Down Expand Up @@ -75,7 +78,7 @@ export const useChartKeyboardNavigation: ChartPlugin<UseChartKeyboardNavigationS
...state,
keyboardNavigation: {
...state.keyboardNavigation,
item: null, // No series to move the focus too.} };
item: null, // No series to move the focus too.
},
};
}
Expand All @@ -87,6 +90,9 @@ export const useChartKeyboardNavigation: ChartPlugin<UseChartKeyboardNavigationS

return {
...state,
...(state.interaction
? { interaction: { ...state.interaction, lastUpdate: 'keyboard' } }
: {}),
keyboardNavigation: {
...state.keyboardNavigation,
item: {
Expand Down Expand Up @@ -127,6 +133,9 @@ export const useChartKeyboardNavigation: ChartPlugin<UseChartKeyboardNavigationS
setNewSeries = true;
return {
...state,
...(state.interaction
? { interaction: { ...state.interaction, lastUpdate: 'keyboard' } }
: {}),
keyboardNavigation: {
...state.keyboardNavigation,
item: {
Expand Down Expand Up @@ -165,6 +174,9 @@ export const useChartKeyboardNavigation: ChartPlugin<UseChartKeyboardNavigationS
setNewSeries = true;
return {
...state,
...(state.interaction
? { interaction: { ...state.interaction, lastUpdate: 'keyboard' } }
: {}),
keyboardNavigation: {
...state.keyboardNavigation,
item: {
Expand Down Expand Up @@ -196,6 +208,7 @@ export const useChartKeyboardNavigation: ChartPlugin<UseChartKeyboardNavigationS

React.useEffect(() => {
const element = svgRef.current;

if (!element || !params.enableKeyboardNavigation) {
return undefined;
}
Expand All @@ -204,9 +217,11 @@ export const useChartKeyboardNavigation: ChartPlugin<UseChartKeyboardNavigationS
switch (event.key) {
case 'ArrowRight':
focusNextItem();

break;
case 'ArrowLeft':
focusPreviousItem();

break;
case 'ArrowDown': {
const updatedStore = focusPreviousSeries();
Expand Down Expand Up @@ -240,6 +255,7 @@ export const useChartKeyboardNavigation: ChartPlugin<UseChartKeyboardNavigationS
};
}, [
svgRef,

focusNextItem,
focusPreviousItem,
removeFocus,
Expand All @@ -265,9 +281,7 @@ export const useChartKeyboardNavigation: ChartPlugin<UseChartKeyboardNavigationS
[store, params.enableKeyboardNavigation],
);

return {
instance: {},
};
return {};
};

useChartKeyboardNavigation.getInitialState = (params) => ({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ChartPluginSignature } from '../../models';
import { ChartSeriesType } from '../../../../models/seriesType/config';
import { SeriesId } from '../../../../models/seriesType/common';
import { UseChartInteractionSignature } from '../useChartInteraction';

export interface UseChartKeyboardNavigationInstance {}

Expand Down Expand Up @@ -35,4 +36,5 @@ export type UseChartKeyboardNavigationSignature = ChartPluginSignature<{
defaultizedParams: UseChartKeyboardNavigationParameters;
instance: UseChartKeyboardNavigationInstance;
state: UseChartKeyboardNavigationState;
optionalDependencies: [UseChartInteractionSignature];
}>;
Loading