-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
/
polyControl.ts
135 lines (124 loc) · 3.98 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
131
132
133
134
135
import { Point } from '../Point';
import { Control } from './Control';
import { TMat2D } from '../typedefs';
import { iMatrix } from '../constants';
import type { Polyline } from '../shapes/Polyline';
import { multiplyTransformMatrices } from '../util/misc/matrix';
import {
TPointerEvent,
Transform,
TransformActionHandler,
} from '../EventTypeDefs';
import { getLocalPoint } from './util';
type TTransformAnchor = Transform & { pointIndex: number };
const getSize = (poly: Polyline) => {
return new Point(poly.width, poly.height);
};
/**
* This function locates the controls.
* It'll be used both for drawing and for interaction.
*/
const factoryPolyPositionHandler = (pointIndex: number) => {
return function (dim: Point, finalMatrix: TMat2D, polyObject: Polyline) {
const x = polyObject.points[pointIndex].x - polyObject.pathOffset.x,
y = polyObject.points[pointIndex].y - polyObject.pathOffset.y;
return new Point(x, y).transform(
multiplyTransformMatrices(
polyObject.canvas?.viewportTransform ?? iMatrix,
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.
*/
const polyActionHandler = (
eventData: TPointerEvent,
transform: TTransformAnchor,
x: number,
y: number
) => {
const poly = transform.target as Polyline,
pointIndex = transform.pointIndex,
mouseLocalPosition = getLocalPoint(transform, 'center', 'center', x, y),
polygonBaseSize = getSize(poly),
size = poly._getTransformedDimensions(),
sizeFactor = polygonBaseSize.divide(size),
adjustFlip = new Point(poly.flipX ? -1 : 1, poly.flipY ? -1 : 1);
const finalPointPosition = mouseLocalPosition
.multiply(adjustFlip)
.multiply(sizeFactor)
.add(poly.pathOffset);
poly.points[pointIndex] = finalPointPosition;
poly.setDimensions();
return true;
};
/**
* Keep the polygon in the same position when we change its `width`/`height`/`top`/`left`.
*/
const anchorWrapper = (
pointIndex: number,
fn: TransformActionHandler<TTransformAnchor>
) => {
return function (
eventData: TPointerEvent,
transform: Transform,
x: number,
y: number
) {
const poly = transform.target as Polyline,
anchorIndex = (pointIndex > 0 ? pointIndex : poly.points.length) - 1,
pointInParentPlane = new Point(
poly.points[anchorIndex].x - poly.pathOffset.x,
poly.points[anchorIndex].y - poly.pathOffset.y
).transform(poly.calcOwnMatrix()),
actionPerformed = fn(eventData, { ...transform, pointIndex }, x, y),
polygonBaseSize = getSize(poly),
adjustFlip = new Point(poly.flipX ? -1 : 1, poly.flipY ? -1 : 1);
const newPosition = new Point(
poly.points[anchorIndex].x,
poly.points[anchorIndex].y
)
.subtract(poly.pathOffset)
.divide(polygonBaseSize)
.multiply(adjustFlip);
poly.setPositionByOrigin(
pointInParentPlane,
newPosition.x + 0.5,
newPosition.y + 0.5
);
return actionPerformed;
};
};
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: 'modifyPoly',
positionHandler: factoryPolyPositionHandler(idx),
actionHandler: anchorWrapper(idx, polyActionHandler),
...options,
});
}
return controls;
}