Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
2ae4236
feat(PolyControl): modify the shape of a poly
luizzappa Jan 1, 2023
1d51089
refactor(util): export normalizePoint
luizzappa Jan 1, 2023
95e713b
feat(actions): expose PolyControl in fabric.controlsUtils
luizzappa Jan 1, 2023
42c1258
prettier
luizzappa Jan 1, 2023
612a2dd
changelog
luizzappa Jan 1, 2023
fd4c5d2
refactor(): rename PolyControl filename
luizzappa Jan 2, 2023
b8bfa8d
refactor(): Point#transform instead of the transformPoint function
luizzappa Jan 2, 2023
3ce7430
refactor(): use iMatrix constant
luizzappa Jan 2, 2023
5d2c208
docs(): fix typo and styling
luizzappa Jan 2, 2023
eafa394
refactor(): introduce getSize method
luizzappa Jan 3, 2023
b8bcb97
refactor(): getLocalPoint instead of normalizePoint
luizzappa Jan 3, 2023
e527acc
refactor(PolyControls#createPolyControls): change signature to receiv…
luizzappa Jan 3, 2023
f1ab52c
fix(PolyControls): poly with flip
luizzappa Jan 3, 2023
e16e64f
minors
ShaMan123 Jan 3, 2023
5260d90
Merge branch 'master' into pr/8556
ShaMan123 Jan 3, 2023
d9195a4
rm `anchorIndex`
ShaMan123 Jan 3, 2023
c6afd8e
`createPolyControls` signature overload
ShaMan123 Jan 3, 2023
b806fb9
refactor(polyControl): control interface instead of subclass
luizzappa Jan 6, 2023
e6ba30c
remove skew support
luizzappa Jan 6, 2023
0ec0431
Merge branch 'master' into pr/8556
ShaMan123 Jan 6, 2023
5464e70
restore signature overloads
ShaMan123 Jan 6, 2023
60b31fe
expose
ShaMan123 Jan 6, 2023
48dcad2
restore action name
ShaMan123 Jan 6, 2023
a6fc8dd
fix(): under group
ShaMan123 Jan 6, 2023
5b7f189
Merge branch 'master' into poly-custom-control
asturur Jan 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## [next]

- feat(PolyControl): modify the shape of a poly with control points [#8556](https://github.com/fabricjs/fabric.js/pull/8556)
- BREAKING: remove Object.stateful and Object.statefulCache [#8573](https://github.com/fabricjs/fabric.js/pull/8573)
- fix(IText): refactor clearing context top logic of itext to align with brush pattern, using the canvas rendering cycle in order to guard from edge cases #8560
- fix(Canvas): `_initRetinaScaling` initializaing the scaling regardless of settings in Canvas. [#8565](https://github.com/fabricjs/fabric.js/pull/8565)
Expand Down
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ import {
renderSquareControl,
} from './src/controls/controls.render';
import { dragHandler } from './src/controls/drag';
import { createPolyControls } from './src/controls/polyControl';
import {
rotationStyleHandler,
rotationWithSnapping,
Expand Down Expand Up @@ -306,6 +307,7 @@ const controlsUtils = {
skewHandlerX,
skewHandlerY,
dragHandler,
createPolyControls,
scaleOrSkewActionName,
rotationStyleHandler,
wrapWithFixedAnchor,
Expand Down
135 changes: 135 additions & 0 deletions src/controls/polyControl.ts
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;
}
2 changes: 1 addition & 1 deletion src/shapes/polyline.class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ export class Polyline extends FabricObject {
*
* @private
*/
_getTransformedDimensions(options: any) {
_getTransformedDimensions(options?: any) {
return this.exactBoundingBox
? super._getTransformedDimensions({
...(options || {}),
Expand Down