-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(Controls) Add handlers to modify polygon points (#8556)
- Loading branch information
Showing
4 changed files
with
139 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
import { Point } from '../point.class'; | ||
import { Control } from './control.class'; | ||
import { TMat2D } from '../typedefs'; | ||
import { iMatrix } from '../constants'; | ||
import type { Polyline } from '../shapes/polyline.class'; | ||
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters