Last active
May 13, 2022 06:30
-
-
Save steveruizok/3f8033ea9e9e655633dc8d21d78e5686 to your computer and use it in GitHub Desktop.
Resizing boxes by corner.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface Box { | |
x: number | |
y: number | |
w: number | |
h: number | |
maxX: number | |
maxY: number | |
} | |
interface BoxWithId extends Box { | |
id: string | |
} | |
export function getCornerResizer(boxes: BoxWithId[], corner: number) { | |
// Get bounding box for all boxes | |
let { x: minX, y: minY, maxX, maxY } = { ...boxes[0] } | |
for (let box of boxes) { | |
minX = Math.min(minX, box.x) | |
minY = Math.min(minY, box.y) | |
maxX = Math.max(maxX, box.maxX) | |
maxY = Math.max(maxY, box.maxY) | |
} | |
const bounds = { | |
x: minX, | |
y: minY, | |
maxX, | |
maxY, | |
w: maxX - minX, | |
h: maxY - minY | |
} | |
// Get normalized boxes, where each property is a normal of the bounding box | |
// For example, an x: .5, y: .75 would be at half of the bounds width, 3/4 its height. | |
const normalizedBoxes: Record<string, Box> = {} | |
for (let box of boxes) { | |
normalizedBoxes[box.id] = { | |
x: (box.x - minX) / bounds.w, | |
y: (box.y - minY) / bounds.h, | |
maxX: 1 - (box.maxX - minX) / bounds.w, | |
maxY: 1 - (box.maxY - minY) / bounds.h, | |
w: box.w / bounds.w, | |
h: box.h / bounds.h | |
} | |
} | |
const aspectRatio = bounds.w / bounds.h | |
let flipX: boolean, | |
flipY: boolean, | |
isRightCorner: boolean, | |
isTopCorner: boolean | |
// Resizing function | |
return (point: { x: number; y: number }, lockAspect = false) => { | |
isTopCorner = corner < 2 // 0TL or 1TR | |
isRightCorner = corner % 3 > 0 // 1TR or 2BR | |
// Update dragging corners | |
if (isTopCorner) minY = point.y | |
else maxY = point.y | |
if (isRightCorner) maxX = point.x | |
else minX = point.x | |
// Are we flipped? | |
flipX = maxX < minX | |
flipY = maxY < minY | |
bounds.w = Math.abs(maxX - minX) | |
bounds.h = Math.abs(maxY - minY) | |
if (lockAspect) { | |
if (bounds.w / bounds.h > aspectRatio) { | |
// Scale bounds height by aspect ratio | |
// and move points to fit new height | |
bounds.h = bounds.w / aspectRatio | |
if (isTopCorner) { | |
minY = flipY ? maxY + bounds.h : maxY - bounds.h | |
} else { | |
maxY = flipY ? minY - bounds.h : minY + bounds.h | |
} | |
} else { | |
// Scale bounds width by aspect ratio | |
// and move points to fit new width | |
bounds.w = bounds.h * aspectRatio | |
if (isRightCorner) { | |
maxX = flipX ? minX - bounds.w : minX + bounds.w | |
} else { | |
minX = flipX ? maxX + bounds.w : maxX - bounds.w | |
} | |
} | |
} | |
bounds.x = flipX ? maxX : minX | |
bounds.y = flipY ? maxY : minY | |
bounds.maxX = bounds.x + bounds.w | |
bounds.maxY = bounds.y + bounds.h | |
for (let box of boxes) { | |
// Use the box's initial size normals to calculate | |
// its size in the new bounds. | |
const nBox = normalizedBoxes[box.id] | |
box.x = bounds.x + (flipX ? nBox.maxX : nBox.x) * bounds.w | |
box.y = bounds.y + (flipY ? nBox.maxY : nBox.y) * bounds.h | |
box.w = nBox.w * bounds.w | |
box.h = nBox.h * bounds.h | |
} | |
return { boxes, bounds } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment