Skip to content

Commit

Permalink
feat: cancel brush/click event with escape key (#819)
Browse files Browse the repository at this point in the history
  • Loading branch information
nickofthyme committed Sep 16, 2020
1 parent 5227b2e commit b599d13
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 22 deletions.
41 changes: 34 additions & 7 deletions src/components/chart_container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ import { connect } from 'react-redux';
import { bindActionCreators, Dispatch } from 'redux';

import { SettingsSpec } from '../specs';
import { onMouseUp, onMouseDown, onPointerMove } from '../state/actions/mouse';
import { onKeyPress as onKeyPressAction } from '../state/actions/key';
import {
onMouseUp as onMouseUpAction,
onMouseDown as onMouseDownAction,
onPointerMove as onPointerMoveAction,
} from '../state/actions/mouse';
import { GlobalChartState, BackwardRef } from '../state/chart_state';
import { getInternalChartRendererSelector } from '../state/selectors/get_chart_type_components';
import { getInternalPointerCursor } from '../state/selectors/get_internal_cursor_pointer';
Expand All @@ -46,9 +51,10 @@ interface ChartContainerComponentStateProps {
) => JSX.Element | null;
}
interface ChartContainerComponentDispatchProps {
onPointerMove: typeof onPointerMove;
onMouseUp: typeof onMouseUp;
onMouseDown: typeof onMouseDown;
onPointerMove: typeof onPointerMoveAction;
onMouseUp: typeof onMouseUpAction;
onMouseDown: typeof onMouseDownAction;
onKeyPress: typeof onKeyPressAction;
}

interface ChartContainerComponentOwnProps {
Expand All @@ -74,6 +80,7 @@ class ChartContainerComponent extends React.Component<ReactiveChartProps> {
if (isChartEmpty) {
return;
}

onPointerMove(
{
x: offsetX,
Expand Down Expand Up @@ -101,9 +108,13 @@ class ChartContainerComponent extends React.Component<ReactiveChartProps> {
if (isChartEmpty) {
return;
}

if (isBrushingAvailable) {
window.addEventListener('mouseup', this.handleBrushEnd);
}

window.addEventListener('keyup', this.handleKeyUp);

onMouseDown(
{
x: offsetX,
Expand All @@ -118,6 +129,9 @@ class ChartContainerComponent extends React.Component<ReactiveChartProps> {
if (isChartEmpty) {
return;
}

window.removeEventListener('keyup', this.handleKeyUp);

onMouseUp(
{
x: offsetX,
Expand All @@ -127,10 +141,22 @@ class ChartContainerComponent extends React.Component<ReactiveChartProps> {
);
};

handleKeyUp = ({ key }: KeyboardEvent) => {
window.removeEventListener('keyup', this.handleKeyUp);

const { isChartEmpty, onKeyPress } = this.props;
if (isChartEmpty) {
return;
}

onKeyPress(key);
};

handleBrushEnd = () => {
const { onMouseUp } = this.props;

window.removeEventListener('mouseup', this.handleBrushEnd);

requestAnimationFrame(() => {
onMouseUp(
{
Expand Down Expand Up @@ -179,9 +205,10 @@ class ChartContainerComponent extends React.Component<ReactiveChartProps> {
const mapDispatchToProps = (dispatch: Dispatch): ChartContainerComponentDispatchProps =>
bindActionCreators(
{
onPointerMove,
onMouseUp,
onMouseDown,
onPointerMove: onPointerMoveAction,
onMouseUp: onMouseUpAction,
onMouseDown: onMouseDownAction,
onKeyPress: onKeyPressAction,
},
dispatch,
);
Expand Down
2 changes: 2 additions & 0 deletions src/state/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { ChartActions } from './chart';
import { ChartSettingsActions } from './chart_settings';
import { ColorsActions } from './colors';
import { EventsActions } from './events';
import { KeyActions } from './key';
import { LegendActions } from './legend';
import { MouseActions } from './mouse';
import { SpecActions } from './specs';
Expand All @@ -33,4 +34,5 @@ export type StateActions =
| LegendActions
| EventsActions
| MouseActions
| KeyActions
| ColorsActions;
41 changes: 41 additions & 0 deletions src/state/actions/key.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

/** @internal */
export const ON_KEY_UP = 'ON_KEY_UP';

interface KeyUpAction {
type: typeof ON_KEY_UP;
/**
* Keyboard key from event
*/
key: string;
}

/**
* Action called on `keyup` event
* @param key keyboard key
* @internal
*/
export function onKeyPress(key: string): KeyUpAction {
return { type: ON_KEY_UP, key };
}

/** @internal */
export type KeyActions = KeyUpAction;
16 changes: 2 additions & 14 deletions src/state/chart_state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { interactionsReducer } from './reducers/interactions';
import { getInternalIsInitializedSelector, InitStatus } from './selectors/get_internal_is_intialized';
import { getLegendItemsSelector } from './selectors/get_legend_items';
import { LegendItemLabel } from './selectors/get_legend_items_labels';
import { getInitialPointerState } from './utils';

export type BackwardRef = () => React.RefObject<HTMLDivElement>;

Expand Down Expand Up @@ -252,20 +253,7 @@ export const getInitialState = (chartId: string): GlobalChartState => ({
chartType: null,
internalChartState: null,
interactions: {
pointer: {
dragging: false,
current: {
position: {
x: -1,
y: -1,
},
time: 0,
},
down: null,
up: null,
lastDrag: null,
lastClick: null,
},
pointer: getInitialPointerState(),
legendCollapsed: false,
highlightedLegendItemKey: null,
deselectedDataSeries: [],
Expand Down
14 changes: 13 additions & 1 deletion src/state/reducers/interactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import { getSeriesIndex } from '../../chart_types/xy_chart/utils/series';
import { LegendItem } from '../../commons/legend';
import { SeriesIdentifier } from '../../commons/series_id';
import { ON_KEY_UP, KeyActions } from '../actions/key';
import {
ON_TOGGLE_LEGEND,
ON_LEGEND_ITEM_OUT,
Expand All @@ -30,14 +31,25 @@ import {
} from '../actions/legend';
import { ON_MOUSE_DOWN, ON_MOUSE_UP, ON_POINTER_MOVE, MouseActions } from '../actions/mouse';
import { InteractionsState } from '../chart_state';
import { getInitialPointerState } from '../utils';

/** @internal */
export function interactionsReducer(
state: InteractionsState,
action: LegendActions | MouseActions,
action: LegendActions | MouseActions | KeyActions,
legendItems: LegendItem[],
): InteractionsState {
switch (action.type) {
case ON_KEY_UP:
if (action.key === 'Escape') {
return {
...state,
pointer: getInitialPointerState(),
};
}

return state;

case ON_POINTER_MOVE:
return {
...state,
Expand Down
16 changes: 16 additions & 0 deletions src/state/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,19 @@ export function isClicking(prevClick: PointerState | null, lastClick: PointerSta
}
return false;
}

/** @internal */
export const getInitialPointerState = () => ({
dragging: false,
current: {
position: {
x: -1,
y: -1,
},
time: 0,
},
down: null,
up: null,
lastDrag: null,
lastClick: null,
});

0 comments on commit b599d13

Please sign in to comment.