-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
/
polyControl.ts
136 lines (123 loc) · 4.05 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
136
import { Point } from '../Point';
import { Control } from './Control';
import type { TMat2D } from '../typedefs';
import { CENTER, iMatrix } from '../constants';
import type { Polyline } from '../shapes/Polyline';
import { multiplyTransformMatrices } from '../util/misc/matrix';
import type {
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.
*/
export const createPolyPositionHandler = (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.
*/
export 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`.
*/
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),
adjustFlip = new Point(poly.flipX ? -1 : 1, poly.flipY ? -1 : 1);
const newPositionNormalized = anchorPoint
.subtract(poly.pathOffset)
.divide(poly._getNonTransformedDimensions())
.multiply(adjustFlip);
poly.setPositionByOrigin(
anchorPointInParentPlane,
newPositionNormalized.x + 0.5,
newPositionNormalized.y + 0.5
);
return actionPerformed;
};
};
export const createPolyActionHandler = (pointIndex: number) =>
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: 'modifyPoly',
positionHandler: createPolyPositionHandler(idx),
actionHandler: createPolyActionHandler(idx),
...options,
});
}
return controls;
}