621 lines
28 KiB
TypeScript
621 lines
28 KiB
TypeScript
import * as THREE from "three";
|
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
import { useFrame, useThree } from "@react-three/fiber";
|
|
import { useSocketStore, useToggleView, useToolMode, } from "../../../../../store/builder/store";
|
|
import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys";
|
|
import { useParams } from "react-router-dom";
|
|
import { getUserData } from "../../../../../functions/getUserData";
|
|
import { useSceneContext } from "../../../sceneContext";
|
|
import { useVersionContext } from "../../../../builder/version/versionContext";
|
|
import { useSelectedPoints } from "../../../../../store/simulation/useSimulationStore";
|
|
import useModuleStore from "../../../../../store/useModuleStore";
|
|
import { calculateAssetTransformationOnWall } from "../../../../builder/wallAsset/Instances/Instance/functions/calculateAssetTransformationOnWall";
|
|
|
|
// import { upsertAisleApi } from "../../../../../services/factoryBuilder/aisle/upsertAisleApi";
|
|
// import { upsertWallApi } from "../../../../../services/factoryBuilder/wall/upsertWallApi";
|
|
// import { upsertFloorApi } from "../../../../../services/factoryBuilder/floor/upsertFloorApi";
|
|
// import { upsertZoneApi } from "../../../../../services/factoryBuilder/zone/upsertZoneApi";
|
|
|
|
function MoveControls2D({
|
|
movedObjects,
|
|
setMovedObjects,
|
|
pastedObjects,
|
|
setPastedObjects,
|
|
duplicatedObjects,
|
|
setDuplicatedObjects,
|
|
rotatedObjects,
|
|
setRotatedObjects,
|
|
}: any) {
|
|
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
|
|
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
|
const { toolMode } = useToolMode();
|
|
const { toggleView } = useToggleView();
|
|
const { activeModule } = useModuleStore();
|
|
const { selectedPoints, clearSelectedPoints } = useSelectedPoints();
|
|
const { socket } = useSocketStore();
|
|
const { userId, organization } = getUserData();
|
|
const { projectId } = useParams();
|
|
const { selectedVersionStore } = useVersionContext();
|
|
const { selectedVersion } = selectedVersionStore();
|
|
const { aisleStore, wallStore, floorStore, zoneStore, undoRedo2DStore, wallAssetStore } = useSceneContext();
|
|
const { getWallAssetsByWall, updateWallAsset } = wallAssetStore();
|
|
const { push2D } = undoRedo2DStore();
|
|
const { setPosition: setAislePosition, getAislesByPointId, getAisleById } = aisleStore();
|
|
const { setPosition: setWallPosition, getWallsByPointId, getWallById } = wallStore();
|
|
const { setPosition: setFloorPosition, getFloorsByPointId, getFloorById } = floorStore();
|
|
const { setPosition: setZonePosition, getZonesByPointId, getZoneById } = zoneStore();
|
|
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
|
|
const [initialPositions, setInitialPositions] = useState<Record<string, THREE.Vector3>>({});
|
|
const [initialStates, setInitialStates] = useState<Record<string, { position: THREE.Vector3; rotation?: THREE.Euler; }>>({});
|
|
const [initial, setInitial] = useState<{
|
|
aisles?: Aisle[],
|
|
walls?: Wall[],
|
|
floors?: Floor[],
|
|
zones?: Zone[]
|
|
}>({});
|
|
const [isMoving, setIsMoving] = useState(false);
|
|
|
|
useEffect(() => {
|
|
if (!camera || !scene || !toggleView) return;
|
|
|
|
const canvasElement = gl.domElement;
|
|
canvasElement.tabIndex = 0;
|
|
|
|
let isMoving = false;
|
|
|
|
const onPointerDown = () => {
|
|
isMoving = false;
|
|
};
|
|
|
|
const onPointerMove = () => {
|
|
isMoving = true;
|
|
};
|
|
|
|
const onPointerUp = (event: PointerEvent) => {
|
|
if (!isMoving && movedObjects.length > 0 && event.button === 0) {
|
|
event.preventDefault();
|
|
placeMovedPoints();
|
|
}
|
|
if (!isMoving && movedObjects.length > 0 && event.button === 2) {
|
|
event.preventDefault();
|
|
|
|
clearSelection();
|
|
setMovedObjects([]);
|
|
resetToInitialPositions();
|
|
}
|
|
};
|
|
|
|
const onKeyDown = (event: KeyboardEvent) => {
|
|
const keyCombination = detectModifierKeys(event);
|
|
|
|
if (pastedObjects.length > 0 || duplicatedObjects.length > 0 || rotatedObjects.length > 0) return;
|
|
|
|
if (keyCombination === "G") {
|
|
if (selectedPoints.length > 0) {
|
|
movePoints();
|
|
}
|
|
}
|
|
|
|
if (keyCombination === "ESCAPE") {
|
|
event.preventDefault();
|
|
|
|
clearSelection();
|
|
setMovedObjects([]);
|
|
resetToInitialPositions();
|
|
}
|
|
};
|
|
|
|
if (toggleView && selectedPoints.length > 0) {
|
|
canvasElement.addEventListener("pointerdown", onPointerDown);
|
|
canvasElement.addEventListener("pointermove", onPointerMove);
|
|
canvasElement.addEventListener("pointerup", onPointerUp);
|
|
canvasElement.addEventListener("keydown", onKeyDown);
|
|
}
|
|
|
|
return () => {
|
|
canvasElement.removeEventListener("pointerdown", onPointerDown);
|
|
canvasElement.removeEventListener("pointermove", onPointerMove);
|
|
canvasElement.removeEventListener("pointerup", onPointerUp);
|
|
canvasElement.removeEventListener("keydown", onKeyDown);
|
|
};
|
|
}, [camera, controls, scene, toggleView, selectedPoints, socket, pastedObjects, duplicatedObjects, movedObjects, rotatedObjects, initial]);
|
|
|
|
useEffect(() => {
|
|
if (toolMode !== 'move' || !toggleView) {
|
|
if (movedObjects.length > 0) {
|
|
resetToInitialPositions();
|
|
}
|
|
clearSelection();
|
|
}
|
|
}, [activeModule, toolMode, toggleView, movedObjects]);
|
|
|
|
useFrame(() => {
|
|
if (!isMoving || movedObjects.length === 0 || !dragOffset) return;
|
|
|
|
raycaster.setFromCamera(pointer, camera);
|
|
const intersectionPoint = new THREE.Vector3();
|
|
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
|
|
|
if (hit) {
|
|
const baseNewPosition = new THREE.Vector3().addVectors(hit, dragOffset);
|
|
|
|
movedObjects.forEach((movedPoint: THREE.Object3D) => {
|
|
if (movedPoint.userData.pointUuid) {
|
|
const point: Point = movedPoint.userData as Point;
|
|
const initialPosition = initialPositions[movedPoint.uuid];
|
|
|
|
if (initialPosition) {
|
|
const relativeOffset = new THREE.Vector3().subVectors(
|
|
initialPosition,
|
|
initialPositions[movedObjects[0].uuid]
|
|
);
|
|
|
|
const newPosition = new THREE.Vector3().addVectors(baseNewPosition, relativeOffset);
|
|
const positionArray: [number, number, number] = [newPosition.x, newPosition.y, newPosition.z];
|
|
|
|
if (point.pointType === 'Aisle') {
|
|
setAislePosition(point.pointUuid, positionArray);
|
|
} else if (point.pointType === 'Wall') {
|
|
setWallPosition(point.pointUuid, positionArray);
|
|
} else if (point.pointType === 'Floor') {
|
|
setFloorPosition(point.pointUuid, positionArray);
|
|
} else if (point.pointType === 'Zone') {
|
|
setZonePosition(point.pointUuid, positionArray);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
const calculateDragOffset = useCallback((point: THREE.Object3D, hitPoint: THREE.Vector3) => {
|
|
const pointPosition = new THREE.Vector3().copy(point.position);
|
|
return new THREE.Vector3().subVectors(pointPosition, hitPoint);
|
|
}, []);
|
|
|
|
const movePoints = (() => {
|
|
if (selectedPoints.length === 0) return;
|
|
|
|
const states: Record<string, { position: THREE.Vector3; rotation?: THREE.Euler; }> = {};
|
|
const initials: {
|
|
aisles?: Aisle[] | undefined;
|
|
walls?: Wall[];
|
|
floors?: Floor[];
|
|
zones?: Zone[];
|
|
} = {}
|
|
|
|
selectedPoints.forEach((point: THREE.Object3D) => {
|
|
states[point.uuid] = {
|
|
position: new THREE.Vector3().copy(point.position),
|
|
rotation: point.rotation ? new THREE.Euler().copy(point.rotation) : undefined
|
|
};
|
|
|
|
if (point.userData.pointType === "Aisle") {
|
|
const aisles = getAislesByPointId(point.userData.pointUuid);
|
|
initials.aisles = [...(initials.aisles ?? []), ...aisles,].filter((aisle, index, self) => index === self.findIndex((a) => a.aisleUuid === aisle.aisleUuid));
|
|
} else if (point.userData.pointType === "Wall") {
|
|
const walls = getWallsByPointId(point.userData.pointUuid);
|
|
initials.walls = [...(initials.walls ?? []), ...walls,].filter((wall, index, self) => index === self.findIndex((w) => w.wallUuid === wall.wallUuid));
|
|
} else if (point.userData.pointType === "Floor") {
|
|
const floors = getFloorsByPointId(point.userData.pointUuid);
|
|
initials.floors = [...(initials.floors ?? []), ...floors,].filter((floor, index, self) => index === self.findIndex((f) => f.floorUuid === floor.floorUuid));
|
|
} else if (point.userData.pointType === "Zone") {
|
|
const zones = getZonesByPointId(point.userData.pointUuid);
|
|
initials.zones = [...(initials.zones ?? []), ...zones,].filter((zone, index, self) => index === self.findIndex((z) => z.zoneUuid === zone.zoneUuid));
|
|
}
|
|
});
|
|
|
|
setInitial(initials)
|
|
setInitialStates(states);
|
|
|
|
const positions: Record<string, THREE.Vector3> = {};
|
|
selectedPoints.forEach((point: THREE.Object3D) => { positions[point.uuid] = new THREE.Vector3().copy(point.position); });
|
|
setInitialPositions(positions);
|
|
|
|
raycaster.setFromCamera(pointer, camera);
|
|
const intersectionPoint = new THREE.Vector3();
|
|
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
|
|
|
if (hit && selectedPoints[0]) {
|
|
const offset = calculateDragOffset(selectedPoints[0], hit);
|
|
setDragOffset(offset);
|
|
}
|
|
|
|
setMovedObjects(selectedPoints);
|
|
setIsMoving(true);
|
|
});
|
|
|
|
const resetToInitialPositions = () => {
|
|
setTimeout(() => {
|
|
movedObjects.forEach((movedPoint: THREE.Object3D) => {
|
|
if (movedPoint.userData.pointUuid && initialStates[movedPoint.uuid]) {
|
|
const point: Point = movedPoint.userData as Point;
|
|
const initialState = initialStates[movedPoint.uuid];
|
|
const positionArray: [number, number, number] = [
|
|
initialState.position.x,
|
|
initialState.position.y,
|
|
initialState.position.z
|
|
];
|
|
|
|
if (point.pointType === 'Aisle') {
|
|
setAislePosition(point.pointUuid, positionArray);
|
|
} else if (point.pointType === 'Wall') {
|
|
setWallPosition(point.pointUuid, positionArray);
|
|
} else if (point.pointType === 'Floor') {
|
|
setFloorPosition(point.pointUuid, positionArray);
|
|
} else if (point.pointType === 'Zone') {
|
|
setZonePosition(point.pointUuid, positionArray);
|
|
}
|
|
}
|
|
});
|
|
}, 0)
|
|
};
|
|
|
|
const placeMovedPoints = () => {
|
|
if (movedObjects.length === 0) return;
|
|
|
|
const undoPoints: UndoRedo2DDataTypeSchema[] = [];
|
|
const processedAisles: UndoRedo2DDataTypeSchema[] = [];
|
|
const processedWalls: UndoRedo2DDataTypeSchema[] = [];
|
|
const processedFloors: UndoRedo2DDataTypeSchema[] = [];
|
|
const processedZones: UndoRedo2DDataTypeSchema[] = [];
|
|
const wallAssetUpdates: WallAsset[] = [];
|
|
|
|
movedObjects.forEach((movedObject: THREE.Object3D) => {
|
|
if (movedObject.userData.pointUuid) {
|
|
const point: Point = movedObject.userData as Point;
|
|
|
|
if (point.pointType === 'Aisle') {
|
|
const updatedAisles = getAislesByPointId(point.pointUuid);
|
|
if (updatedAisles.length > 0 && projectId) {
|
|
updatedAisles.forEach((updatedAisle) => {
|
|
|
|
// API
|
|
|
|
// upsertAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId, selectedVersion?.versionId || '');
|
|
|
|
// SOCKET
|
|
|
|
socket.emit('v1:model-aisle:add', {
|
|
projectId,
|
|
versionId: selectedVersion?.versionId || '',
|
|
userId,
|
|
organization,
|
|
aisleUuid: updatedAisle.aisleUuid,
|
|
points: updatedAisle.points,
|
|
type: updatedAisle.type
|
|
});
|
|
|
|
const old = initialStates[movedObject.uuid];
|
|
if (old) {
|
|
processedAisles.push({
|
|
type: 'Aisle',
|
|
lineData: {
|
|
...updatedAisle,
|
|
points: [
|
|
initialStates[updatedAisle.points[0].pointUuid] ?
|
|
{ ...updatedAisle.points[0], position: initialStates[updatedAisle.points[0].pointUuid].position }
|
|
: updatedAisle.points[0],
|
|
initialStates[updatedAisle.points[1].pointUuid] ?
|
|
{ ...updatedAisle.points[1], position: initialStates[updatedAisle.points[1].pointUuid].position }
|
|
: updatedAisle.points[1]
|
|
] as [Point, Point],
|
|
},
|
|
newData: updatedAisle,
|
|
timeStamp: new Date().toISOString(),
|
|
});
|
|
}
|
|
});
|
|
}
|
|
} else if (point.pointType === 'Wall') {
|
|
const updatedWalls = getWallsByPointId(point.pointUuid);
|
|
if (updatedWalls?.length && projectId) {
|
|
updatedWalls.forEach(updatedWall => {
|
|
|
|
const initialWall = initial.walls?.find(w => w.wallUuid === updatedWall.wallUuid);
|
|
|
|
if (initialWall) {
|
|
const assetsOnWall = getWallAssetsByWall(updatedWall.wallUuid);
|
|
|
|
assetsOnWall.forEach((asset) => {
|
|
const { position, rotation } = calculateAssetTransformationOnWall(asset, initialWall, updatedWall);
|
|
|
|
const updatedWallAsset: WallAsset = {
|
|
...asset,
|
|
position: [position[0], asset.position[1], position[2]],
|
|
rotation,
|
|
};
|
|
|
|
wallAssetUpdates.push(updatedWallAsset);
|
|
});
|
|
}
|
|
|
|
// API
|
|
|
|
// upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
|
|
|
// SOCKET
|
|
|
|
socket.emit('v1:model-Wall:add', {
|
|
wallData: updatedWall,
|
|
projectId,
|
|
versionId: selectedVersion?.versionId || '',
|
|
userId,
|
|
organization
|
|
});
|
|
|
|
const old = initialStates[movedObject.uuid];
|
|
if (old) {
|
|
processedWalls.push({
|
|
type: 'Wall',
|
|
lineData: {
|
|
...updatedWall,
|
|
points: [
|
|
initialStates[updatedWall.points[0].pointUuid] ?
|
|
{ ...updatedWall.points[0], position: initialStates[updatedWall.points[0].pointUuid].position }
|
|
: updatedWall.points[0],
|
|
initialStates[updatedWall.points[1].pointUuid] ?
|
|
{ ...updatedWall.points[1], position: initialStates[updatedWall.points[1].pointUuid].position }
|
|
: updatedWall.points[1]
|
|
] as [Point, Point],
|
|
},
|
|
newData: updatedWall,
|
|
timeStamp: new Date().toISOString(),
|
|
});
|
|
}
|
|
});
|
|
}
|
|
} else if (point.pointType === 'Floor') {
|
|
const Floors = getFloorsByPointId(point.pointUuid);
|
|
const updatedFloors = getFloorsByPointId(point.pointUuid);
|
|
if (updatedFloors?.length && projectId) {
|
|
updatedFloors.forEach(updatedFloor => {
|
|
|
|
// API
|
|
|
|
// upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedFloor);
|
|
|
|
// SOCKET
|
|
|
|
socket.emit('v1:model-Floor:add', {
|
|
floorData: updatedFloor,
|
|
projectId,
|
|
versionId: selectedVersion?.versionId || '',
|
|
userId,
|
|
organization
|
|
});
|
|
|
|
const updatedFloorsData = updatedFloors.map((floor) => {
|
|
const originalFloor = Floors.find(f => f.floorUuid === floor.floorUuid) || floor;
|
|
|
|
const updatedPoints = originalFloor.points.map((pt: Point) => {
|
|
const init = initialStates[pt.pointUuid];
|
|
return init ? { ...pt, position: [init.position.x, init.position.y, init.position.z] } : pt;
|
|
}) as [Point, Point];
|
|
|
|
return {
|
|
type: "Floor" as const,
|
|
lineData: { ...originalFloor, points: updatedPoints },
|
|
newData: floor,
|
|
timeStamp: new Date().toISOString(),
|
|
};
|
|
});
|
|
|
|
processedFloors.push(...updatedFloorsData);
|
|
});
|
|
}
|
|
} else if (point.pointType === 'Zone') {
|
|
const Zones = getZonesByPointId(point.pointUuid);
|
|
const updatedZones = getZonesByPointId(point.pointUuid);
|
|
if (updatedZones?.length && projectId) {
|
|
updatedZones.forEach(updatedZone => {
|
|
|
|
// API
|
|
|
|
// upsertZoneApi(projectId, selectedVersion?.versionId || '', updatedZone);
|
|
|
|
// SOCKET
|
|
|
|
socket.emit('v1:zone:add', {
|
|
zoneData: updatedZone,
|
|
projectId,
|
|
versionId: selectedVersion?.versionId || '',
|
|
userId,
|
|
organization
|
|
});
|
|
|
|
const updatedZonesData = updatedZones.map((zone) => {
|
|
const originalZone = Zones.find(z => z.zoneUuid === zone.zoneUuid) || zone;
|
|
|
|
const updatedPoints = originalZone.points.map((pt: Point) => {
|
|
const init = initialStates[pt.pointUuid];
|
|
return init ? { ...pt, position: [init.position.x, init.position.y, init.position.z] } : pt;
|
|
}) as [Point, Point];
|
|
|
|
return {
|
|
type: "Zone" as const,
|
|
lineData: { ...originalZone, points: updatedPoints },
|
|
newData: zone,
|
|
timeStamp: new Date().toISOString(),
|
|
};
|
|
});
|
|
|
|
processedZones.push(...updatedZonesData);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
setTimeout(() => {
|
|
|
|
if (wallAssetUpdates.length > 0) {
|
|
wallAssetUpdates.filter((wallAssets, index, self) => index === self.findIndex((w) => w.modelUuid === wallAssets.modelUuid));
|
|
wallAssetUpdates.forEach((updatedWallAsset) => {
|
|
if (projectId && updatedWallAsset) {
|
|
|
|
updateWallAsset(updatedWallAsset.modelUuid, {
|
|
position: updatedWallAsset.position,
|
|
rotation: updatedWallAsset.rotation
|
|
});
|
|
|
|
// API
|
|
|
|
// upsertWallAssetApi(projectId, selectedVersion?.versionId || '', updatedWallAsset);
|
|
|
|
// SOCKET
|
|
|
|
const data = {
|
|
wallAssetData: updatedWallAsset,
|
|
projectId: projectId,
|
|
versionId: selectedVersion?.versionId || '',
|
|
userId: userId,
|
|
organization: organization
|
|
}
|
|
|
|
socket.emit('v1:wall-asset:add', data);
|
|
}
|
|
});
|
|
}
|
|
|
|
if (processedWalls.length > 0) {
|
|
const wallMap = new Map<string, UndoRedo2DDataTypeSchema[]>();
|
|
|
|
for (const wall of processedWalls) {
|
|
if (wall.type !== 'Wall' || !wall.lineData.wallUuid) continue;
|
|
const uuid = wall.lineData.wallUuid;
|
|
if (!wallMap.has(uuid)) wallMap.set(uuid, []);
|
|
wallMap.get(uuid)!.push(wall);
|
|
}
|
|
|
|
wallMap.forEach((actions, uuid) => {
|
|
const hasUpdate = actions.some(action => 'newData' in action);
|
|
if (hasUpdate) {
|
|
const wallData = getWallById(uuid);
|
|
if (wallData) {
|
|
undoPoints.push({
|
|
type: 'Wall',
|
|
lineData: actions[0].lineData as Wall,
|
|
newData: wallData as Wall,
|
|
timeStamp: new Date().toISOString()
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
if (processedAisles.length > 0) {
|
|
const aisleMap = new Map<string, UndoRedo2DDataTypeSchema[]>();
|
|
|
|
for (const aisle of processedAisles) {
|
|
if (aisle.type !== 'Aisle' || !aisle.lineData.aisleUuid) continue;
|
|
const uuid = aisle.lineData.aisleUuid;
|
|
if (!aisleMap.has(uuid)) aisleMap.set(uuid, []);
|
|
aisleMap.get(uuid)!.push(aisle);
|
|
}
|
|
|
|
aisleMap.forEach((actions, uuid) => {
|
|
const hasUpdate = actions.some(action => 'newData' in action);
|
|
if (hasUpdate) {
|
|
const aisleData = getAisleById(uuid);
|
|
if (aisleData) {
|
|
undoPoints.push({
|
|
type: 'Aisle',
|
|
lineData: actions[0].lineData as Aisle,
|
|
newData: aisleData as Aisle,
|
|
timeStamp: new Date().toISOString()
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
if (processedFloors.length > 0) {
|
|
const floorMap = new Map<string, UndoRedo2DDataTypeSchema[]>();
|
|
|
|
for (const floor of processedFloors) {
|
|
if (floor.type !== 'Floor' || !floor.lineData.floorUuid) continue;
|
|
const uuid = floor.lineData.floorUuid;
|
|
if (!floorMap.has(uuid)) {
|
|
floorMap.set(uuid, []);
|
|
}
|
|
floorMap.get(uuid)!.push(floor);
|
|
}
|
|
|
|
floorMap.forEach((actions, uuid) => {
|
|
const hasUpdate = actions.some(action => 'newData' in action);
|
|
if (hasUpdate) {
|
|
const floorData = getFloorById(uuid);
|
|
if (floorData) {
|
|
undoPoints.push({
|
|
type: 'Floor',
|
|
lineData: actions[0].lineData as Floor,
|
|
newData: floorData as Floor,
|
|
timeStamp: new Date().toISOString()
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
if (processedZones.length > 0) {
|
|
const zoneMap = new Map<string, UndoRedo2DDataTypeSchema[]>();
|
|
|
|
for (const zone of processedZones) {
|
|
if (zone.type !== 'Zone' || !zone.lineData.zoneUuid) continue;
|
|
const uuid = zone.lineData.zoneUuid;
|
|
if (!zoneMap.has(uuid)) {
|
|
zoneMap.set(uuid, []);
|
|
}
|
|
zoneMap.get(uuid)!.push(zone);
|
|
}
|
|
|
|
zoneMap.forEach((actions, uuid) => {
|
|
const hasUpdate = actions.some(action => 'newData' in action);
|
|
if (hasUpdate) {
|
|
const zoneData = getZoneById(uuid);
|
|
if (zoneData) {
|
|
undoPoints.push({
|
|
type: 'Zone',
|
|
lineData: actions[0].lineData as Zone,
|
|
newData: zoneData as Zone,
|
|
timeStamp: new Date().toISOString()
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
if (undoPoints.length > 0) {
|
|
push2D({
|
|
type: 'Draw',
|
|
actions: [
|
|
{
|
|
actionType: 'Lines-Update',
|
|
points: undoPoints
|
|
}
|
|
]
|
|
});
|
|
}
|
|
}, 0);
|
|
|
|
echo.success("Object moved!");
|
|
clearSelection();
|
|
};
|
|
|
|
const clearSelection = () => {
|
|
setPastedObjects([]);
|
|
setDuplicatedObjects([]);
|
|
setMovedObjects([]);
|
|
setRotatedObjects([]);
|
|
clearSelectedPoints();
|
|
};
|
|
|
|
return (
|
|
<>
|
|
</>
|
|
);
|
|
}
|
|
|
|
export default MoveControls2D;
|