Adds stretch

This commit is contained in:
Steve Ruiz 2021-05-27 07:32:55 +01:00
parent f0afe62073
commit e9d46a70e4
3 changed files with 65 additions and 26 deletions

View file

@ -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

View file

@ -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],
})
} }
}, },
}) })

View file

@ -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",