Skip to content

Commit be42243

Browse files
authored
Merge pull request #828 from renato-bohler/touch-events
Adds support for touch events, enabling touch dragging the canvas
2 parents 66184bd + 1bdc6c7 commit be42243

File tree

9 files changed

+122
-23
lines changed

9 files changed

+122
-23
lines changed

diagrams-demo-gallery/demos/demo-alternative-linking/DefaultState.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { MouseEvent } from 'react';
1+
import { MouseEvent, TouchEvent } from 'react';
22
import {
33
SelectingState,
44
State,
@@ -45,6 +45,16 @@ export class DefaultState extends State<DiagramEngine> {
4545
})
4646
);
4747

48+
// touch drags the canvas
49+
this.registerAction(
50+
new Action({
51+
type: InputType.TOUCH_START,
52+
fire: (event: ActionEvent<TouchEvent>) => {
53+
this.transitionWithEvent(new DragCanvasState(), event);
54+
}
55+
})
56+
);
57+
4858
this.registerAction(
4959
new Action({
5060
type: InputType.MOUSE_UP,

packages/react-canvas-core/src/core-actions/Action.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { MouseEvent, KeyboardEvent, WheelEvent, SyntheticEvent } from 'react';
1+
import { MouseEvent, KeyboardEvent, WheelEvent, TouchEvent, SyntheticEvent } from 'react';
22
import { Toolkit } from '../Toolkit';
33
import { CanvasEngine } from '../CanvasEngine';
44
import { BaseModel } from '../core-models/BaseModel';
@@ -9,7 +9,10 @@ export enum InputType {
99
MOUSE_MOVE = 'mouse-move',
1010
MOUSE_WHEEL = 'mouse-wheel',
1111
KEY_DOWN = 'key-down',
12-
KEY_UP = 'key-up'
12+
KEY_UP = 'key-up',
13+
TOUCH_START = 'touch-start',
14+
TOUCH_END = 'touch-end',
15+
TOUCH_MOVE = 'touch-move'
1316
}
1417

1518
export interface Mapping {
@@ -19,6 +22,9 @@ export interface Mapping {
1922
[InputType.MOUSE_WHEEL]: WheelEvent;
2023
[InputType.KEY_DOWN]: KeyboardEvent;
2124
[InputType.KEY_UP]: KeyboardEvent;
25+
[InputType.TOUCH_START]: TouchEvent;
26+
[InputType.TOUCH_END]: TouchEvent;
27+
[InputType.TOUCH_MOVE]: TouchEvent;
2228
}
2329

2430
export interface ActionEvent<Event extends SyntheticEvent = SyntheticEvent, Model extends BaseModel = BaseModel> {

packages/react-canvas-core/src/core-actions/ActionEventBus.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,14 @@ export class ActionEventBus {
6363
return this.getActionsForType(InputType.MOUSE_MOVE);
6464
} else if (event.type === 'wheel') {
6565
return this.getActionsForType(InputType.MOUSE_WHEEL);
66+
} else if (event.type === 'touchstart') {
67+
return this.getActionsForType(InputType.TOUCH_START);
68+
} else if (event.type === 'touchend') {
69+
return this.getActionsForType(InputType.TOUCH_END);
70+
} else if (event.type === 'touchmove') {
71+
return this.getActionsForType(InputType.TOUCH_MOVE);
6672
}
73+
6774
return [];
6875
}
6976

packages/react-canvas-core/src/core-state/AbstractDisplacementState.ts

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export interface AbstractDisplacementStateEvent {
77
displacementY: number;
88
virtualDisplacementX: number;
99
virtualDisplacementY: number;
10-
event: React.MouseEvent;
10+
event: React.MouseEvent | React.TouchEvent;
1111
}
1212

1313
export abstract class AbstractDisplacementState<E extends CanvasEngine = CanvasEngine> extends State<E> {
@@ -22,11 +22,8 @@ export abstract class AbstractDisplacementState<E extends CanvasEngine = CanvasE
2222
new Action({
2323
type: InputType.MOUSE_DOWN,
2424
fire: (actionEvent: ActionEvent<React.MouseEvent>) => {
25-
this.initialX = actionEvent.event.clientX;
26-
this.initialY = actionEvent.event.clientY;
27-
const rel = this.engine.getRelativePoint(actionEvent.event.clientX, actionEvent.event.clientY);
28-
this.initialXRelative = rel.x;
29-
this.initialYRelative = rel.y;
25+
const { clientX, clientY } = actionEvent.event;
26+
this.handleMoveStart(clientX, clientY);
3027
}
3128
})
3229
);
@@ -44,25 +41,65 @@ export abstract class AbstractDisplacementState<E extends CanvasEngine = CanvasE
4441
return;
4542
}
4643

47-
this.fireMouseMoved({
48-
displacementX: event.clientX - this.initialX,
49-
displacementY: event.clientY - this.initialY,
50-
virtualDisplacementX: (event.clientX - this.initialX) / (this.engine.getModel().getZoomLevel() / 100.0),
51-
virtualDisplacementY: (event.clientY - this.initialY) / (this.engine.getModel().getZoomLevel() / 100.0),
52-
event: event
53-
});
44+
const { clientX, clientY } = event;
45+
this.handleMove(clientX, clientY, event);
5446
}
5547
})
5648
);
5749
this.registerAction(
5850
new Action({
5951
type: InputType.MOUSE_UP,
60-
fire: (event: ActionEvent<React.MouseEvent>) => {
61-
// when the mouse if up, we eject this state
62-
this.eject();
52+
fire: () => this.handleMoveEnd()
53+
})
54+
);
55+
56+
this.registerAction(
57+
new Action({
58+
type: InputType.TOUCH_START,
59+
fire: (actionEvent: ActionEvent<React.TouchEvent>) => {
60+
const { clientX, clientY } = actionEvent.event.touches[0];
61+
this.handleMoveStart(clientX, clientY);
62+
}
63+
})
64+
);
65+
this.registerAction(
66+
new Action({
67+
type: InputType.TOUCH_MOVE,
68+
fire: (actionEvent: ActionEvent<React.TouchEvent>) => {
69+
const { event } = actionEvent;
70+
const { clientX, clientY } = event.touches[0];
71+
this.handleMove(clientX, clientY, event);
6372
}
6473
})
6574
);
75+
this.registerAction(
76+
new Action({
77+
type: InputType.TOUCH_END,
78+
fire: () => this.handleMoveEnd()
79+
})
80+
);
81+
}
82+
83+
protected handleMoveStart(x: number, y: number): void {
84+
this.initialX = x;
85+
this.initialY = y;
86+
const rel = this.engine.getRelativePoint(x, y);
87+
this.initialXRelative = rel.x;
88+
this.initialYRelative = rel.y;
89+
}
90+
91+
protected handleMove(x: number, y: number, event: React.MouseEvent | React.TouchEvent): void {
92+
this.fireMouseMoved({
93+
displacementX: x - this.initialX,
94+
displacementY: y - this.initialY,
95+
virtualDisplacementX: (x - this.initialX) / (this.engine.getModel().getZoomLevel() / 100.0),
96+
virtualDisplacementY: (y - this.initialY) / (this.engine.getModel().getZoomLevel() / 100.0),
97+
event
98+
});
99+
}
100+
101+
protected handleMoveEnd(): void {
102+
this.eject();
66103
}
67104

68105
abstract fireMouseMoved(event: AbstractDisplacementStateEvent);

packages/react-canvas-core/src/entities/canvas/CanvasWidget.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,15 @@ export class CanvasWidget extends React.Component<DiagramProps> {
9090
}}
9191
onMouseMove={(event) => {
9292
this.props.engine.getActionEventBus().fireAction({ event });
93+
}}
94+
onTouchStart={(event) => {
95+
this.props.engine.getActionEventBus().fireAction({ event });
96+
}}
97+
onTouchEnd={(event) => {
98+
this.props.engine.getActionEventBus().fireAction({ event });
99+
}}
100+
onTouchMove={(event) => {
101+
this.props.engine.getActionEventBus().fireAction({ event });
93102
}}>
94103
{model.getLayers().map((layer) => {
95104
return (

packages/react-canvas-core/src/entities/selection/SelectionBoxWidget.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ namespace S {
1616
export class SelectionBoxWidget extends React.Component<SelectionBoxWidgetProps> {
1717
render() {
1818
const { rect } = this.props;
19+
20+
if (!rect) return null;
21+
1922
return (
2023
<S.Container
2124
style={{

packages/react-canvas-core/src/states/DefaultState.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { State } from '../core-state/State';
22
import { Action, ActionEvent, InputType } from '../core-actions/Action';
3-
import { MouseEvent } from 'react';
3+
import { MouseEvent, TouchEvent } from 'react';
44
import { DragCanvasState } from './DragCanvasState';
55
import { SelectingState } from './SelectingState';
66
import { MoveItemsState } from './MoveItemsState';
@@ -28,5 +28,15 @@ export class DefaultState extends State {
2828
}
2929
})
3030
);
31+
32+
// touch drags the canvas
33+
this.registerAction(
34+
new Action({
35+
type: InputType.TOUCH_START,
36+
fire: (event: ActionEvent<TouchEvent>) => {
37+
this.transitionWithEvent(new DragCanvasState(), event);
38+
}
39+
})
40+
);
3141
}
3242
}

packages/react-canvas-core/src/states/SelectionBoxState.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
import { MouseEvent, TouchEvent } from 'react';
12
import { AbstractDisplacementState, AbstractDisplacementStateEvent } from '../core-state/AbstractDisplacementState';
23
import { State } from '../core-state/State';
34
import { SelectionLayerModel } from '../entities/selection/SelectionLayerModel';
4-
import { Rectangle } from '@projectstorm/geometry';
5+
import { Point, Rectangle } from '@projectstorm/geometry';
56
import { ModelGeometryInterface } from '../core/ModelGeometryInterface';
67

78
export class SelectionBoxState extends AbstractDisplacementState {
@@ -26,7 +27,13 @@ export class SelectionBoxState extends AbstractDisplacementState {
2627
}
2728

2829
getBoxDimensions(event: AbstractDisplacementStateEvent): ClientRect {
29-
const rel = this.engine.getRelativePoint(event.event.clientX, event.event.clientY);
30+
let rel: Point;
31+
if (event.event instanceof MouseEvent) {
32+
rel = this.engine.getRelativePoint(event.event.clientX, event.event.clientY);
33+
} else if (event.event instanceof TouchEvent) {
34+
const touch = event.event.touches[0];
35+
rel = this.engine.getRelativePoint(touch.clientX, touch.clientY);
36+
}
3037

3138
return {
3239
left: rel.x > this.initialXRelative ? this.initialXRelative : rel.x,

packages/react-diagrams-core/src/states/DefaultDiagramState.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { MouseEvent } from 'react';
1+
import { MouseEvent, TouchEvent } from 'react';
22
import {
33
SelectingState,
44
State,
@@ -48,5 +48,15 @@ export class DefaultDiagramState extends State<DiagramEngine> {
4848
}
4949
})
5050
);
51+
52+
// touch drags the canvas
53+
this.registerAction(
54+
new Action({
55+
type: InputType.TOUCH_START,
56+
fire: (event: ActionEvent<TouchEvent>) => {
57+
this.transitionWithEvent(this.dragCanvas, event);
58+
}
59+
})
60+
);
5161
}
5262
}

0 commit comments

Comments
 (0)