fabric
Version:
Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.
117 lines (111 loc) • 4.02 kB
text/typescript
import type { FabricObject, Point } from 'fabric';
import type { AligningGuidelines } from '..';
import type { LineProps } from '../typedefs';
import { getDistanceList } from './basic';
type CollectPointProps = {
target: FabricObject;
/** Operation points of the target element: top-left, bottom-left, top-right, bottom-right */
point: Point;
/** Position using diagonal points when resizing/scaling. */
diagonalPoint: 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;
/** When holding the centerKey (default is altKey), the shape will scale based on the center point, with the reference point being the center. */
isCenter: boolean;
/** tl、tr、br、bl、mt、mr、mb、ml */
corner: string;
};
export function collectVerticalPoint(
this: AligningGuidelines,
props: CollectPointProps,
): LineProps[] {
const {
target,
isScale,
isUniform,
corner,
point,
diagonalPoint,
list,
isCenter,
} = props;
const { dis, arr } = getDistanceList(point, list, 'x');
const margin = this.margin / this.canvas.getZoom();
if (dis > margin) return [];
let v = arr[arr.length - 1].x - point.x;
// tl bl ml
// If modifying on the left side, the size decreases; conversely, it increases.
const dirX = corner.includes('l') ? -1 : 1;
v *= dirX;
const { width, height, scaleX, scaleY } = target;
// Because when modifying through the center point, isUniform is always false, so skew does not need to be considered.
const dStrokeWidth = target.strokeUniform ? 0 : target.strokeWidth;
const scaleWidth = scaleX * width + dStrokeWidth;
const sx = (v + scaleWidth) / scaleWidth;
// When v equals -scaleWidth, sx equals 0.
if (sx == 0) return [];
if (isScale) {
target.set('scaleX', scaleX * sx);
if (isUniform) target.set('scaleY', scaleY * sx);
} else {
target.set('width', width * sx);
if (isUniform) target.set('height', height * sx);
}
if (isCenter) {
target.setRelativeXY(diagonalPoint, 'center', 'center');
} else {
const originArr = this.contraryOriginMap;
target.setRelativeXY(diagonalPoint, ...originArr[corner]);
}
target.setCoords();
return arr.map((target) => ({ origin: point, target }));
}
export function collectHorizontalPoint(
this: AligningGuidelines,
props: CollectPointProps,
): LineProps[] {
const {
target,
isScale,
isUniform,
corner,
point,
diagonalPoint,
list,
isCenter,
} = props;
const { dis, arr } = getDistanceList(point, list, 'y');
const margin = this.margin / this.canvas.getZoom();
if (dis > margin) return [];
let v = arr[arr.length - 1].y - point.y;
// tl mt tr
// If modifying on the top side, the size decreases; conversely, it increases.
const dirY = corner.includes('t') ? -1 : 1;
v *= dirY;
const { width, height, scaleX, scaleY } = target;
// Because when modifying through the center point, isUniform is always false, so skew does not need to be considered.
const dStrokeWidth = target.strokeUniform ? 0 : target.strokeWidth;
const scaleHeight = scaleY * height + dStrokeWidth;
const sy = (v + scaleHeight) / scaleHeight;
// When v equals -scaleHeight, sy equals 0.
if (sy == 0) return [];
if (isScale) {
target.set('scaleY', scaleY * sy);
if (isUniform) target.set('scaleX', scaleX * sy);
} else {
target.set('height', height * sy);
if (isUniform) target.set('width', width * sy);
}
if (isCenter) {
target.setRelativeXY(diagonalPoint, 'center', 'center');
} else {
const originArr = this.contraryOriginMap;
target.setRelativeXY(diagonalPoint, ...originArr[corner]);
}
target.setCoords();
return arr.map((target) => ({ origin: point, target }));
}