-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
/
polyControl.ts
130 lines (118 loc) · 3.67 KB
/
polyControl.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import { Point } from '../Point';
import { Control } from './Control';
import type { TMat2D } from '../typedefs';
import type { Polyline } from '../shapes/Polyline';
import { multiplyTransformMatrices } from '../util/misc/matrix';
import type {
TModificationEvents,
TPointerEvent,
Transform,
TransformActionHandler,
} from '../EventTypeDefs';
import { wrapWithFireEvent } from './wrapWithFireEvent';
import { sendPointToPlane } from '../util';
const ACTION_NAME: TModificationEvents = 'modifyPoly';
type TTransformAnchor = Transform & { pointIndex: number };
/**
* This function locates the controls.
* It'll be used both for drawing and for interaction.
*/
export const createPolyPositionHandler = (pointIndex: number) => {
return function (dim: Point, finalMatrix: TMat2D, polyObject: Polyline) {
const { points, pathOffset } = polyObject;
return new Point(points[pointIndex])
.subtract(pathOffset)
.transform(
multiplyTransformMatrices(
polyObject.getViewportTransform(),
polyObject.calcTransformMatrix()
)
);
};
};
/**
* This function defines what the control does.
* It'll be called on every mouse move after a control has been clicked and is being dragged.
* The function receives as argument the mouse event, the current transform object
* and the current position in canvas coordinate `transform.target` is a reference to the
* current object being transformed.
*/
export const polyActionHandler = (
eventData: TPointerEvent,
transform: TTransformAnchor,
x: number,
y: number
) => {
const { target, pointIndex } = transform;
const poly = target as Polyline;
const mouseLocalPosition = sendPointToPlane(
new Point(x, y),
undefined,
poly.calcOwnMatrix()
);
poly.points[pointIndex] = mouseLocalPosition.add(poly.pathOffset);
poly.setDimensions();
return true;
};
/**
* Keep the polygon in the same position when we change its `width`/`height`/`top`/`left`.
*/
export const factoryPolyActionHandler = (
pointIndex: number,
fn: TransformActionHandler<TTransformAnchor>
) => {
return function (
eventData: TPointerEvent,
transform: Transform,
x: number,
y: number
) {
const poly = transform.target as Polyline,
anchorPoint = new Point(
poly.points[(pointIndex > 0 ? pointIndex : poly.points.length) - 1]
),
anchorPointInParentPlane = anchorPoint
.subtract(poly.pathOffset)
.transform(poly.calcOwnMatrix()),
actionPerformed = fn(eventData, { ...transform, pointIndex }, x, y);
const newAnchorPointInParentPlane = anchorPoint
.subtract(poly.pathOffset)
.transform(poly.calcOwnMatrix());
const diff = newAnchorPointInParentPlane.subtract(anchorPointInParentPlane);
poly.left -= diff.x;
poly.top -= diff.y;
return actionPerformed;
};
};
export const createPolyActionHandler = (pointIndex: number) =>
wrapWithFireEvent(
ACTION_NAME,
factoryPolyActionHandler(pointIndex, polyActionHandler)
);
export function createPolyControls(
poly: Polyline,
options?: Partial<Control>
): Record<string, Control>;
export function createPolyControls(
numOfControls: number,
options?: Partial<Control>
): Record<string, Control>;
export function createPolyControls(
arg0: number | Polyline,
options: Partial<Control> = {}
) {
const controls = {} as Record<string, Control>;
for (
let idx = 0;
idx < (typeof arg0 === 'number' ? arg0 : arg0.points.length);
idx++
) {
controls[`p${idx}`] = new Control({
actionName: ACTION_NAME,
positionHandler: createPolyPositionHandler(idx),
actionHandler: createPolyActionHandler(idx),
...options,
});
}
return controls;
}