Adds stretch
This commit is contained in:
parent
f0afe62073
commit
e9d46a70e4
3 changed files with 65 additions and 26 deletions
|
@ -1,10 +1,8 @@
|
||||||
import Command from "./command"
|
import Command from "./command"
|
||||||
import history from "../history"
|
import history from "../history"
|
||||||
import { AlignType, Data, DistributeType } from "types"
|
import { Data, DistributeType } from "types"
|
||||||
import * as vec from "utils/vec"
|
|
||||||
import {
|
import {
|
||||||
getBoundsCenter,
|
getBoundsCenter,
|
||||||
getBoundsFromPoints,
|
|
||||||
getCommonBounds,
|
getCommonBounds,
|
||||||
getPage,
|
getPage,
|
||||||
getSelectedShapes,
|
getSelectedShapes,
|
||||||
|
@ -19,17 +17,11 @@ export default function distributeCommand(data: Data, type: DistributeType) {
|
||||||
const entries = selectedShapes.map(
|
const entries = selectedShapes.map(
|
||||||
(shape) => [shape.id, getShapeUtils(shape).getBounds(shape)] as const
|
(shape) => [shape.id, getShapeUtils(shape).getBounds(shape)] as const
|
||||||
)
|
)
|
||||||
|
|
||||||
const boundsForShapes = Object.fromEntries(entries)
|
const boundsForShapes = Object.fromEntries(entries)
|
||||||
|
|
||||||
const commonBounds = getCommonBounds(...entries.map((entry) => entry[1]))
|
const commonBounds = getCommonBounds(...entries.map((entry) => entry[1]))
|
||||||
|
|
||||||
const innerBounds = getBoundsFromPoints(
|
|
||||||
entries.map((entry) => getBoundsCenter(entry[1]))
|
|
||||||
)
|
|
||||||
|
|
||||||
const midX = commonBounds.minX + commonBounds.width / 2
|
|
||||||
const midY = commonBounds.minY + commonBounds.height / 2
|
|
||||||
|
|
||||||
const centers = Object.fromEntries(
|
const centers = Object.fromEntries(
|
||||||
selectedShapes.map((shape) => [
|
selectedShapes.map((shape) => [
|
||||||
shape.id,
|
shape.id,
|
||||||
|
@ -73,15 +65,15 @@ export default function distributeCommand(data: Data, type: DistributeType) {
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const sortedByCenter = entries.sort(
|
const entriesToMove = entries.sort(
|
||||||
(a, b) => centers[a[0]][0] - centers[b[0]][0]
|
(a, b) => centers[a[0]][0] - centers[b[0]][0]
|
||||||
)
|
)
|
||||||
|
|
||||||
let x = commonBounds.minX
|
let x = commonBounds.minX
|
||||||
const step = (commonBounds.width - span) / (len - 1)
|
const step = (commonBounds.width - span) / (len - 1)
|
||||||
|
|
||||||
for (let i = 0; i < sortedByCenter.length - 1; i++) {
|
for (let i = 0; i < entriesToMove.length - 1; i++) {
|
||||||
const [id, bounds] = sortedByCenter[i]
|
const [id, bounds] = entriesToMove[i]
|
||||||
const shape = shapes[id]
|
const shape = shapes[id]
|
||||||
getShapeUtils(shape).translateTo(shape, [x, bounds.minY])
|
getShapeUtils(shape).translateTo(shape, [x, bounds.minY])
|
||||||
x += bounds.width + step
|
x += bounds.width + step
|
||||||
|
@ -115,15 +107,15 @@ export default function distributeCommand(data: Data, type: DistributeType) {
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const sortedByCenter = entries.sort(
|
const entriesToMove = entries.sort(
|
||||||
(a, b) => centers[a[0]][1] - centers[b[0]][1]
|
(a, b) => centers[a[0]][1] - centers[b[0]][1]
|
||||||
)
|
)
|
||||||
|
|
||||||
let y = commonBounds.minY
|
let y = commonBounds.minY
|
||||||
const step = (commonBounds.height - span) / (len - 1)
|
const step = (commonBounds.height - span) / (len - 1)
|
||||||
|
|
||||||
for (let i = 0; i < sortedByCenter.length - 1; i++) {
|
for (let i = 0; i < entriesToMove.length - 1; i++) {
|
||||||
const [id, bounds] = sortedByCenter[i]
|
const [id, bounds] = entriesToMove[i]
|
||||||
const shape = shapes[id]
|
const shape = shapes[id]
|
||||||
getShapeUtils(shape).translateTo(shape, [bounds.minX, y])
|
getShapeUtils(shape).translateTo(shape, [bounds.minX, y])
|
||||||
y += bounds.height + step
|
y += bounds.height + step
|
||||||
|
|
|
@ -1,36 +1,82 @@
|
||||||
import Command from "./command"
|
import Command from "./command"
|
||||||
import history from "../history"
|
import history from "../history"
|
||||||
import { StretchType, Data } from "types"
|
import { StretchType, Data, Edge, Corner } from "types"
|
||||||
import { getPage } from "utils/utils"
|
import { getCommonBounds, getPage, getSelectedShapes } from "utils/utils"
|
||||||
import { getShapeUtils } from "lib/shape-utils"
|
import { getShapeUtils } from "lib/shape-utils"
|
||||||
|
import { current } from "immer"
|
||||||
|
|
||||||
export default function stretchCommand(data: Data, type: StretchType) {
|
export default function stretchCommand(data: Data, type: StretchType) {
|
||||||
const { currentPageId } = data
|
const { currentPageId } = data
|
||||||
|
const initialShapes = getSelectedShapes(current(data))
|
||||||
const initialPoints = Object.fromEntries(
|
const entries = initialShapes.map(
|
||||||
Object.entries(getPage(data).shapes).map(([id, shape]) => [id, shape.point])
|
(shape) => [shape.id, getShapeUtils(shape).getBounds(shape)] as const
|
||||||
)
|
)
|
||||||
|
const boundsForShapes = Object.fromEntries(entries)
|
||||||
|
const commonBounds = getCommonBounds(...entries.map((entry) => entry[1]))
|
||||||
|
|
||||||
history.execute(
|
history.execute(
|
||||||
data,
|
data,
|
||||||
new Command({
|
new Command({
|
||||||
name: "distributed",
|
name: "stretched",
|
||||||
category: "canvas",
|
category: "canvas",
|
||||||
do(data) {
|
do(data) {
|
||||||
const { shapes } = getPage(data, currentPageId)
|
const { shapes } = getPage(data, currentPageId)
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case StretchType.Horizontal: {
|
case StretchType.Horizontal: {
|
||||||
|
for (let id in boundsForShapes) {
|
||||||
|
const initialShape = initialShapes[id]
|
||||||
|
const shape = shapes[id]
|
||||||
|
const oldBounds = boundsForShapes[id]
|
||||||
|
const newBounds = { ...oldBounds }
|
||||||
|
newBounds.minX = commonBounds.minX
|
||||||
|
newBounds.width = commonBounds.width
|
||||||
|
newBounds.maxX = commonBounds.maxX
|
||||||
|
|
||||||
|
getShapeUtils(shape).transform(shape, newBounds, {
|
||||||
|
type: Corner.TopLeft,
|
||||||
|
scaleX: newBounds.width / oldBounds.width,
|
||||||
|
scaleY: 1,
|
||||||
|
initialShape,
|
||||||
|
transformOrigin: [0.5, 0.5],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
break
|
||||||
}
|
}
|
||||||
case StretchType.Vertical: {
|
case StretchType.Vertical: {
|
||||||
|
for (let id in boundsForShapes) {
|
||||||
|
const initialShape = initialShapes[id]
|
||||||
|
const shape = shapes[id]
|
||||||
|
const oldBounds = boundsForShapes[id]
|
||||||
|
const newBounds = { ...oldBounds }
|
||||||
|
newBounds.minY = commonBounds.minY
|
||||||
|
newBounds.height = commonBounds.height
|
||||||
|
newBounds.maxY = commonBounds.maxY
|
||||||
|
|
||||||
|
getShapeUtils(shape).transform(shape, newBounds, {
|
||||||
|
type: Corner.TopLeft,
|
||||||
|
scaleX: 1,
|
||||||
|
scaleY: newBounds.height / oldBounds.height,
|
||||||
|
initialShape,
|
||||||
|
transformOrigin: [0.5, 0.5],
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
undo(data) {
|
undo(data) {
|
||||||
const { shapes } = getPage(data, currentPageId)
|
const { shapes } = getPage(data, currentPageId)
|
||||||
for (let id in initialPoints) {
|
for (let id in boundsForShapes) {
|
||||||
const shape = shapes[id]
|
const shape = shapes[id]
|
||||||
getShapeUtils(shape).translateTo(shape, initialPoints[id])
|
const initialShape = initialShapes[id]
|
||||||
|
const initialBounds = boundsForShapes[id]
|
||||||
|
getShapeUtils(shape).transform(shape, initialBounds, {
|
||||||
|
type: Corner.BottomRight,
|
||||||
|
scaleX: 1,
|
||||||
|
scaleY: 1,
|
||||||
|
initialShape,
|
||||||
|
transformOrigin: [0.5, 0.5],
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -81,8 +81,6 @@ const state = createState({
|
||||||
TOGGLED_STYLE_PANEL_OPEN: "toggleStylePanel",
|
TOGGLED_STYLE_PANEL_OPEN: "toggleStylePanel",
|
||||||
CHANGED_STYLE: ["updateStyles", "applyStylesToSelection"],
|
CHANGED_STYLE: ["updateStyles", "applyStylesToSelection"],
|
||||||
RESET_CAMERA: "resetCamera",
|
RESET_CAMERA: "resetCamera",
|
||||||
ALIGNED: "alignSelection",
|
|
||||||
DISTRIBUTED: "distributeSelection",
|
|
||||||
ZOOMED_TO_FIT: "zoomCameraToFit",
|
ZOOMED_TO_FIT: "zoomCameraToFit",
|
||||||
ZOOMED_TO_SELECTION: {
|
ZOOMED_TO_SELECTION: {
|
||||||
if: "hasSelection",
|
if: "hasSelection",
|
||||||
|
@ -125,6 +123,9 @@ const state = createState({
|
||||||
INCREASED_CODE_FONT_SIZE: "increaseCodeFontSize",
|
INCREASED_CODE_FONT_SIZE: "increaseCodeFontSize",
|
||||||
DECREASED_CODE_FONT_SIZE: "decreaseCodeFontSize",
|
DECREASED_CODE_FONT_SIZE: "decreaseCodeFontSize",
|
||||||
CHANGED_CODE_CONTROL: "updateControls",
|
CHANGED_CODE_CONTROL: "updateControls",
|
||||||
|
ALIGNED: "alignSelection",
|
||||||
|
STRETCHED: "stretchSelection",
|
||||||
|
DISTRIBUTED: "distributeSelection",
|
||||||
MOVED: "moveSelection",
|
MOVED: "moveSelection",
|
||||||
},
|
},
|
||||||
initial: "notPointing",
|
initial: "notPointing",
|
||||||
|
|
Loading…
Reference in a new issue