mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
feat: image support (#4011)
Co-authored-by: Emil Atanasov <heitara@gmail.com> Co-authored-by: Aakansha Doshi <aakansha1216@gmail.com>
This commit is contained in:
parent
0f0244224d
commit
163ad1f4c4
85 changed files with 3536 additions and 618 deletions
|
@ -47,9 +47,9 @@ export const transformElements = (
|
|||
transformHandleType: MaybeTransformHandleType,
|
||||
selectedElements: readonly NonDeletedExcalidrawElement[],
|
||||
resizeArrowDirection: "origin" | "end",
|
||||
isRotateWithDiscreteAngle: boolean,
|
||||
isResizeCenterPoint: boolean,
|
||||
shouldKeepSidesRatio: boolean,
|
||||
shouldRotateWithDiscreteAngle: boolean,
|
||||
shouldResizeFromCenter: boolean,
|
||||
shouldMaintainAspectRatio: boolean,
|
||||
pointerX: number,
|
||||
pointerY: number,
|
||||
centerX: number,
|
||||
|
@ -62,7 +62,7 @@ export const transformElements = (
|
|||
element,
|
||||
pointerX,
|
||||
pointerY,
|
||||
isRotateWithDiscreteAngle,
|
||||
shouldRotateWithDiscreteAngle,
|
||||
);
|
||||
updateBoundElements(element);
|
||||
} else if (
|
||||
|
@ -76,7 +76,7 @@ export const transformElements = (
|
|||
reshapeSingleTwoPointElement(
|
||||
element,
|
||||
resizeArrowDirection,
|
||||
isRotateWithDiscreteAngle,
|
||||
shouldRotateWithDiscreteAngle,
|
||||
pointerX,
|
||||
pointerY,
|
||||
);
|
||||
|
@ -90,7 +90,7 @@ export const transformElements = (
|
|||
resizeSingleTextElement(
|
||||
element,
|
||||
transformHandleType,
|
||||
isResizeCenterPoint,
|
||||
shouldResizeFromCenter,
|
||||
pointerX,
|
||||
pointerY,
|
||||
);
|
||||
|
@ -98,10 +98,10 @@ export const transformElements = (
|
|||
} else if (transformHandleType) {
|
||||
resizeSingleElement(
|
||||
pointerDownState.originalElements.get(element.id) as typeof element,
|
||||
shouldKeepSidesRatio,
|
||||
shouldMaintainAspectRatio,
|
||||
element,
|
||||
transformHandleType,
|
||||
isResizeCenterPoint,
|
||||
shouldResizeFromCenter,
|
||||
pointerX,
|
||||
pointerY,
|
||||
);
|
||||
|
@ -115,7 +115,7 @@ export const transformElements = (
|
|||
selectedElements,
|
||||
pointerX,
|
||||
pointerY,
|
||||
isRotateWithDiscreteAngle,
|
||||
shouldRotateWithDiscreteAngle,
|
||||
centerX,
|
||||
centerY,
|
||||
);
|
||||
|
@ -142,13 +142,13 @@ const rotateSingleElement = (
|
|||
element: NonDeletedExcalidrawElement,
|
||||
pointerX: number,
|
||||
pointerY: number,
|
||||
isRotateWithDiscreteAngle: boolean,
|
||||
shouldRotateWithDiscreteAngle: boolean,
|
||||
) => {
|
||||
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
||||
const cx = (x1 + x2) / 2;
|
||||
const cy = (y1 + y2) / 2;
|
||||
let angle = (5 * Math.PI) / 2 + Math.atan2(pointerY - cy, pointerX - cx);
|
||||
if (isRotateWithDiscreteAngle) {
|
||||
if (shouldRotateWithDiscreteAngle) {
|
||||
angle += SHIFT_LOCKING_ANGLE / 2;
|
||||
angle -= angle % SHIFT_LOCKING_ANGLE;
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ const getPerfectElementSizeWithRotation = (
|
|||
export const reshapeSingleTwoPointElement = (
|
||||
element: NonDeleted<ExcalidrawLinearElement>,
|
||||
resizeArrowDirection: "origin" | "end",
|
||||
isRotateWithDiscreteAngle: boolean,
|
||||
shouldRotateWithDiscreteAngle: boolean,
|
||||
pointerX: number,
|
||||
pointerY: number,
|
||||
) => {
|
||||
|
@ -212,7 +212,7 @@ export const reshapeSingleTwoPointElement = (
|
|||
element.x + element.points[1][0] - rotatedX,
|
||||
element.y + element.points[1][1] - rotatedY,
|
||||
];
|
||||
if (isRotateWithDiscreteAngle) {
|
||||
if (shouldRotateWithDiscreteAngle) {
|
||||
[width, height] = getPerfectElementSizeWithRotation(
|
||||
element.type,
|
||||
width,
|
||||
|
@ -281,28 +281,28 @@ const measureFontSizeFromWH = (
|
|||
|
||||
const getSidesForTransformHandle = (
|
||||
transformHandleType: TransformHandleType,
|
||||
isResizeFromCenter: boolean,
|
||||
shouldResizeFromCenter: boolean,
|
||||
) => {
|
||||
return {
|
||||
n:
|
||||
/^(n|ne|nw)$/.test(transformHandleType) ||
|
||||
(isResizeFromCenter && /^(s|se|sw)$/.test(transformHandleType)),
|
||||
(shouldResizeFromCenter && /^(s|se|sw)$/.test(transformHandleType)),
|
||||
s:
|
||||
/^(s|se|sw)$/.test(transformHandleType) ||
|
||||
(isResizeFromCenter && /^(n|ne|nw)$/.test(transformHandleType)),
|
||||
(shouldResizeFromCenter && /^(n|ne|nw)$/.test(transformHandleType)),
|
||||
w:
|
||||
/^(w|nw|sw)$/.test(transformHandleType) ||
|
||||
(isResizeFromCenter && /^(e|ne|se)$/.test(transformHandleType)),
|
||||
(shouldResizeFromCenter && /^(e|ne|se)$/.test(transformHandleType)),
|
||||
e:
|
||||
/^(e|ne|se)$/.test(transformHandleType) ||
|
||||
(isResizeFromCenter && /^(w|nw|sw)$/.test(transformHandleType)),
|
||||
(shouldResizeFromCenter && /^(w|nw|sw)$/.test(transformHandleType)),
|
||||
};
|
||||
};
|
||||
|
||||
const resizeSingleTextElement = (
|
||||
element: NonDeleted<ExcalidrawTextElement>,
|
||||
transformHandleType: "nw" | "ne" | "sw" | "se",
|
||||
isResizeFromCenter: boolean,
|
||||
shouldResizeFromCenter: boolean,
|
||||
pointerX: number,
|
||||
pointerY: number,
|
||||
) => {
|
||||
|
@ -361,7 +361,7 @@ const resizeSingleTextElement = (
|
|||
const deltaX2 = (x2 - nextX2) / 2;
|
||||
const deltaY2 = (y2 - nextY2) / 2;
|
||||
const [nextElementX, nextElementY] = adjustXYWithRotation(
|
||||
getSidesForTransformHandle(transformHandleType, isResizeFromCenter),
|
||||
getSidesForTransformHandle(transformHandleType, shouldResizeFromCenter),
|
||||
element.x,
|
||||
element.y,
|
||||
element.angle,
|
||||
|
@ -383,10 +383,10 @@ const resizeSingleTextElement = (
|
|||
|
||||
export const resizeSingleElement = (
|
||||
stateAtResizeStart: NonDeletedExcalidrawElement,
|
||||
shouldKeepSidesRatio: boolean,
|
||||
shouldMaintainAspectRatio: boolean,
|
||||
element: NonDeletedExcalidrawElement,
|
||||
transformHandleDirection: TransformHandleDirection,
|
||||
isResizeFromCenter: boolean,
|
||||
shouldResizeFromCenter: boolean,
|
||||
pointerX: number,
|
||||
pointerY: number,
|
||||
) => {
|
||||
|
@ -444,13 +444,13 @@ export const resizeSingleElement = (
|
|||
let eleNewHeight = element.height * scaleY;
|
||||
|
||||
// adjust dimensions for resizing from center
|
||||
if (isResizeFromCenter) {
|
||||
if (shouldResizeFromCenter) {
|
||||
eleNewWidth = 2 * eleNewWidth - eleInitialWidth;
|
||||
eleNewHeight = 2 * eleNewHeight - eleInitialHeight;
|
||||
}
|
||||
|
||||
// adjust dimensions to keep sides ratio
|
||||
if (shouldKeepSidesRatio) {
|
||||
if (shouldMaintainAspectRatio) {
|
||||
const widthRatio = Math.abs(eleNewWidth) / eleInitialWidth;
|
||||
const heightRatio = Math.abs(eleNewHeight) / eleInitialHeight;
|
||||
if (transformHandleDirection.length === 1) {
|
||||
|
@ -495,7 +495,7 @@ export const resizeSingleElement = (
|
|||
}
|
||||
|
||||
// Keeps opposite handle fixed during resize
|
||||
if (shouldKeepSidesRatio) {
|
||||
if (shouldMaintainAspectRatio) {
|
||||
if (["s", "n"].includes(transformHandleDirection)) {
|
||||
newTopLeft[0] = startCenter[0] - newBoundsWidth / 2;
|
||||
}
|
||||
|
@ -523,7 +523,7 @@ export const resizeSingleElement = (
|
|||
}
|
||||
}
|
||||
|
||||
if (isResizeFromCenter) {
|
||||
if (shouldResizeFromCenter) {
|
||||
newTopLeft[0] = startCenter[0] - Math.abs(newBoundsWidth) / 2;
|
||||
newTopLeft[1] = startCenter[1] - Math.abs(newBoundsHeight) / 2;
|
||||
}
|
||||
|
@ -558,6 +558,18 @@ export const resizeSingleElement = (
|
|||
...rescaledPoints,
|
||||
};
|
||||
|
||||
if ("scale" in element && "scale" in stateAtResizeStart) {
|
||||
mutateElement(element, {
|
||||
scale: [
|
||||
// defaulting because scaleX/Y can be 0/-0
|
||||
(Math.sign(scaleX) || stateAtResizeStart.scale[0]) *
|
||||
stateAtResizeStart.scale[0],
|
||||
(Math.sign(scaleY) || stateAtResizeStart.scale[1]) *
|
||||
stateAtResizeStart.scale[1],
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
resizedElement.width !== 0 &&
|
||||
resizedElement.height !== 0 &&
|
||||
|
@ -692,13 +704,13 @@ const rotateMultipleElements = (
|
|||
elements: readonly NonDeletedExcalidrawElement[],
|
||||
pointerX: number,
|
||||
pointerY: number,
|
||||
isRotateWithDiscreteAngle: boolean,
|
||||
shouldRotateWithDiscreteAngle: boolean,
|
||||
centerX: number,
|
||||
centerY: number,
|
||||
) => {
|
||||
let centerAngle =
|
||||
(5 * Math.PI) / 2 + Math.atan2(pointerY - centerY, pointerX - centerX);
|
||||
if (isRotateWithDiscreteAngle) {
|
||||
if (shouldRotateWithDiscreteAngle) {
|
||||
centerAngle += SHIFT_LOCKING_ANGLE / 2;
|
||||
centerAngle -= centerAngle % SHIFT_LOCKING_ANGLE;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue