Skip to content

Commit

Permalink
fix(AligningGuidelines): Align guidless changes aspect ratio on snapp…
Browse files Browse the repository at this point in the history
…ing when scaling
  • Loading branch information
zhe-he committed Sep 2, 2024
1 parent 6d120a0 commit c1054f1
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 21 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## [next]

- fix(AligningGuidelines): Align guidless changes aspect ratio on snapping when scaling [#10114](https://github.com/fabricjs/fabric.js/issues/10114)

## [6.4.1]

- fix(): Package.json had wrong path to types for extensions [#10115](https://github.com/fabricjs/fabric.js/pull/10115)
Expand Down
6 changes: 5 additions & 1 deletion extensions/aligning_guidelines/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,18 @@ export function initAligningGuidelines(
index -= 4;
}
let point = activeObject.getCoords()[index];
const uniformIsToggled = e.e[canvas.uniScaleKey!];
const isUniform =
(canvas.uniformScaling && !uniformIsToggled) ||
(!canvas.uniformScaling && uniformIsToggled);
for (const object of objects) {
const [rect, coords] = getCaCheMapValue(object);
const center = new Point(
rect.left + rect.width / 2,
rect.top + rect.height / 2,
);
const list = [...coords, center];
const props = { activeObject, point, list, isScale, index };
const props = { activeObject, point, list, isScale, isUniform, index };
const vLines = collectVerticalPoint(props);
const hLines = collectHorizontalPoint(props);
vLines.forEach((o) => {
Expand Down
80 changes: 60 additions & 20 deletions extensions/aligning_guidelines/util/collect-point.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,51 @@ import { getDistance } from './basic';

type CollectPointProps = {
activeObject: FabricObject;
/** Operation points of the target element: top-left, bottom-left, top-right, bottom-right */
point: Point;
/** Set of points to consider for alignment: [tl, tr, br, bl, center] */
list: Point[];
/** Change the zoom or change the size, determine by whether e.transform.action starts with the string "scale" */
isScale: boolean;
/** Whether to change uniformly is determined by canvas.uniformScaling and canvas.uniScaleKey. */
isUniform: boolean;
/** Which specific point to operate on, 0-3 correspond to top-left, top-right, bottom-right, bottom-left */
index: number;
};
const originXArr: TOriginX[] = ['left', 'center', 'right'];
const originYArr: TOriginY[] = ['top', 'center', 'bottom'];

export function collectVerticalPoint(props: CollectPointProps) {
const aligningLineMargin = aligningLineConfig.margin;
const { activeObject, isScale, index, point, list } = props;
const { activeObject, isScale, isUniform, index, point, list } = props;
const { dis, arr } = getDistanceList(point, list, 'x');
const margin = aligningLineMargin / (activeObject.canvas?.getZoom() ?? 1);
if (dis > margin) return [];
let v = arr[arr.length - 1].x - point.x;
const dir = index == 0 || index == 3 ? -1 : 1;
v *= dir;
// To the left or to the right?
const dirX = index == 0 || index == 3 ? -1 : 1;
// To the top or to the bottom?
const dirY = index < 2 ? -1 : 1;
v *= dirX;

const { width, scaleX, left } = activeObject;
const { width, height, scaleX, scaleY, left, top } = activeObject;
const dim = activeObject._getTransformedDimensions();
const sx = (v + dim.x) / dim.x;
if (isScale) activeObject.set('scaleX', scaleX * sx);
else activeObject.set('width', width * sx);
const dArr = [0, (v / 2) * dir, v * dir];
if (dir < 0) dArr.reverse();
const d = dArr[originXArr.indexOf(activeObject.originX)];
activeObject.set('left', left + d);
if (isScale) {
activeObject.set('scaleX', scaleX * sx);
if (isUniform) activeObject.set('scaleY', scaleY * sx);
} else {
activeObject.set('width', width * sx);
if (isUniform) activeObject.set('height', height * sx);
}
const dx = getDisByOriginX(activeObject, v * dirX);
if (isUniform) {
const h = activeObject._getTransformedDimensions().y - dim.y;
const dy = getDisByOriginY(activeObject, h * dirY);
activeObject.set('top', top + dy);
}
activeObject.set('left', left + dx);

activeObject.setCoords();
return arr.map((item) => ({
x: item.x,
Expand All @@ -41,23 +59,34 @@ export function collectVerticalPoint(props: CollectPointProps) {

export function collectHorizontalPoint(props: CollectPointProps) {
const aligningLineMargin = aligningLineConfig.margin;
const { activeObject, isScale, index, point, list } = props;
const { activeObject, isScale, isUniform, index, point, list } = props;
const { dis, arr } = getDistanceList(point, list, 'y');
const margin = aligningLineMargin / (activeObject.canvas?.getZoom() ?? 1);
if (dis > margin) return [];
let v = arr[arr.length - 1].y - point.y;
const dir = index < 2 ? -1 : 1;
v *= dir;
// To the left or to the right?
const dirX = index == 0 || index == 3 ? -1 : 1;
// To the top or to the bottom?
const dirY = index < 2 ? -1 : 1;
v *= dirY;

const { height, scaleY, top } = activeObject;
const { width, height, scaleX, scaleY, left, top } = activeObject;
const dim = activeObject._getTransformedDimensions();
const sy = (v + dim.y) / dim.y;
if (isScale) activeObject.set('scaleY', scaleY * sy);
else activeObject.set('height', height * sy);
const dArr = [0, (v / 2) * dir, v * dir];
if (dir < 0) dArr.reverse();
const d = dArr[originYArr.indexOf(activeObject.originY)];
activeObject.set('top', top + d);
if (isScale) {
activeObject.set('scaleY', scaleY * sy);
if (isUniform) activeObject.set('scaleX', scaleX * sy);
} else {
activeObject.set('height', height * sy);
if (isUniform) activeObject.set('width', width * sy);
}
const dy = getDisByOriginY(activeObject, v * dirY);
if (isUniform) {
const w = activeObject._getTransformedDimensions().x - dim.x;
const dx = getDisByOriginX(activeObject, w * dirX);
activeObject.set('left', left + dx);
}
activeObject.set('top', top + dy);
activeObject.setCoords();
return arr.map((item) => ({
y: item.y,
Expand All @@ -81,3 +110,14 @@ function getDistanceList(point: Point, list: Point[], type: 'x' | 'y') {
}
return { dis, arr };
}

function getDisByOriginX(target: FabricObject, v: number) {
const dArr = [0, v / 2, v];
if (v < 0) dArr.reverse();
return dArr[originXArr.indexOf(target.originX)];
}
function getDisByOriginY(target: FabricObject, v: number) {
const dArr = [0, v / 2, v];
if (v < 0) dArr.reverse();
return dArr[originYArr.indexOf(target.originY)];
}

0 comments on commit c1054f1

Please sign in to comment.