Skip to content

Commit

Permalink
Enforce stricter types for default interactions config
Browse files Browse the repository at this point in the history
  • Loading branch information
axelboc committed Jul 1, 2022
1 parent dba830e commit 0b5ad5c
Show file tree
Hide file tree
Showing 17 changed files with 143 additions and 99 deletions.
36 changes: 36 additions & 0 deletions apps/storybook/src/DefaultInteractions.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { DefaultInteractions, ResetZoomButton, VisCanvas } from '@h5web/lib';
import type { DefaultInteractionsProps } from '@h5web/lib/src/interactions/DefaultInteractions';
import type { Meta, Story } from '@storybook/react';

import FillHeight from './decorators/FillHeight';

const Template: Story<DefaultInteractionsProps> = (args) => {
return (
<VisCanvas
abscissaConfig={{ visDomain: [-10, 0], showGrid: true }}
ordinateConfig={{ visDomain: [50, 100], showGrid: true }}
>
<DefaultInteractions {...args} />
<ResetZoomButton />
</VisCanvas>
);
};

export const Default = Template.bind({});

export default {
title: 'Building Blocks/DefaultInteractions',
component: DefaultInteractions,
decorators: [FillHeight],
parameters: { layout: 'fullscreen' },
argTypes: {
keepRatio: { defaultValue: false },
pan: { defaultValue: {} },
zoom: { defaultValue: {} },
xAxisZoom: { defaultValue: { modifierKey: 'Alt' } },
yAxisZoom: { defaultValue: { modifierKey: 'Shift' } },
selectToZoom: { defaultValue: { modifierKey: 'Control' } },
xSelectToZoom: { defaultValue: { modifierKey: ['Control', 'Alt'] } },
ySelectToZoom: { defaultValue: { modifierKey: ['Control', 'Shift'] } },
},
} as Meta<DefaultInteractionsProps>;
6 changes: 3 additions & 3 deletions apps/storybook/src/HeatmapVis.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ ChangeInteractionKeys.args = {
dataArray,
domain,
interactions: {
XAxisZoom: false,
YAxisZoom: false,
SelectToZoom: { modifierKey: 'Shift' },
xAxisZoom: false,
yAxisZoom: false,
selectToZoom: { modifierKey: 'Shift' },
},
};

Expand Down
2 changes: 1 addition & 1 deletion packages/lib/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export { default as HeatmapMesh } from './vis/heatmap/HeatmapMesh';
export type { HeatmapMeshProps } from './vis/heatmap/HeatmapMesh';

// Interactions
export { default as DefaultInteractions } from './interactions/DefaultInteractions';
export { default as Pan } from './interactions/Pan';
export { default as Zoom } from './interactions/Zoom';
export { default as XAxisZoom } from './interactions/XAxisZoom';
Expand Down Expand Up @@ -144,4 +145,3 @@ export type { TiledHeatmapMeshProps } from './vis/tiles/TiledHeatmapMesh';
export { getLayerSizes, TilesApi } from './vis/tiles/api';
export { useValidDomainForScale } from './vis/hooks';
export { assertLength, assertDefined } from '@h5web/shared';
export { default as DefaultInteractions } from './interactions/DefaultInteractions';
9 changes: 4 additions & 5 deletions packages/lib/src/interactions/AxialSelectToZoom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,11 @@ import { getVisibleDomains } from '../vis/utils';
import SelectionRect from './SelectionRect';
import SelectionTool from './SelectionTool';
import { useMoveCameraTo } from './hooks';
import type { ModifierKey, Selection } from './models';
import type { Selection, CommonInteractionProps } from './models';
import { getEnclosedRectangle } from './utils';

interface Props {
interface Props extends CommonInteractionProps {
axis: 'x' | 'y';
disabled?: boolean;
modifierKey?: ModifierKey[] | ModifierKey;
}

function AxialSelectToZoom(props: Props) {
Expand Down Expand Up @@ -73,7 +71,7 @@ function AxialSelectToZoom(props: Props) {
return (
<SelectionTool
onSelectionEnd={onSelectionEnd}
id={`AxialSelectToZoom${axis}`}
id={`${axis.toUpperCase()}SelectToZoom`}
modifierKey={modifierKey}
disabled={disabled}
>
Expand All @@ -89,4 +87,5 @@ function AxialSelectToZoom(props: Props) {
);
}

export type { Props as AxialSelectToZoomProps };
export default AxialSelectToZoom;
93 changes: 57 additions & 36 deletions packages/lib/src/interactions/DefaultInteractions.tsx
Original file line number Diff line number Diff line change
@@ -1,58 +1,79 @@
import { merge } from 'lodash';

import Pan from '../interactions/Pan';
import type { PanProps } from '../interactions/Pan';
import SelectToZoom from '../interactions/SelectToZoom';
import type { SelectToZoomProps } from '../interactions/SelectToZoom';
import XAxisZoom from '../interactions/XAxisZoom';
import type { XAxisZoomProps } from '../interactions/XAxisZoom';
import YAxisZoom from '../interactions/YAxisZoom';
import type { YAxisZoomProps } from '../interactions/YAxisZoom';
import Zoom from '../interactions/Zoom';
import type { ZoomProps } from '../interactions/Zoom';
import AxialSelectToZoom from './AxialSelectToZoom';
import type { Interactions } from './models';
import { getDefaultInteractions } from './utils';
import type { AxialSelectToZoomProps } from './AxialSelectToZoom';

export interface DefaultInteractionsConfig {
pan?: PanProps | false;
zoom?: ZoomProps | false;
xAxisZoom?: XAxisZoomProps | false;
yAxisZoom?: YAxisZoomProps | false;
selectToZoom?: Omit<SelectToZoomProps, 'keepRatio'> | false;
xSelectToZoom?: Omit<AxialSelectToZoomProps, 'axis'> | false;
ySelectToZoom?: Omit<AxialSelectToZoomProps, 'axis'> | false;
}

interface Props {
interactions?: Interactions;
interface Props extends DefaultInteractionsConfig {
keepRatio?: boolean;
}

function DefaultInteractions(props: Props) {
const { interactions: givenInteractions = {}, keepRatio } = props;

const parsedInteractions = Object.fromEntries(
Object.entries(givenInteractions).map(([k, v]) => {
if (v === true) {
return [k, {}];
}

if (v === false) {
return [k, null];
}

return [k, v];
})
);

const interactions = merge(
getDefaultInteractions(keepRatio),
parsedInteractions
);
const { keepRatio, ...interactions } = props;

return (
<>
{interactions.Pan && <Pan {...interactions.Pan} />}
{interactions.Zoom && <Zoom {...interactions.Zoom} />}
{interactions.XAxisZoom && <XAxisZoom {...interactions.XAxisZoom} />}
{interactions.YAxisZoom && <YAxisZoom {...interactions.YAxisZoom} />}
{interactions.SelectToZoom && (
<SelectToZoom {...interactions.SelectToZoom} keepRatio={keepRatio} />
{interactions.pan !== false && <Pan {...interactions.pan} />}
{interactions.zoom !== false && <Zoom {...interactions.zoom} />}

{interactions.xAxisZoom !== false && (
<XAxisZoom
modifierKey="Alt"
disabled={keepRatio}
{...interactions.xAxisZoom}
/>
)}
{interactions.yAxisZoom !== false && (
<YAxisZoom
modifierKey="Shift"
disabled={keepRatio}
{...interactions.yAxisZoom}
/>
)}

{interactions.selectToZoom !== false && (
<SelectToZoom
keepRatio={keepRatio}
modifierKey="Control"
{...interactions.selectToZoom}
/>
)}
{interactions.XSelectToZoom && (
<AxialSelectToZoom axis="x" {...interactions.XSelectToZoom} />
{interactions.xSelectToZoom !== false && (
<AxialSelectToZoom
axis="x"
modifierKey={['Control', 'Alt']}
disabled={keepRatio}
{...interactions.xSelectToZoom}
/>
)}
{interactions.YSelectToZoom && (
<AxialSelectToZoom axis="y" {...interactions.YSelectToZoom} />
{interactions.ySelectToZoom !== false && (
<AxialSelectToZoom
axis="y"
modifierKey={['Control', 'Shift']}
disabled={keepRatio}
{...interactions.ySelectToZoom}
/>
)}
</>
);
}

export type { Props as DefaultInteractionsProps };
export default DefaultInteractions;
9 changes: 7 additions & 2 deletions packages/lib/src/interactions/Pan.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ import {
useInteraction,
} from './hooks';
import { MouseButton } from './models';
import type { CanvasEvent, Interaction } from './models';
import type { CanvasEvent, CommonInteractionProps } from './models';
import { getModifierKeyArray } from './utils';

function Pan(props: Interaction) {
interface Props extends CommonInteractionProps {
button?: MouseButton;
}

function Pan(props: Props) {
const { button = MouseButton.Left, modifierKey, disabled } = props;
const modifierKeys = getModifierKeyArray(modifierKey);

Expand Down Expand Up @@ -68,4 +72,5 @@ function Pan(props: Interaction) {
return null;
}

export type { Props as PanProps };
export default Pan;
5 changes: 3 additions & 2 deletions packages/lib/src/interactions/SelectToZoom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import RatioSelectionRect from './RatioSelectionRect';
import SelectionRect from './SelectionRect';
import SelectionTool from './SelectionTool';
import { useMoveCameraTo } from './hooks';
import type { Interaction, Selection } from './models';
import type { CommonInteractionProps, Selection } from './models';
import { getEnclosedRectangle, getRatioRespectingRectangle } from './utils';

interface Props extends Omit<Interaction, 'button'> {
interface Props extends CommonInteractionProps {
keepRatio?: boolean;
}

Expand Down Expand Up @@ -90,4 +90,5 @@ function SelectToZoom(props: Props) {
);
}

export type { Props as SelectToZoomProps };
export default SelectToZoom;
6 changes: 3 additions & 3 deletions packages/lib/src/interactions/SelectionTool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ import {
useInteraction,
useModifierKeyPressed,
} from './hooks';
import type { CanvasEvent, Interaction, Selection } from './models';
import type { CanvasEvent, CommonInteractionProps, Selection } from './models';
import { MouseButton } from './models';
import { boundPointToFOV, getModifierKeyArray } from './utils';

interface Props extends Omit<Interaction, 'button'> {
interface Props extends CommonInteractionProps {
id?: string;
onSelectionStart?: () => void;
onSelectionChange?: (points: Selection) => void;
onSelectionEnd?: (points: Selection) => void;
id?: string;
children: (points: Selection) => ReactElement;
}

Expand Down
7 changes: 5 additions & 2 deletions packages/lib/src/interactions/XAxisZoom.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { useCanvasEvents, useInteraction, useZoomOnWheel } from './hooks';
import type { WheelInteraction } from './models';
import type { CommonInteractionProps } from './models';
import { getModifierKeyArray } from './utils';

function XAxisZoom(props: WheelInteraction) {
type Props = CommonInteractionProps;

function XAxisZoom(props: Props) {
const { modifierKey, disabled } = props;
const shouldInteract = useInteraction('XAxisZoom', {
modifierKeys: getModifierKeyArray(modifierKey),
Expand All @@ -20,4 +22,5 @@ function XAxisZoom(props: WheelInteraction) {
return null;
}

export type { Props as XAxisZoomProps };
export default XAxisZoom;
7 changes: 5 additions & 2 deletions packages/lib/src/interactions/YAxisZoom.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { useCanvasEvents, useZoomOnWheel, useInteraction } from './hooks';
import type { WheelInteraction } from './models';
import type { CommonInteractionProps } from './models';
import { getModifierKeyArray } from './utils';

function YAxisZoom(props: WheelInteraction) {
type Props = CommonInteractionProps;

function YAxisZoom(props: Props) {
const { modifierKey, disabled } = props;
const shouldInteract = useInteraction('YAxisZoom', {
modifierKeys: getModifierKeyArray(modifierKey),
Expand All @@ -20,4 +22,5 @@ function YAxisZoom(props: WheelInteraction) {
return null;
}

export type { Props as YAxisZoomProps };
export default YAxisZoom;
7 changes: 5 additions & 2 deletions packages/lib/src/interactions/Zoom.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { useCanvasEvents, useZoomOnWheel, useInteraction } from './hooks';
import type { WheelInteraction } from './models';
import type { CommonInteractionProps } from './models';
import { getModifierKeyArray } from './utils';

function Zoom(props: WheelInteraction) {
type Props = CommonInteractionProps;

function Zoom(props: Props) {
const { modifierKey, disabled } = props;
const shouldInteract = useInteraction('Zoom', {
modifierKeys: getModifierKeyArray(modifierKey),
Expand All @@ -21,4 +23,5 @@ function Zoom(props: WheelInteraction) {
return null;
}

export type { Props as ZoomProps };
export default Zoom;
7 changes: 1 addition & 6 deletions packages/lib/src/interactions/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,7 @@ export interface InteractionEntry {
disabled?: boolean;
}

export interface Interaction {
button?: MouseButton;
export interface CommonInteractionProps {
modifierKey?: ModifierKey | ModifierKey[];
disabled?: boolean;
}

export type WheelInteraction = Omit<Interaction, 'button'>;

export type Interactions = Record<string, Interaction | boolean>;
16 changes: 1 addition & 15 deletions packages/lib/src/interactions/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Vector2 } from 'three';

import type { Size } from '../vis/models';
import { getWorldFOV } from '../vis/utils';
import type { Interaction, ModifierKey } from './models';
import type { ModifierKey } from './models';

export function boundPointToFOV(
unboundedPoint: Vector2 | Vector3,
Expand Down Expand Up @@ -46,20 +46,6 @@ export function getRatioRespectingRectangle(
];
}

export function getDefaultInteractions(
keepRatio?: boolean
): Record<string, Interaction> {
return {
Pan: {},
Zoom: {},
XAxisZoom: { modifierKey: 'Alt', disabled: keepRatio },
YAxisZoom: { modifierKey: 'Shift', disabled: keepRatio },
SelectToZoom: { modifierKey: 'Control' },
XSelectToZoom: { modifierKey: ['Control', 'Alt'], disabled: keepRatio },
YSelectToZoom: { modifierKey: ['Control', 'Shift'], disabled: keepRatio },
};
}

export function getEnclosedRectangle(startPoint: Vector2, endPoint: Vector2) {
// center = start + (end - start) / 2
const center = endPoint
Expand Down
Loading

0 comments on commit 0b5ad5c

Please sign in to comment.