| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- import Command from "./command"
- import history from "../history"
- import { Data, MoveType, Shape } from "types"
- import { forceIntegerChildIndices, getChildren, getPage } from "utils/utils"
-
- export default function moveCommand(data: Data, type: MoveType) {
- const { currentPageId } = data
-
- const page = getPage(data)
-
- const selectedIds = Array.from(data.selectedIds.values())
-
- const initialIndices = Object.fromEntries(
- selectedIds.map((id) => [id, page.shapes[id].childIndex])
- )
-
- history.execute(
- data,
- new Command({
- name: "move_shapes",
- category: "canvas",
- manualSelection: true,
- do(data) {
- const page = getPage(data, currentPageId)
-
- const shapes = selectedIds.map((id) => page.shapes[id])
-
- const shapesByParentId = shapes.reduce<Record<string, Shape[]>>(
- (acc, shape) => {
- if (acc[shape.parentId] === undefined) {
- acc[shape.parentId] = []
- }
- acc[shape.parentId].push(shape)
- return acc
- },
- {}
- )
-
- switch (type) {
- case MoveType.ToFront: {
- for (let id in shapesByParentId) {
- moveToFront(shapesByParentId[id], getChildren(data, id))
- }
- break
- }
- case MoveType.ToBack: {
- for (let id in shapesByParentId) {
- moveToBack(shapesByParentId[id], getChildren(data, id))
- }
- break
- }
- case MoveType.Forward: {
- for (let id in shapesByParentId) {
- const visited = new Set<string>()
- const siblings = getChildren(data, id)
- shapesByParentId[id]
- .sort((a, b) => b.childIndex - a.childIndex)
- .forEach((shape) => moveForward(shape, siblings, visited))
- }
- break
- }
- case MoveType.Backward: {
- for (let id in shapesByParentId) {
- const visited = new Set<string>()
- const siblings = getChildren(data, id)
- shapesByParentId[id]
- .sort((a, b) => a.childIndex - b.childIndex)
- .forEach((shape) => moveBackward(shape, siblings, visited))
- }
- break
- }
- }
- },
- undo(data) {
- const page = getPage(data)
-
- for (let id of selectedIds) {
- page.shapes[id].childIndex = initialIndices[id]
- }
- },
- })
- )
- }
-
- function moveToFront(shapes: Shape[], siblings: Shape[]) {
- shapes.sort((a, b) => a.childIndex - b.childIndex)
-
- const diff = siblings
- .filter((sib) => !shapes.includes(sib))
- .sort((a, b) => b.childIndex - a.childIndex)
-
- if (diff.length === 0) return
-
- const startIndex = Math.ceil(diff[0].childIndex) + 1
-
- shapes.forEach((shape, i) => (shape.childIndex = startIndex + i))
- }
-
- function moveToBack(shapes: Shape[], siblings: Shape[]) {
- shapes.sort((a, b) => b.childIndex - a.childIndex)
-
- const diff = siblings
- .filter((sib) => !shapes.includes(sib))
- .sort((a, b) => a.childIndex - b.childIndex)
-
- if (diff.length === 0) return
-
- const startIndex = diff[0]?.childIndex
-
- const step = startIndex / (shapes.length + 1)
-
- shapes.forEach((shape, i) => (shape.childIndex = startIndex - (i + 1) * step))
- }
-
- function moveForward(shape: Shape, siblings: Shape[], visited: Set<string>) {
- visited.add(shape.id)
- const index = siblings.indexOf(shape)
- const nextSibling = siblings[index + 1]
-
- if (nextSibling && !visited.has(nextSibling.id)) {
- const nextNextSibling = siblings[index + 2]
-
- let nextIndex = nextNextSibling
- ? (nextSibling.childIndex + nextNextSibling.childIndex) / 2
- : Math.ceil(nextSibling.childIndex + 1)
-
- if (nextIndex === nextSibling.childIndex) {
- forceIntegerChildIndices(siblings)
-
- nextIndex = nextNextSibling
- ? (nextSibling.childIndex + nextNextSibling.childIndex) / 2
- : Math.ceil(nextSibling.childIndex + 1)
- }
-
- shape.childIndex = nextIndex
-
- siblings.sort((a, b) => a.childIndex - b.childIndex)
- }
- }
-
- function moveBackward(shape: Shape, siblings: Shape[], visited: Set<string>) {
- visited.add(shape.id)
- const index = siblings.indexOf(shape)
- const nextSibling = siblings[index - 1]
-
- if (nextSibling && !visited.has(nextSibling.id)) {
- const nextNextSibling = siblings[index - 2]
-
- let nextIndex = nextNextSibling
- ? (nextSibling.childIndex + nextNextSibling.childIndex) / 2
- : nextSibling.childIndex / 2
-
- if (shape.childIndex === nextSibling.childIndex) {
- forceIntegerChildIndices(siblings)
-
- nextNextSibling
- ? (nextSibling.childIndex + nextNextSibling.childIndex) / 2
- : nextSibling.childIndex / 2
- }
-
- shape.childIndex = nextIndex
-
- siblings.sort((a, b) => a.childIndex - b.childIndex)
- }
- }
|