Skip to content

Commit

Permalink
review + vpt rotation
Browse files Browse the repository at this point in the history
  • Loading branch information
ShaMan123 committed Dec 24, 2023
1 parent 5dea8b8 commit 935f0c3
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 38 deletions.
60 changes: 40 additions & 20 deletions e2e/tests/controls/hit-regions/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,47 @@
import { expect, test } from '@playwright/test';
import setup from '../../../setup';
import { CanvasUtil } from '../../../utils/CanvasUtil';

setup();

test('Control hit regions', async ({ page }) => {
const canvasUtil = new CanvasUtil(page);
await canvasUtil.executeInBrowser((canvas) => {
const rect = canvas.getActiveObject();
const render = ({ x, y }: fabric.Point, fill: string) => {
const ctx = canvas.getTopContext();
ctx.fillStyle = fill;
ctx.beginPath();
ctx.arc(x, y, 1, 0, Math.PI * 2);
ctx.fill();
};
for (let y = 0; y <= canvas.height; y++) {
for (let x = 0; x < canvas.width; x++) {
const point = new fabric.Point(x, y);
rect._findTargetCorner(point, true) && render(point, 'indigo');
rect._findTargetCorner(point) && render(point, 'magenta');
for (const vpt of [
undefined,
{ angle: -30 },
{ scaleX: 2, scaleY: 0.5, width: 500 },
] as const) {
test(`Control hit regions with viewport of ${JSON.stringify(
vpt,
null,
2
)}`, async ({ page }) => {
const canvasUtil = new CanvasUtil(page);
await canvasUtil.executeInBrowser((canvas, vpt) => {
const rect = canvas.getActiveObject();
const center = rect.getCenterPoint();
vpt &&
canvas.setViewportTransform(
fabric.util.multiplyTransformMatrixArray([
fabric.util.createTranslateMatrix(center.x, center.y),
fabric.util.composeMatrix(vpt),
fabric.util.createTranslateMatrix(-center.x, -center.y),
])
);
vpt?.width && canvas.setDimensions({ width: vpt.width });
canvas.viewportCenterObject(rect);
const render = ({ x, y }: fabric.Point, fill: string) => {
const ctx = canvas.getTopContext();
ctx.fillStyle = fill;
ctx.beginPath();
ctx.arc(x, y, 1, 0, Math.PI * 2);
ctx.fill();
};
for (let y = 0; y <= canvas.height; y++) {
for (let x = 0; x < canvas.width; x++) {
const point = new fabric.Point(x, y);
rect._findTargetCorner(point, true) && render(point, 'indigo');
rect._findTargetCorner(point) && render(point, 'magenta');
}
}
}
}, vpt);
expect(await new CanvasUtil(page).screenshot()).toMatchSnapshot();
});
expect(await new CanvasUtil(page).screenshot()).toMatchSnapshot();
});
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
45 changes: 27 additions & 18 deletions src/shapes/Object/InteractiveObject.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { Point } from '../../Point';
import type { TCornerPoint, TDegree } from '../../typedefs';
import { FabricObject } from './Object';
import { degreesToRadians } from '../../util/misc/radiansDegreesConversion';
import {
degreesToRadians,
radiansToDegrees,
} from '../../util/misc/radiansDegreesConversion';
import type { TQrDecomposeOut } from '../../util/misc/matrix';
import {
calcDimensionsMatrix,
Expand Down Expand Up @@ -217,8 +220,11 @@ export class InteractiveFabricObject<
calcOCoords(): Record<string, TOCoord> {
const vpt = this.getViewportTransform();
const center = this.getCenterPoint();
const rotation = calcPlaneRotation(this.calcTransformMatrix());
const rotation = calcPlaneRotation(
multiplyTransformMatrices(vpt, this.calcTransformMatrix())
);

// calculate the viewport bbox size
const bboxTransform = multiplyTransformMatrixArray([
vpt,
createTranslateMatrix(center.x, center.y),
Expand All @@ -228,24 +234,26 @@ export class InteractiveFabricObject<
this.getCoords().map((p) => p.transform(bboxTransform))
);
const size = new Point(bbox.width, bbox.height).scalarAdd(this.padding * 2);
const translation = center.transform(vpt, true);

// calculate the transform used by controls
const translation = center.transform(vpt);
const t = multiplyTransformMatrices(
createTranslateMatrix(vpt[4] + translation.x, vpt[5] + translation.y),
createTranslateMatrix(translation.x, translation.y),
createRotationMatrix(rotation)
);

return Object.fromEntries(
Object.entries(this.controls).map(([key, control]) => {
const position = control.positionHandler(size, t, this, control);
return [
key,
// coords[key] are sometimes used as points. Those are points to which we add
// the property corner and touchCorner from `_calcCornerCoords`.
// don't remove this assign for an object spread.
Object.assign(position, this._calcCornerCoords(control, position)),
];
})
);
const controls: Record<string, TOCoord> = {};
this.forEachControl((control, key) => {
const position = control.positionHandler(size, t, this, control);

// coords[key] are sometimes used as points. Those are points to which we add
// the property corner and touchCorner from `_calcCornerCoords`.
// don't remove this assign for an object spread.
controls[key] = Object.assign(
position,
this._calcCornerCoords(control, position, radiansToDegrees(rotation))
);
});

// debug code
/*
Expand All @@ -260,6 +268,8 @@ export class InteractiveFabricObject<
});
} 50);
*/

return controls;
}

/**
Expand All @@ -269,8 +279,7 @@ export class InteractiveFabricObject<
* @todo evaluate simplification of code switching to circle interaction area at runtime
* @private
*/
private _calcCornerCoords(control: Control, position: Point) {
const angle = this.getTotalAngle();
private _calcCornerCoords(control: Control, position: Point, angle: TDegree) {
const corner = control.calcCornerCoords(
angle,
this.cornerSize,
Expand Down

0 comments on commit 935f0c3

Please sign in to comment.