seat-editor 2.1.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/constant.d.ts +232 -0
- package/dist/app/constant.js +3683 -3045
- package/dist/app/new-board/page.js +5 -6
- package/dist/app/only-view/chair.d.ts +1 -0
- package/dist/app/only-view/chair.js +4 -0
- package/dist/app/only-view/constant.d.ts +22 -2
- package/dist/app/only-view/constant.js +4 -4
- package/dist/app/only-view/page.js +74 -37
- package/dist/app/only-view/user.d.ts +1 -0
- package/dist/app/only-view/user.js +4 -0
- package/dist/components/layer-v3/index.d.ts +23 -4
- package/dist/components/layer-v3/index.js +329 -146
- package/dist/components/layer-v4/index.d.ts +20 -0
- package/dist/components/layer-v4/index.js +445 -0
- package/dist/components/lib/index.d.ts +1 -1
- package/dist/components/lib/index.js +1 -1
- package/dist/features/board/index.js +1 -1
- package/dist/features/board-v2/index.js +1 -1
- package/dist/features/board-v3/board-slice.d.ts +1 -0
- package/dist/features/board-v3/board-slice.js +26 -3
- package/dist/features/board-v3/constant.d.ts +5 -0
- package/dist/features/board-v3/constant.js +5 -0
- package/dist/features/board-v3/index copy.d.ts +47 -0
- package/dist/features/board-v3/index copy.js +2073 -0
- package/dist/features/board-v3/index.js +1409 -647
- package/dist/features/board-v3/polygon.d.ts +28 -0
- package/dist/features/board-v3/polygon.js +109 -0
- package/dist/features/board-v3/rect.d.ts +9 -0
- package/dist/features/board-v3/rect.js +152 -0
- package/dist/features/board-v3/resize-element.d.ts +12 -0
- package/dist/features/board-v3/resize-element.js +40 -0
- package/dist/features/board-v3/utils.d.ts +162 -0
- package/dist/features/board-v3/utils.js +787 -0
- package/dist/features/package/index.js +1 -1
- package/dist/features/panel/index.js +130 -20
- package/dist/features/panel/panel-slice.d.ts +5 -0
- package/dist/features/panel/panel-slice.js +15 -0
- package/dist/features/panel/select-tool.js +11 -1
- package/dist/features/panel/selected-group.d.ts +2 -0
- package/dist/features/panel/selected-group.js +7 -0
- package/dist/features/panel/table-seat-square.d.ts +2 -0
- package/dist/features/panel/table-seat-square.js +9 -0
- package/dist/features/side-tool/index.js +13 -6
- package/dist/features/view-only/index.js +0 -1
- package/dist/features/view-only-2/index.js +0 -1
- package/dist/features/view-only-3/index.d.ts +68 -0
- package/dist/features/view-only-3/index.js +510 -0
- package/dist/features/view-only-3/utils.d.ts +1 -0
- package/dist/features/view-only-3/utils.js +3 -0
- package/dist/seat-editor.css +1 -1
- package/dist/utils/constant.d.ts +1 -0
- package/dist/utils/constant.js +11 -0
- package/dist/utils/format.d.ts +2 -0
- package/dist/utils/format.js +29 -0
- package/package.json +3 -1
- package/dist/features/view/index.d.ts +0 -19
- package/dist/features/view/index.js +0 -221
|
@@ -1,70 +1,222 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { useCallback, useEffect, useRef, useState
|
|
4
|
-
import { TransformWrapper, TransformComponent,
|
|
3
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
4
|
+
import { TransformWrapper, TransformComponent, } from "react-zoom-pan-pinch";
|
|
5
5
|
import { useAppSelector, useAppDispatch } from "../../hooks/use-redux";
|
|
6
6
|
import Layers from "../../components/layer-v3";
|
|
7
|
-
import { throttle } from "lodash";
|
|
7
|
+
import { isEmpty, isPlainObject, isUndefined, throttle } from "lodash";
|
|
8
8
|
import ModalPreview from "../../components/modal-preview";
|
|
9
|
-
import LayerView from "../view";
|
|
9
|
+
import LayerView from "../view-only-2";
|
|
10
10
|
import { isEqual, debounce } from "lodash";
|
|
11
11
|
import { ZoomIn, ZoomOut } from "lucide-react";
|
|
12
12
|
import { Button } from "antd";
|
|
13
|
+
import { getAttributeElement, getAttributeElements } from "./resize-element";
|
|
14
|
+
import { applyResizeToSvgElement, arrayToSvgPointsAttr, createTableGhost, getGlobalBBox, getRotation, getSvgElementSize, getTranslate, isClosingPolygon, normalizeAngle, pointsStringToArray, resizeBox, resizeSeatCircle, resizeSeatSquare, stabilizeRotation, stabilizeTranslateOnRotate, updateManyComponents, updateSelectionBox, updateSingleComponent, } from "./utils";
|
|
15
|
+
const toolElement = ["square", "circle", "table-seat-circle"];
|
|
16
|
+
const idSelectionBoxGhost = "selection-box-ghost";
|
|
17
|
+
const nameShapeSelectionBoxGhost = "selection-box";
|
|
13
18
|
const BoardTemplate = ({ onSelectComponent, viewOnly }) => {
|
|
14
19
|
const dispatch = useAppDispatch();
|
|
15
|
-
const theme = useAppSelector((state) => state.theme);
|
|
16
20
|
const transformRef = useRef(null);
|
|
17
21
|
const containerRef = useRef(null);
|
|
22
|
+
const releaseGroupRef = useRef(false);
|
|
23
|
+
const dataSetGhost = useRef(null);
|
|
18
24
|
const [widthBoard, setWidthBoard] = useState(20000);
|
|
19
25
|
const [heightBoard, setHeightBoard] = useState(20000);
|
|
20
26
|
const svgRef = useRef(null);
|
|
21
27
|
const [shadowShape, setShadowShape] = useState([]);
|
|
22
|
-
const [startPoint, setStartPoint] = useState(null);
|
|
23
|
-
const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
|
|
24
|
-
// const [moveComponent, setMoveComponent] = useState(false);
|
|
25
28
|
const [scale, setScale] = useState(1);
|
|
29
|
+
const [boardSize, setBoardSize] = useState({ width: 20100, height: 20100 });
|
|
30
|
+
const [minCoords, setMinCoords] = useState({ x: -200, y: -200 });
|
|
31
|
+
const [hasInitialized, setHasInitialzed] = useState(false);
|
|
32
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
26
33
|
const activeTool = useAppSelector((state) => state.tool.active);
|
|
27
34
|
const grid = useAppSelector((state) => state.tool.grid);
|
|
28
35
|
const lockBackground = useAppSelector((state) => state.tool.lockBackground);
|
|
29
|
-
const { components: componentsProps, extraComponents: extraComponentsProps, flagChange, } = useAppSelector((state) => state.board);
|
|
30
|
-
const
|
|
36
|
+
const { components: componentsProps, extraComponents: extraComponentsProps, flagChange, updateBy, } = useAppSelector((state) => state.board);
|
|
37
|
+
const { selectionLines } = useAppSelector((state) => state.panel);
|
|
38
|
+
const [selectedLines, setSelectedLines] = useState([]);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
if (activeTool === "select" || activeTool !== "select") {
|
|
41
|
+
handleUnSelectComponent();
|
|
42
|
+
}
|
|
43
|
+
}, [activeTool]);
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (selectionLines) {
|
|
46
|
+
setSelectedLines(selectionLines);
|
|
47
|
+
const idSelected = dataElementSelectionGroupRef.current.map((item) => item.id);
|
|
48
|
+
const newSelectionData = [
|
|
49
|
+
...componentsState,
|
|
50
|
+
...extraComponentsState,
|
|
51
|
+
].filter((comp) => idSelected.includes(comp.id));
|
|
52
|
+
dataElementSelectionGroupRef.current = newSelectionData;
|
|
53
|
+
}
|
|
54
|
+
}, [selectionLines]);
|
|
31
55
|
useEffect(() => {
|
|
32
56
|
var _a;
|
|
33
57
|
if (activeTool !== ((_a = shadowShape[0]) === null || _a === void 0 ? void 0 : _a.shape)) {
|
|
34
58
|
setShadowShape([]);
|
|
35
59
|
}
|
|
36
60
|
}, [activeTool]);
|
|
37
|
-
// const [isDragging, setIsDragging] = useState(false);
|
|
38
61
|
const [resizeDirection, setResizeDirection] = useState(null);
|
|
39
62
|
const backgroundColor = useAppSelector((state) => state.board.backgroundColor);
|
|
40
63
|
const selectedComponentProps = useAppSelector((state) => state.panel.selectedComponent);
|
|
41
|
-
const screenCTMRef = useRef(null);
|
|
42
|
-
const dragIndex = useRef(null);
|
|
43
64
|
const [componentsState, setComponentsState] = useState([]);
|
|
44
65
|
const [extraComponentsState, setExtraComponentsState] = useState([]);
|
|
45
66
|
const [selectedComponent, setSelectedComponent] = useState(null);
|
|
46
67
|
const isSyncingFromRedux = useRef(false);
|
|
47
|
-
const startPos = useRef({ x: 0, y: 0 });
|
|
48
68
|
const isDragging = useRef(false);
|
|
49
69
|
const moveComponent = useRef(false);
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
72
|
+
if (hasInitialized)
|
|
73
|
+
return;
|
|
74
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
75
|
+
// let widthMinX = 0;
|
|
76
|
+
// let heightMinY = 0;
|
|
77
|
+
componentsProps === null || componentsProps === void 0 ? void 0 : componentsProps.forEach((_) => {
|
|
78
|
+
var _a, _b, _c, _d;
|
|
79
|
+
let values = _;
|
|
80
|
+
if ((_a = values === null || values === void 0 ? void 0 : values.shape) === null || _a === void 0 ? void 0 : _a.includes("square")) {
|
|
81
|
+
minX = Math.min(minX, values.x);
|
|
82
|
+
minY = Math.min(minY, values.y);
|
|
83
|
+
maxX = Math.max(maxX, values.x + values.width);
|
|
84
|
+
maxY = Math.max(maxY, values.y + values.height);
|
|
85
|
+
}
|
|
86
|
+
if ((_b = values === null || values === void 0 ? void 0 : values.shape) === null || _b === void 0 ? void 0 : _b.includes("circle")) {
|
|
87
|
+
minX = Math.min(minX, values.x);
|
|
88
|
+
minY = Math.min(minY, values.y);
|
|
89
|
+
maxX = Math.max(maxX, values.x + values.width);
|
|
90
|
+
maxY = Math.max(maxY, values.y + values.height);
|
|
91
|
+
}
|
|
92
|
+
if ((_c = values === null || values === void 0 ? void 0 : values.shape) === null || _c === void 0 ? void 0 : _c.includes("table-seat-circle")) {
|
|
93
|
+
minX = Math.min(minX, values.x);
|
|
94
|
+
minY = Math.min(minY, values.y);
|
|
95
|
+
maxX = Math.max(maxX, values.x + values.width);
|
|
96
|
+
maxY = Math.max(maxY, values.y + values.height);
|
|
97
|
+
}
|
|
98
|
+
if ((_d = values === null || values === void 0 ? void 0 : values.shape) === null || _d === void 0 ? void 0 : _d.includes("image-table")) {
|
|
99
|
+
minX = Math.min(minX, values.x);
|
|
100
|
+
minY = Math.min(minY, values.y);
|
|
101
|
+
maxX = Math.max(maxX, values.x + values.width);
|
|
102
|
+
maxY = Math.max(maxY, values.y + values.height);
|
|
103
|
+
}
|
|
104
|
+
// if (minX === _.x) {
|
|
105
|
+
// widthMinX = _.width;
|
|
106
|
+
// }
|
|
107
|
+
// if (minY === _.y) {
|
|
108
|
+
// heightMinY = _.height;
|
|
109
|
+
// }
|
|
110
|
+
});
|
|
111
|
+
extraComponentsProps === null || extraComponentsProps === void 0 ? void 0 : extraComponentsProps.forEach((values) => {
|
|
112
|
+
var _a, _b;
|
|
113
|
+
if ((_a = values === null || values === void 0 ? void 0 : values.shape) === null || _a === void 0 ? void 0 : _a.includes("background")) {
|
|
114
|
+
minX = Math.min(minX, values.x);
|
|
115
|
+
minY = Math.min(minY, values.y);
|
|
116
|
+
maxX = Math.max(maxX, values.x + values.width);
|
|
117
|
+
maxY = Math.max(maxY, values.y + values.height);
|
|
118
|
+
}
|
|
119
|
+
if ((_b = values === null || values === void 0 ? void 0 : values.shape) === null || _b === void 0 ? void 0 : _b.includes("text")) {
|
|
120
|
+
minX = Math.min(minX, values.x);
|
|
121
|
+
minY = Math.min(minY, values.y);
|
|
122
|
+
maxX = Math.max(maxX, values.x + values.width);
|
|
123
|
+
maxY = Math.max(maxY, values.y + values.height);
|
|
124
|
+
}
|
|
125
|
+
// if (minX === values.x) {
|
|
126
|
+
// widthMinX = values.width;
|
|
127
|
+
// }
|
|
128
|
+
// if (minY === values.y) {
|
|
129
|
+
// heightMinY = values.height;
|
|
130
|
+
// }
|
|
131
|
+
});
|
|
132
|
+
let backgroundHasOne = false;
|
|
133
|
+
if ((extraComponentsProps === null || extraComponentsProps === void 0 ? void 0 : extraComponentsProps.length) === 1 &&
|
|
134
|
+
((_b = (_a = extraComponentsProps === null || extraComponentsProps === void 0 ? void 0 : extraComponentsProps[0]) === null || _a === void 0 ? void 0 : _a.shape) === null || _b === void 0 ? void 0 : _b.includes("background"))) {
|
|
135
|
+
backgroundHasOne = true;
|
|
136
|
+
minX = (_c = extraComponentsProps === null || extraComponentsProps === void 0 ? void 0 : extraComponentsProps[0]) === null || _c === void 0 ? void 0 : _c.x;
|
|
137
|
+
minY = (_d = extraComponentsProps === null || extraComponentsProps === void 0 ? void 0 : extraComponentsProps[0]) === null || _d === void 0 ? void 0 : _d.y;
|
|
138
|
+
maxX = (_e = extraComponentsProps === null || extraComponentsProps === void 0 ? void 0 : extraComponentsProps[0]) === null || _e === void 0 ? void 0 : _e.width;
|
|
139
|
+
maxY = (_f = extraComponentsProps === null || extraComponentsProps === void 0 ? void 0 : extraComponentsProps[0]) === null || _f === void 0 ? void 0 : _f.height;
|
|
140
|
+
// if (minX === extraComponentsProps?.[0]?.x) {
|
|
141
|
+
// widthMinX = extraComponentsProps?.[0]?.width;
|
|
142
|
+
// }
|
|
143
|
+
// if (minY === extraComponentsProps?.[0]?.y) {
|
|
144
|
+
// heightMinY = extraComponentsProps?.[0]?.height;
|
|
145
|
+
// }
|
|
146
|
+
}
|
|
147
|
+
if ((extraComponentsProps === null || extraComponentsProps === void 0 ? void 0 : extraComponentsProps.length) < 1 &&
|
|
148
|
+
["background", "text"].includes((_g = componentsProps === null || componentsProps === void 0 ? void 0 : componentsProps[0]) === null || _g === void 0 ? void 0 : _g.shape)) {
|
|
149
|
+
minX = minX - minX * 0.5;
|
|
150
|
+
minY = minY - minY * 0.5;
|
|
151
|
+
}
|
|
152
|
+
if ((minX !== Infinity || minY !== Infinity) && !activeTool) {
|
|
153
|
+
(_h = transformRef.current) === null || _h === void 0 ? void 0 : _h.setTransform(-minX, -minY, scale);
|
|
154
|
+
setHasInitialzed(true);
|
|
155
|
+
}
|
|
156
|
+
// }
|
|
157
|
+
// if (!backgroundHasOne) {
|
|
158
|
+
// setMinCoords({ x: minX - minX * 0.5, y: minY - minY * 0.5 });
|
|
159
|
+
// }
|
|
160
|
+
// if(maxX > boardSize.width){
|
|
161
|
+
// setBoardSize((prev) => ({ ...prev, width: maxX }));
|
|
162
|
+
// }
|
|
163
|
+
// if(maxY > boardSize.height){
|
|
164
|
+
// setBoardSize((prev) => ({ ...prev, height: maxY }));
|
|
165
|
+
// }
|
|
166
|
+
// return {
|
|
167
|
+
// minX: backgroundHasOne ? minX : minX - minX * 0.5,
|
|
168
|
+
// minY: backgroundHasOne ? minY : minY - minY * 0.5,
|
|
169
|
+
// width: maxX,
|
|
170
|
+
// height: maxY,
|
|
171
|
+
// };
|
|
172
|
+
}, [componentsProps, extraComponentsProps]);
|
|
50
173
|
const debouncedSyncToReduxSelected = useRef(debounce((data) => {
|
|
51
174
|
throttledDispatch(data);
|
|
52
175
|
}, 300)).current;
|
|
53
|
-
const
|
|
176
|
+
const updateQueue = useRef([]);
|
|
177
|
+
const isFlushing = useRef(false);
|
|
178
|
+
const updateFlushToRedux = () => {
|
|
179
|
+
if (isFlushing.current)
|
|
180
|
+
return;
|
|
181
|
+
isFlushing.current = true;
|
|
182
|
+
requestAnimationFrame(() => {
|
|
183
|
+
const batch = updateQueue.current;
|
|
184
|
+
updateQueue.current = [];
|
|
185
|
+
isFlushing.current = false;
|
|
186
|
+
dispatch({
|
|
187
|
+
type: "board/setNewComponents",
|
|
188
|
+
payload: batch === null || batch === void 0 ? void 0 : batch[0],
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
};
|
|
192
|
+
const queueUpdateComponents = (data) => {
|
|
54
193
|
dispatch({
|
|
55
194
|
type: "board/setNewComponents",
|
|
56
195
|
payload: data,
|
|
57
196
|
});
|
|
58
|
-
}
|
|
197
|
+
};
|
|
198
|
+
const queueUpdateExtraComponents = (data) => {
|
|
199
|
+
dispatch({
|
|
200
|
+
type: "board/setNewExtraComponents",
|
|
201
|
+
payload: data,
|
|
202
|
+
});
|
|
203
|
+
};
|
|
59
204
|
const debouncedSyncExtraComponents = useRef(debounce((data) => {
|
|
60
205
|
dispatch({
|
|
61
206
|
type: "board/setNewExtraComponents",
|
|
62
207
|
payload: data,
|
|
63
208
|
});
|
|
209
|
+
}, 1000));
|
|
210
|
+
const debouncedUpdateSelectedLines = useRef(debounce((data) => {
|
|
211
|
+
const id = data;
|
|
212
|
+
const { g } = getAttributeElement(svgRef.current, id);
|
|
213
|
+
const getBBox = getGlobalBBox(svgRef.current, g);
|
|
214
|
+
console.log("masukkk update");
|
|
215
|
+
setSelectedLines((prev) => (Object.assign(Object.assign({}, prev), getBBox)));
|
|
64
216
|
}, 300));
|
|
65
217
|
// Redux → Local
|
|
66
218
|
useEffect(() => {
|
|
67
|
-
if (flagChange) {
|
|
219
|
+
if (flagChange && updateBy === "global") {
|
|
68
220
|
if (!isEqual(componentsProps, componentsState)) {
|
|
69
221
|
isSyncingFromRedux.current = true;
|
|
70
222
|
setComponentsState(componentsProps !== null && componentsProps !== void 0 ? componentsProps : []);
|
|
@@ -76,44 +228,50 @@ const BoardTemplate = ({ onSelectComponent, viewOnly }) => {
|
|
|
76
228
|
if (!isEqual(selectedComponentProps, selectedComponent)) {
|
|
77
229
|
isSyncingFromRedux.current = true;
|
|
78
230
|
setSelectedComponent(selectedComponentProps !== null && selectedComponentProps !== void 0 ? selectedComponentProps : []);
|
|
231
|
+
console.log("masukkk");
|
|
232
|
+
debouncedUpdateSelectedLines.current(selectedComponentProps === null || selectedComponentProps === void 0 ? void 0 : selectedComponentProps.id);
|
|
79
233
|
}
|
|
80
234
|
dispatch({ type: "board/setFlagChange", payload: false });
|
|
81
235
|
}
|
|
82
236
|
}, [
|
|
83
237
|
componentsProps,
|
|
84
238
|
extraComponentsProps,
|
|
85
|
-
selectedComponentProps,
|
|
86
|
-
flagChange,
|
|
239
|
+
// selectedComponentProps,
|
|
240
|
+
// flagChange,
|
|
87
241
|
]);
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
if (isSyncingFromRedux.current) {
|
|
91
|
-
isSyncingFromRedux.current = false;
|
|
242
|
+
const updateComponentAttribute = (component) => {
|
|
243
|
+
if (!component)
|
|
92
244
|
return;
|
|
245
|
+
const updatedComponents = updateSingleComponent(componentsState, component, setComponentsState);
|
|
246
|
+
if (updatedComponents) {
|
|
247
|
+
dispatch({ type: "board/setUpdateBy", payload: "local" });
|
|
248
|
+
queueUpdateComponents(updatedComponents);
|
|
93
249
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
!isEqual(extraComponentsState, [])) {
|
|
100
|
-
debouncedSyncExtraComponents.current(extraComponentsState);
|
|
101
|
-
}
|
|
102
|
-
}, [componentsState, extraComponentsState]);
|
|
103
|
-
const handleAddComponent = (shape) => {
|
|
104
|
-
dispatch({
|
|
105
|
-
type: activeTool === "text"
|
|
106
|
-
? "board/setExtraComponent"
|
|
107
|
-
: "board/addComponent",
|
|
108
|
-
payload: Object.assign(Object.assign({}, shape), { fill: theme === null || theme === void 0 ? void 0 : theme.primaryColor }),
|
|
109
|
-
});
|
|
110
|
-
const payload = Object.assign(Object.assign({}, shape), { fill: theme === null || theme === void 0 ? void 0 : theme.primaryColor });
|
|
111
|
-
if (activeTool === "text") {
|
|
112
|
-
setExtraComponentsState((prev) => [...prev, payload]);
|
|
250
|
+
const updatedExtra = updateSingleComponent(extraComponentsState, component, setExtraComponentsState);
|
|
251
|
+
if (updatedExtra) {
|
|
252
|
+
dispatch({ type: "board/setUpdateBy", payload: "local" });
|
|
253
|
+
queueUpdateExtraComponents(updatedExtra);
|
|
254
|
+
debouncedSyncExtraComponents.current(updatedExtra);
|
|
113
255
|
}
|
|
114
|
-
|
|
115
|
-
|
|
256
|
+
};
|
|
257
|
+
const updateComponentsAttribute = (components) => {
|
|
258
|
+
if (!components.length)
|
|
259
|
+
return;
|
|
260
|
+
const isExtra = components === null || components === void 0 ? void 0 : components.filter((item) => (item === null || item === void 0 ? void 0 : item.shape) === "polygon");
|
|
261
|
+
if (isExtra) {
|
|
262
|
+
const nextExtra = updateManyComponents(extraComponentsState, components, setExtraComponentsState);
|
|
263
|
+
dispatch({ type: "board/setUpdateBy", payload: "local" });
|
|
264
|
+
queueUpdateComponents(nextExtra);
|
|
116
265
|
}
|
|
266
|
+
const nextComponents = updateManyComponents(componentsState, components, setComponentsState);
|
|
267
|
+
dispatch({ type: "board/setUpdateBy", payload: "local" });
|
|
268
|
+
queueUpdateExtraComponents(nextComponents);
|
|
269
|
+
};
|
|
270
|
+
const addComponents = (components) => {
|
|
271
|
+
const newComponentState = [...extraComponentsState, components];
|
|
272
|
+
setExtraComponentsState(newComponentState);
|
|
273
|
+
dispatch({ type: "board/setUpdateBy", payload: "local" });
|
|
274
|
+
dispatch({ type: "board/setExtraComponent", payload: components });
|
|
117
275
|
};
|
|
118
276
|
const getSvgCoords = (e) => {
|
|
119
277
|
var _a;
|
|
@@ -124,154 +282,6 @@ const BoardTemplate = ({ onSelectComponent, viewOnly }) => {
|
|
|
124
282
|
const transformed = point.matrixTransform((_a = svg.getScreenCTM()) === null || _a === void 0 ? void 0 : _a.inverse());
|
|
125
283
|
return { x: transformed.x, y: transformed.y };
|
|
126
284
|
};
|
|
127
|
-
const createShape = (x, y, fill) => ({
|
|
128
|
-
x,
|
|
129
|
-
y,
|
|
130
|
-
width: 50 / scale,
|
|
131
|
-
height: 50 / scale,
|
|
132
|
-
shape: activeTool,
|
|
133
|
-
id: Date.now(),
|
|
134
|
-
fill,
|
|
135
|
-
rotation: activeTool === "diamond" ? 45 : 0,
|
|
136
|
-
seatCount: activeTool === "table-seat-circle" ? 6 : 0,
|
|
137
|
-
openSpace: activeTool === "table-seat-circle" ? 0 : undefined,
|
|
138
|
-
seatFill: activeTool === "table-seat-circle" ? "#DADADA" : undefined,
|
|
139
|
-
text: activeTool === "text" ? "Text" : "",
|
|
140
|
-
fontColor: activeTool === "text" ? "#DADADA" : undefined,
|
|
141
|
-
points: [],
|
|
142
|
-
});
|
|
143
|
-
const getCoords = (e) => {
|
|
144
|
-
const svgRect = svgRef.current.getBoundingClientRect();
|
|
145
|
-
if ("touches" in e) {
|
|
146
|
-
return {
|
|
147
|
-
x: e.touches[0].clientX,
|
|
148
|
-
y: e.touches[0].clientY,
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
return {
|
|
152
|
-
x: e.clientX - svgRect.x,
|
|
153
|
-
y: e.clientY - svgRect.y,
|
|
154
|
-
};
|
|
155
|
-
};
|
|
156
|
-
const handleMouseDown = (e, item, direction) => {
|
|
157
|
-
if (!item && !direction) {
|
|
158
|
-
if (["node", "select"].includes(activeTool)) {
|
|
159
|
-
setSelectedComponent(null);
|
|
160
|
-
dispatch({ type: "panel/setSelectedComponent", payload: null });
|
|
161
|
-
}
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
if (["node", "select"].includes(activeTool) && item && !direction) {
|
|
165
|
-
const coords = getCoords(e);
|
|
166
|
-
// startPos.current = { x: e.clientX, y: e.clientY };
|
|
167
|
-
// const rectBox = (e?.target as HTMLElement).getBoundingClientRect();
|
|
168
|
-
if (activeTool === "node") {
|
|
169
|
-
moveComponent.current = true;
|
|
170
|
-
isDragging.current = false;
|
|
171
|
-
dispatch({ type: "panel/setShow", payload: false });
|
|
172
|
-
// dispatch({
|
|
173
|
-
// type: "tool/setActiveTool",
|
|
174
|
-
// payload: "node",
|
|
175
|
-
// });
|
|
176
|
-
}
|
|
177
|
-
if (activeTool === "select") {
|
|
178
|
-
isDragging.current = true;
|
|
179
|
-
moveComponent.current = false;
|
|
180
|
-
dispatch({ type: "panel/setShow", payload: true });
|
|
181
|
-
}
|
|
182
|
-
const rectBox = (e === null || e === void 0 ? void 0 : e.target).getBoundingClientRect();
|
|
183
|
-
setDragOffset({
|
|
184
|
-
x: coords.x - rectBox.left + ((item === null || item === void 0 ? void 0 : item.strokeWidth) || 0),
|
|
185
|
-
y: coords.y - rectBox.top + ((item === null || item === void 0 ? void 0 : item.strokeWidth) || 0),
|
|
186
|
-
});
|
|
187
|
-
setSelectedComponent(item);
|
|
188
|
-
dispatch({
|
|
189
|
-
type: "panel/setSelectedComponent",
|
|
190
|
-
payload: item,
|
|
191
|
-
});
|
|
192
|
-
// const handleMouseMove = (event: MouseEvent) => {
|
|
193
|
-
// const dx = Math.abs(event.clientX - startPos.current.x);
|
|
194
|
-
// const dy = Math.abs(event.clientY - startPos.current.y);
|
|
195
|
-
// if (dx > 1 || dy > 1) {
|
|
196
|
-
// if (!moveComponent.current && item) {
|
|
197
|
-
// dispatch({ type: "panel/setSelectedComponent", payload: item });
|
|
198
|
-
// setSelectedComponent(item);
|
|
199
|
-
// }
|
|
200
|
-
// moveComponent.current = true;
|
|
201
|
-
// }
|
|
202
|
-
// };
|
|
203
|
-
// const handleMouseUp = () => {
|
|
204
|
-
// document.removeEventListener("mousemove", handleMouseMove);
|
|
205
|
-
// document.removeEventListener("mouseup", handleMouseUp);
|
|
206
|
-
// if (moveComponent.current) {
|
|
207
|
-
// moveComponent.current = false;
|
|
208
|
-
// } else {
|
|
209
|
-
// isDragging.current = true;
|
|
210
|
-
// moveComponent.current = false;
|
|
211
|
-
// setResizeDirection(direction);
|
|
212
|
-
// if (item) {
|
|
213
|
-
// dispatch({ type: "panel/setSelectedComponent", payload: item });
|
|
214
|
-
// dispatch({ type: "panel/setShow", payload: true });
|
|
215
|
-
// setSelectedComponent(item);
|
|
216
|
-
// }
|
|
217
|
-
// }
|
|
218
|
-
// };
|
|
219
|
-
// Pasang ke `document` agar global
|
|
220
|
-
// document.addEventListener("mousemove", handleMouseMove);
|
|
221
|
-
// document.addEventListener("mouseup", handleMouseUp);
|
|
222
|
-
}
|
|
223
|
-
// if(activeTool === "select" && item && !direction) {
|
|
224
|
-
// dispatch({
|
|
225
|
-
// type: "tool/setActiveTool",
|
|
226
|
-
// payload: "node",
|
|
227
|
-
// });
|
|
228
|
-
// }
|
|
229
|
-
if (activeTool === "select" && direction) {
|
|
230
|
-
setResizeDirection(direction);
|
|
231
|
-
}
|
|
232
|
-
};
|
|
233
|
-
const handleMouseEnter = () => {
|
|
234
|
-
if (![
|
|
235
|
-
"square",
|
|
236
|
-
"circle",
|
|
237
|
-
"diamond",
|
|
238
|
-
"table-seat-circle",
|
|
239
|
-
"table-seat-square",
|
|
240
|
-
"text",
|
|
241
|
-
].includes(activeTool))
|
|
242
|
-
return;
|
|
243
|
-
};
|
|
244
|
-
const handleMouseLeave = () => {
|
|
245
|
-
if (![
|
|
246
|
-
"square",
|
|
247
|
-
"circle",
|
|
248
|
-
"diamond",
|
|
249
|
-
"table-seat-circle",
|
|
250
|
-
"table-seat-square",
|
|
251
|
-
"text",
|
|
252
|
-
].includes(activeTool))
|
|
253
|
-
return;
|
|
254
|
-
setShadowShape([]);
|
|
255
|
-
};
|
|
256
|
-
const handleMouseClick = (e) => {
|
|
257
|
-
if (["select", "node"].includes(activeTool) && selectedComponent) {
|
|
258
|
-
handleUnSelectComponent();
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
if (![
|
|
262
|
-
"square",
|
|
263
|
-
"circle",
|
|
264
|
-
"diamond",
|
|
265
|
-
"table-seat-circle",
|
|
266
|
-
"table-seat-square",
|
|
267
|
-
"text",
|
|
268
|
-
].includes(activeTool)) {
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
const { x, y } = getSvgCoords(e);
|
|
272
|
-
setStartPoint({ x, y });
|
|
273
|
-
handleAddComponent(createShape(x, y, theme === null || theme === void 0 ? void 0 : theme.primaryColor));
|
|
274
|
-
};
|
|
275
285
|
const throttledDispatch = useCallback(throttle((component) => {
|
|
276
286
|
// dispatch({
|
|
277
287
|
// type: "board/updateComponent",
|
|
@@ -283,372 +293,6 @@ const BoardTemplate = ({ onSelectComponent, viewOnly }) => {
|
|
|
283
293
|
});
|
|
284
294
|
}, 16), // 16ms ≈ 60fps
|
|
285
295
|
[dispatch]);
|
|
286
|
-
const handleMouseMove = (e) => {
|
|
287
|
-
var _a;
|
|
288
|
-
if ([
|
|
289
|
-
"square",
|
|
290
|
-
"circle",
|
|
291
|
-
"diamond",
|
|
292
|
-
"table-seat-circle",
|
|
293
|
-
"table-seat-square",
|
|
294
|
-
"text",
|
|
295
|
-
"ruler",
|
|
296
|
-
].includes(activeTool)) {
|
|
297
|
-
const { x, y } = getSvgCoords(e);
|
|
298
|
-
setShadowShape([createShape(x, y, theme === null || theme === void 0 ? void 0 : theme.primaryColor)]);
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
if ((selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.shape) === "background" && lockBackground)
|
|
302
|
-
return;
|
|
303
|
-
if (activeTool === "node" &&
|
|
304
|
-
selectedComponent &&
|
|
305
|
-
moveComponent.current &&
|
|
306
|
-
dragOffset &&
|
|
307
|
-
// !isTouching.current &&
|
|
308
|
-
!resizeDirection) {
|
|
309
|
-
const workspaceRect = e.currentTarget.getBoundingClientRect();
|
|
310
|
-
const coords = getCoords(e);
|
|
311
|
-
const newX = coords.x - workspaceRect.left - (dragOffset === null || dragOffset === void 0 ? void 0 : dragOffset.x);
|
|
312
|
-
const newY = coords.y - workspaceRect.top - (dragOffset === null || dragOffset === void 0 ? void 0 : dragOffset.y);
|
|
313
|
-
let newPosition = {
|
|
314
|
-
x: newX / scale,
|
|
315
|
-
y: newY / scale,
|
|
316
|
-
};
|
|
317
|
-
requestAnimationFrame(() => {
|
|
318
|
-
setComponentsState((prev) => {
|
|
319
|
-
return prev.map((component) => {
|
|
320
|
-
if (component.id === selectedComponent.id) {
|
|
321
|
-
return Object.assign(Object.assign({}, component), { x: newPosition.x, y: newPosition.y });
|
|
322
|
-
}
|
|
323
|
-
return component;
|
|
324
|
-
});
|
|
325
|
-
});
|
|
326
|
-
setExtraComponentsState((prev) => {
|
|
327
|
-
return prev.map((component) => {
|
|
328
|
-
if (component.id === selectedComponent.id) {
|
|
329
|
-
return Object.assign(Object.assign({}, component), { x: newPosition.x, y: newPosition.y });
|
|
330
|
-
}
|
|
331
|
-
return component;
|
|
332
|
-
});
|
|
333
|
-
});
|
|
334
|
-
setSelectedComponent((prev) => {
|
|
335
|
-
return Object.assign(Object.assign({}, prev), { x: newPosition.x, y: newPosition.y });
|
|
336
|
-
});
|
|
337
|
-
});
|
|
338
|
-
debouncedSyncToReduxSelected(Object.assign(Object.assign({}, selectedComponent), newPosition));
|
|
339
|
-
return;
|
|
340
|
-
}
|
|
341
|
-
if (activeTool === "select" && resizeDirection) {
|
|
342
|
-
const coords = getCoords(e);
|
|
343
|
-
const workspaceRect = e.currentTarget.getBoundingClientRect();
|
|
344
|
-
const instance = (_a = transformRef.current) === null || _a === void 0 ? void 0 : _a.instance;
|
|
345
|
-
if (!instance)
|
|
346
|
-
return;
|
|
347
|
-
const { positionX, positionY } = instance.transformState;
|
|
348
|
-
const currentX = (coords.x + workspaceRect.left - 50 - positionX) / scale;
|
|
349
|
-
const currentY = (coords.y + workspaceRect.top - positionY) / scale;
|
|
350
|
-
const { x, y, width, height } = selectedComponent;
|
|
351
|
-
let newShape = Object.assign({}, selectedComponent);
|
|
352
|
-
switch (resizeDirection) {
|
|
353
|
-
case "top-left":
|
|
354
|
-
newShape.width = width + (x - currentX);
|
|
355
|
-
newShape.height = height + (y - currentY);
|
|
356
|
-
newShape.x = currentX;
|
|
357
|
-
newShape.y = currentY;
|
|
358
|
-
break;
|
|
359
|
-
case "top-right":
|
|
360
|
-
newShape.width = currentX - newShape.x;
|
|
361
|
-
newShape.height = newShape.height + (newShape.y - currentY);
|
|
362
|
-
newShape.y = currentY;
|
|
363
|
-
break;
|
|
364
|
-
case "bottom-left":
|
|
365
|
-
newShape.width += newShape.x - currentX;
|
|
366
|
-
newShape.height = currentY - newShape.y;
|
|
367
|
-
newShape.x = currentX;
|
|
368
|
-
break;
|
|
369
|
-
case "bottom-right":
|
|
370
|
-
newShape.width = currentX - newShape.x;
|
|
371
|
-
newShape.height = currentY - newShape.y;
|
|
372
|
-
break;
|
|
373
|
-
case "left":
|
|
374
|
-
newShape.width += newShape.x - currentX;
|
|
375
|
-
newShape.x = currentX;
|
|
376
|
-
break;
|
|
377
|
-
case "right":
|
|
378
|
-
newShape.width = currentX - newShape.x;
|
|
379
|
-
break;
|
|
380
|
-
case "top": {
|
|
381
|
-
newShape.height += newShape.y - currentY;
|
|
382
|
-
newShape.y = currentY;
|
|
383
|
-
break;
|
|
384
|
-
}
|
|
385
|
-
case "bottom":
|
|
386
|
-
newShape.height = currentY - newShape.y;
|
|
387
|
-
break;
|
|
388
|
-
default:
|
|
389
|
-
break;
|
|
390
|
-
}
|
|
391
|
-
requestAnimationFrame(() => {
|
|
392
|
-
setComponentsState((prev) => {
|
|
393
|
-
return prev.map((component) => {
|
|
394
|
-
if (component.id === selectedComponent.id) {
|
|
395
|
-
return Object.assign(Object.assign({}, component), newShape);
|
|
396
|
-
}
|
|
397
|
-
return component;
|
|
398
|
-
});
|
|
399
|
-
});
|
|
400
|
-
setExtraComponentsState((prev) => {
|
|
401
|
-
return prev.map((component) => {
|
|
402
|
-
if (component.id === selectedComponent.id) {
|
|
403
|
-
return Object.assign(Object.assign({}, component), newShape);
|
|
404
|
-
}
|
|
405
|
-
return component;
|
|
406
|
-
});
|
|
407
|
-
});
|
|
408
|
-
setSelectedComponent(newShape);
|
|
409
|
-
});
|
|
410
|
-
debouncedSyncToReduxSelected(newShape);
|
|
411
|
-
}
|
|
412
|
-
};
|
|
413
|
-
const handleMouseUp = () => {
|
|
414
|
-
if (["select", "node"].includes(activeTool) && selectedComponent) {
|
|
415
|
-
setResizeDirection(null);
|
|
416
|
-
moveComponent.current = false;
|
|
417
|
-
}
|
|
418
|
-
};
|
|
419
|
-
// useEffect(() => {
|
|
420
|
-
// if (containerRef.current) {
|
|
421
|
-
// setWidthBoard(containerRef.current.offsetWidth);
|
|
422
|
-
// setHeightBoard(containerRef.current.offsetHeight);
|
|
423
|
-
// }
|
|
424
|
-
// }, [
|
|
425
|
-
// containerRef?.current?.offsetWidth,
|
|
426
|
-
// containerRef?.current?.offsetHeight,
|
|
427
|
-
// viewOnly,
|
|
428
|
-
// ]);
|
|
429
|
-
const handleUnSelectComponent = () => {
|
|
430
|
-
dispatch({ type: "panel/setSelectedComponent", payload: null });
|
|
431
|
-
setSelectedComponent(null);
|
|
432
|
-
};
|
|
433
|
-
// const handleTouchStart = (
|
|
434
|
-
// e: React.TouchEvent<
|
|
435
|
-
// SVGRectElement | SVGCircleElement | SVGTextElement | SVGImageElement
|
|
436
|
-
// >,
|
|
437
|
-
// items: any,
|
|
438
|
-
// direction?: string
|
|
439
|
-
// ) => {
|
|
440
|
-
// if (activeTool === "node" && !direction && items) {
|
|
441
|
-
// // dispatch({ type: "panel/setShow", payload: false });
|
|
442
|
-
// // setMoveComponent(true);
|
|
443
|
-
// moveComponent.current = true;
|
|
444
|
-
// isTouching.current = true;
|
|
445
|
-
// // dispatch({ type: "panel/setSelectedComponent", payload: item });
|
|
446
|
-
// onSelectComponent && onSelectComponent(items);
|
|
447
|
-
// dispatch({ type: "panel/setSelectedComponent", payload: items });
|
|
448
|
-
// setSelectedComponent(items);
|
|
449
|
-
// // selectedComponentRef.current = items;
|
|
450
|
-
// const touch = e.touches[0];
|
|
451
|
-
// const svg = e.currentTarget.ownerSVGElement;
|
|
452
|
-
// const pt = svg.createSVGPoint();
|
|
453
|
-
// if (!svg) return;
|
|
454
|
-
// pt.x = touch.clientX;
|
|
455
|
-
// pt.y = touch.clientY;
|
|
456
|
-
// const cursorpt = pt.matrixTransform(svg.getScreenCTM()?.inverse());
|
|
457
|
-
// screenCTMRef.current = svg.getScreenCTM()?.inverse() || null;
|
|
458
|
-
// setDragOffset({
|
|
459
|
-
// x: cursorpt.x - items.x,
|
|
460
|
-
// y: cursorpt.y - items.y,
|
|
461
|
-
// });
|
|
462
|
-
// // dragOffset.current = {
|
|
463
|
-
// // x: cursorpt.x - items.x,
|
|
464
|
-
// // y: cursorpt.y - items.y
|
|
465
|
-
// // }
|
|
466
|
-
// } else if (activeTool === "select" && direction) {
|
|
467
|
-
// setResizeDirection(direction);
|
|
468
|
-
// // setIsDragging(true);
|
|
469
|
-
// // setMoveComponent(true);
|
|
470
|
-
// moveComponent.current = true;
|
|
471
|
-
// isDragging.current = true;
|
|
472
|
-
// isTouching.current = true;
|
|
473
|
-
// const touch = e.touches[0];
|
|
474
|
-
// const svg = e.currentTarget.ownerSVGElement;
|
|
475
|
-
// const pt = svg.createSVGPoint();
|
|
476
|
-
// if (!svg) return;
|
|
477
|
-
// pt.x = touch.clientX;
|
|
478
|
-
// pt.y = touch.clientY;
|
|
479
|
-
// const cursorpt = pt.matrixTransform(svg.getScreenCTM()?.inverse());
|
|
480
|
-
// screenCTMRef.current = svg.getScreenCTM()?.inverse() || null;
|
|
481
|
-
// setDragOffset({
|
|
482
|
-
// x: cursorpt.x - items.x,
|
|
483
|
-
// y: cursorpt.y - items.y,
|
|
484
|
-
// });
|
|
485
|
-
// // dragOffset.current = {
|
|
486
|
-
// // x: cursorpt.x - items.x,
|
|
487
|
-
// // y: cursorpt.y - items.y
|
|
488
|
-
// // }
|
|
489
|
-
// }
|
|
490
|
-
// };
|
|
491
|
-
// const handleTouchMove = (
|
|
492
|
-
// e: React.TouchEvent<
|
|
493
|
-
// SVGRectElement | SVGCircleElement | SVGTextElement | SVGImageElement
|
|
494
|
-
// >
|
|
495
|
-
// ) => {
|
|
496
|
-
// if (
|
|
497
|
-
// activeTool === "node" &&
|
|
498
|
-
// moveComponent &&
|
|
499
|
-
// isTouching.current &&
|
|
500
|
-
// !resizeDirection
|
|
501
|
-
// ) {
|
|
502
|
-
// isDragging.current = true;
|
|
503
|
-
// moveComponent.current = true;
|
|
504
|
-
// const touch = e.touches[0];
|
|
505
|
-
// const svg = e.currentTarget.ownerSVGElement;
|
|
506
|
-
// if (!svg) return;
|
|
507
|
-
// const pt = svg.createSVGPoint();
|
|
508
|
-
// pt.x = touch.clientX;
|
|
509
|
-
// pt.y = touch.clientY;
|
|
510
|
-
// const cursorpt = pt.matrixTransform(screenCTMRef.current);
|
|
511
|
-
// requestAnimationFrame(() => {
|
|
512
|
-
// if (selectedComponent?.shape != "background") {
|
|
513
|
-
// setComponentsState((prev) => {
|
|
514
|
-
// return prev.map((component) => {
|
|
515
|
-
// if (component.id === selectedComponent.id) {
|
|
516
|
-
// return {
|
|
517
|
-
// ...component,
|
|
518
|
-
// x: cursorpt.x - dragOffset?.x,
|
|
519
|
-
// y: cursorpt.y - dragOffset?.y,
|
|
520
|
-
// };
|
|
521
|
-
// }
|
|
522
|
-
// return component;
|
|
523
|
-
// });
|
|
524
|
-
// });
|
|
525
|
-
// }
|
|
526
|
-
// if (selectedComponent?.shape == "background") {
|
|
527
|
-
// setExtraComponentsState((prev) => {
|
|
528
|
-
// return prev.map((component) => {
|
|
529
|
-
// if (component.id === selectedComponent.id) {
|
|
530
|
-
// return {
|
|
531
|
-
// ...component,
|
|
532
|
-
// x: cursorpt.x - dragOffset?.x,
|
|
533
|
-
// y: cursorpt.y - dragOffset?.y,
|
|
534
|
-
// };
|
|
535
|
-
// }
|
|
536
|
-
// return component;
|
|
537
|
-
// });
|
|
538
|
-
// });
|
|
539
|
-
// }
|
|
540
|
-
// setSelectedComponent({
|
|
541
|
-
// ...selectedComponent,
|
|
542
|
-
// x: cursorpt.x - dragOffset?.x,
|
|
543
|
-
// y: cursorpt.y - dragOffset?.y,
|
|
544
|
-
// });
|
|
545
|
-
// });
|
|
546
|
-
// // updateComponentRef({
|
|
547
|
-
// // ...(typeof selectedComponent === "object" && selectedComponent !== null
|
|
548
|
-
// // ? selectedComponent
|
|
549
|
-
// // : {}),
|
|
550
|
-
// // x: cursorpt.x - dragOffset?.current.x,
|
|
551
|
-
// // y: cursorpt.y - dragOffset?.current.y,
|
|
552
|
-
// // });
|
|
553
|
-
// } else if (
|
|
554
|
-
// activeTool === "select" &&
|
|
555
|
-
// moveComponent.current &&
|
|
556
|
-
// isTouching.current &&
|
|
557
|
-
// resizeDirection
|
|
558
|
-
// ) {
|
|
559
|
-
// // setIsDragging(true);
|
|
560
|
-
// isDragging.current = true;
|
|
561
|
-
// const touch = e.touches[0];
|
|
562
|
-
// const svg = e.currentTarget.ownerSVGElement;
|
|
563
|
-
// if (!svg) return;
|
|
564
|
-
// const pt = svg.createSVGPoint();
|
|
565
|
-
// pt.x = touch.clientX;
|
|
566
|
-
// pt.y = touch.clientY;
|
|
567
|
-
// const cursorpt = pt.matrixTransform(screenCTMRef.current);
|
|
568
|
-
// let newShape = { ...selectedComponent };
|
|
569
|
-
// switch (resizeDirection) {
|
|
570
|
-
// case "top-left":
|
|
571
|
-
// newShape.width = newShape.width + (newShape.x - cursorpt.x);
|
|
572
|
-
// newShape.height = newShape.height + (newShape.y - cursorpt.y);
|
|
573
|
-
// newShape.x = cursorpt.x;
|
|
574
|
-
// newShape.y = cursorpt.y;
|
|
575
|
-
// break;
|
|
576
|
-
// case "top-right":
|
|
577
|
-
// newShape.width = cursorpt.x - newShape.x;
|
|
578
|
-
// newShape.height = newShape.height + (newShape.y - cursorpt.y);
|
|
579
|
-
// newShape.y = cursorpt.y;
|
|
580
|
-
// break;
|
|
581
|
-
// case "bottom-left":
|
|
582
|
-
// newShape.width = newShape.width + (newShape.x - cursorpt.x);
|
|
583
|
-
// newShape.height = cursorpt.y - newShape.y;
|
|
584
|
-
// newShape.x = cursorpt.x;
|
|
585
|
-
// break;
|
|
586
|
-
// case "bottom-right":
|
|
587
|
-
// newShape.width = cursorpt.x - newShape.x;
|
|
588
|
-
// newShape.height = cursorpt.y - newShape.y;
|
|
589
|
-
// break;
|
|
590
|
-
// case "top-center":
|
|
591
|
-
// newShape.height = newShape.height + (newShape.y - cursorpt.y);
|
|
592
|
-
// newShape.y = cursorpt.y;
|
|
593
|
-
// break;
|
|
594
|
-
// case "bottom-center":
|
|
595
|
-
// newShape.height = cursorpt.y - newShape.y;
|
|
596
|
-
// break;
|
|
597
|
-
// case "right-center":
|
|
598
|
-
// newShape.width = cursorpt.x - newShape.x;
|
|
599
|
-
// break;
|
|
600
|
-
// case "left-center":
|
|
601
|
-
// newShape.width = newShape.width + (newShape.x - cursorpt.x);
|
|
602
|
-
// newShape.x = cursorpt.x;
|
|
603
|
-
// break;
|
|
604
|
-
// default:
|
|
605
|
-
// break;
|
|
606
|
-
// }
|
|
607
|
-
// // updateComponentRef({
|
|
608
|
-
// // ...(typeof selectedComponent === "object" && selectedComponent !== null
|
|
609
|
-
// // ? selectedComponent
|
|
610
|
-
// // : {}),
|
|
611
|
-
// // ...newShape,
|
|
612
|
-
// // });
|
|
613
|
-
// requestAnimationFrame(() => {
|
|
614
|
-
// setComponentsState((prev) => {
|
|
615
|
-
// return prev.map((component) => {
|
|
616
|
-
// if (component.id === selectedComponent.id) {
|
|
617
|
-
// return {
|
|
618
|
-
// ...component,
|
|
619
|
-
// ...newShape,
|
|
620
|
-
// };
|
|
621
|
-
// }
|
|
622
|
-
// return component;
|
|
623
|
-
// });
|
|
624
|
-
// });
|
|
625
|
-
// setExtraComponentsState((prev) => {
|
|
626
|
-
// return prev.map((component) => {
|
|
627
|
-
// if (component.id === selectedComponent.id) {
|
|
628
|
-
// return {
|
|
629
|
-
// ...component,
|
|
630
|
-
// ...newShape,
|
|
631
|
-
// };
|
|
632
|
-
// }
|
|
633
|
-
// return component;
|
|
634
|
-
// });
|
|
635
|
-
// });
|
|
636
|
-
// setSelectedComponent({
|
|
637
|
-
// ...selectedComponent,
|
|
638
|
-
// ...newShape,
|
|
639
|
-
// });
|
|
640
|
-
// });
|
|
641
|
-
// debouncedSyncToReduxSelected(newShape);
|
|
642
|
-
// }
|
|
643
|
-
// };
|
|
644
|
-
// const handleTouchEnd = () => {
|
|
645
|
-
// // setMoveComponent(false);
|
|
646
|
-
// // setIsDragging(false);
|
|
647
|
-
// moveComponent.current = false;
|
|
648
|
-
// isDragging.current = false;
|
|
649
|
-
// isTouching.current = false;
|
|
650
|
-
// setResizeDirection(null);
|
|
651
|
-
// };
|
|
652
296
|
const getCursorStyle = () => {
|
|
653
297
|
if (activeTool === "select" && moveComponent.current) {
|
|
654
298
|
return "grabbing";
|
|
@@ -663,19 +307,6 @@ const BoardTemplate = ({ onSelectComponent, viewOnly }) => {
|
|
|
663
307
|
return "crosshair";
|
|
664
308
|
}
|
|
665
309
|
};
|
|
666
|
-
const renderMiniMap = () => {
|
|
667
|
-
return (_jsx(MiniMap, { width: 250, height: 250, children: _jsx("div", { className: "w-full h-full", children: _jsx("svg", { id: "workspace", width: "100%", height: "100%",
|
|
668
|
-
// viewBox={`0 0 ${widthBoard} ${heightBoard}`}
|
|
669
|
-
className: "h-screen w-full", xmlns: "http://www.w3.org/2000/svg", preserveAspectRatio: "xMidYMid meet", style: {
|
|
670
|
-
background: "#f5f5f5",
|
|
671
|
-
display: "block",
|
|
672
|
-
}, children: _jsx(Layers, { shadowShape: shadowShape, components: [...extraComponentsState, ...componentsState], activeTool: activeTool,
|
|
673
|
-
// onClick={handleSelectComponent}
|
|
674
|
-
onMouseDown: handleMouseDown,
|
|
675
|
-
// onMouseUp={handleMouseUp}
|
|
676
|
-
// onBlur={handleUnSelectComponent}
|
|
677
|
-
selectedComponent: selectedComponent }) }) }) }));
|
|
678
|
-
};
|
|
679
310
|
const handelZoomIn = () => {
|
|
680
311
|
var _a;
|
|
681
312
|
if (activeTool !== "grab") {
|
|
@@ -696,90 +327,1221 @@ const BoardTemplate = ({ onSelectComponent, viewOnly }) => {
|
|
|
696
327
|
}
|
|
697
328
|
(_a = transformRef.current) === null || _a === void 0 ? void 0 : _a.zoomOut();
|
|
698
329
|
};
|
|
699
|
-
// const
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
// if (item.id === selectedComponent?.id) {
|
|
707
|
-
// handleUnSelectComponent();
|
|
708
|
-
// return;
|
|
709
|
-
// }
|
|
710
|
-
// dispatch({ type: "panel/setSelectedComponent", payload: item });
|
|
711
|
-
// setSelectedComponent(item);
|
|
712
|
-
// // setSelectedComponent(item);
|
|
713
|
-
// throttledDispatch(item);
|
|
714
|
-
// }
|
|
715
|
-
// };
|
|
716
|
-
// activeTool === "select" &&
|
|
717
|
-
// moveComponent &&
|
|
718
|
-
// isTouching.current &&
|
|
719
|
-
// !resizeDirection
|
|
720
|
-
// const [nodes, setNodes] = useState([
|
|
721
|
-
// { x: 80, y: 40 },
|
|
722
|
-
// { x: 220, y: 40 },
|
|
723
|
-
// { x: 260, y: 160 },
|
|
724
|
-
// { x: 40, y: 160 },
|
|
725
|
-
// ]);
|
|
726
|
-
const addNode = () => {
|
|
727
|
-
// if (nodes.length < 30) {
|
|
728
|
-
// const midIndex = Math.floor(nodes.length / 2);
|
|
729
|
-
// const prev = nodes[midIndex - 1];
|
|
730
|
-
// const curr = nodes[midIndex];
|
|
731
|
-
// const newNode = {
|
|
732
|
-
// x: (prev.x + curr.x) / 2,
|
|
733
|
-
// y: (prev.y + curr.y) / 2,
|
|
734
|
-
// };
|
|
735
|
-
// const newNodes = [...nodes];
|
|
736
|
-
// newNodes.splice(midIndex, 0, newNode);
|
|
737
|
-
// setNodes(newNodes);
|
|
738
|
-
// }
|
|
330
|
+
// const [touch, setTouch] = useState(false);
|
|
331
|
+
const handleUnSelectComponent = () => {
|
|
332
|
+
dispatch({ type: "panel/setSelectedComponent", payload: null });
|
|
333
|
+
setSelectedComponent(null);
|
|
334
|
+
setSelectedLines(null);
|
|
335
|
+
dispatch({ type: "panel/setShow", payload: false });
|
|
336
|
+
dataElementSelectionGroupRef.current = [];
|
|
739
337
|
};
|
|
740
|
-
const
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
338
|
+
const startAngleRef = useRef(0);
|
|
339
|
+
const startRotationRef = useRef(0);
|
|
340
|
+
const ghostRotateElement = useRef(0);
|
|
341
|
+
const isResizeRef = useRef(false);
|
|
342
|
+
const isResizeSelectionRef = useRef(false);
|
|
343
|
+
const selectionDataRef = useRef([]);
|
|
344
|
+
// const selectionElementsRef = useRef<any>([]);
|
|
345
|
+
// const selectionElementRawsRef = useRef<any>([]);
|
|
346
|
+
const hadSelectionRef = useRef(false);
|
|
347
|
+
//FLAGE EVERY HANDLE EVENT
|
|
348
|
+
//CREATE
|
|
349
|
+
const isCreateElementRef = useRef(false);
|
|
350
|
+
//RESIZE
|
|
351
|
+
const onResizeSelectionRef = useRef(false);
|
|
352
|
+
//ROTATE
|
|
353
|
+
const isRotatingRef = useRef(false);
|
|
354
|
+
const rotationSelectionRef = useRef(0);
|
|
355
|
+
//DRAG/MOVE
|
|
356
|
+
//SELECT
|
|
357
|
+
const isSelectingRef = useRef(false);
|
|
358
|
+
const activeIdSelectedRef = useRef(null);
|
|
359
|
+
//SELECTION
|
|
360
|
+
const selectionLinesRef = useRef(null);
|
|
361
|
+
const onMakeSelectionRef = useRef(false);
|
|
362
|
+
// const dataElementSelectionGroupRawRef = useRef<Element[]>([]);
|
|
363
|
+
const onMoveSelectionBoxRef = useRef(false);
|
|
364
|
+
const onResizeSelectionBoxRef = useRef(false);
|
|
365
|
+
const dataElementSelectionGroupRef = useRef([]);
|
|
366
|
+
//polygon
|
|
367
|
+
const isPolygonRef = useRef(false);
|
|
368
|
+
const polygonElementRef = useRef([]);
|
|
369
|
+
const isOnMakePolygonRef = useRef(false);
|
|
370
|
+
const startPointPolygonLineRef = useRef({ x: 0, y: 0 });
|
|
371
|
+
const handlePointerDown = (e) => {
|
|
372
|
+
var _a, _b, _c, _d, _e;
|
|
373
|
+
const shiftActive = e.shiftKey;
|
|
374
|
+
console.log("shiftActive", shiftActive);
|
|
375
|
+
const svg = svgRef.current;
|
|
376
|
+
if (!e.isPrimary)
|
|
377
|
+
return;
|
|
378
|
+
if (!svg)
|
|
379
|
+
return;
|
|
380
|
+
isDragging.current = false;
|
|
381
|
+
let hasMoved = false;
|
|
382
|
+
releaseGroupRef.current = false;
|
|
383
|
+
const startX = e.clientX;
|
|
384
|
+
const startY = e.clientY;
|
|
385
|
+
const pt = svg.createSVGPoint();
|
|
386
|
+
pt.x = e.clientX;
|
|
387
|
+
pt.y = e.clientY;
|
|
388
|
+
const { x, y } = getSvgCoords(e);
|
|
389
|
+
//CREATE ELEMENT
|
|
390
|
+
const isInitialCreateElemente = toolElement.includes(activeTool) && !isCreateElementRef.current;
|
|
391
|
+
if (isInitialCreateElemente) {
|
|
392
|
+
console.log("INITIAL CREATE ELEMENT");
|
|
393
|
+
const tables = createTableGhost({
|
|
394
|
+
x,
|
|
395
|
+
y,
|
|
396
|
+
width: 1,
|
|
397
|
+
height: 1,
|
|
398
|
+
fill: "red",
|
|
399
|
+
shape: activeTool,
|
|
400
|
+
});
|
|
401
|
+
// setGhostCreateElement(tables);
|
|
402
|
+
(_a = svgRef.current) === null || _a === void 0 ? void 0 : _a.appendChild(tables);
|
|
403
|
+
isCreateElementRef.current = true;
|
|
404
|
+
}
|
|
405
|
+
const targetSelection = e.target.closest("g[id='selection-lines']");
|
|
406
|
+
//ROTATE
|
|
407
|
+
const targetRotate = e.target.closest("circle[data-role]");
|
|
408
|
+
if (targetRotate) {
|
|
409
|
+
console.log("TARGET ROTATE");
|
|
410
|
+
isRotatingRef.current = true;
|
|
411
|
+
}
|
|
412
|
+
// RESIZE
|
|
413
|
+
const targetGroup = e.target.closest("g[data-id]");
|
|
414
|
+
const targetPointPolygon = e.target.closest("circle[data-point]");
|
|
415
|
+
// TARGET ELEMENT
|
|
416
|
+
let idTargetElement = JSON.parse((targetGroup === null || targetGroup === void 0 ? void 0 : targetGroup.getAttribute("data-id")) || "{}");
|
|
417
|
+
const selectionTarget = (_c = (_b = targetSelection === null || targetSelection === void 0 ? void 0 : targetSelection.dataset) === null || _b === void 0 ? void 0 : _b.selection) === null || _c === void 0 ? void 0 : _c.replace("selection-", "");
|
|
418
|
+
const activeId = selectionTarget !== null && selectionTarget !== void 0 ? selectionTarget : idTargetElement;
|
|
419
|
+
const isInSelectionTarget = !isUndefined(selectionTarget);
|
|
420
|
+
const isInTargetElement = !isPlainObject(idTargetElement);
|
|
421
|
+
const isSingleSelection = isInSelectionTarget && (selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id) === activeId;
|
|
422
|
+
console.log("activeId", activeId);
|
|
423
|
+
const { g, inner } = getAttributeElement(svg, activeId);
|
|
424
|
+
if (targetGroup && shiftActive) {
|
|
425
|
+
const findById = [...componentsState, ...extraComponentsState].find((comp) => comp.id == activeId);
|
|
426
|
+
console.log("findById", findById, "HIT TARGET USING SHIFT");
|
|
427
|
+
const dataSelection = [...dataElementSelectionGroupRef.current, findById];
|
|
428
|
+
dataElementSelectionGroupRef.current = dataSelection;
|
|
429
|
+
}
|
|
430
|
+
const box = getGlobalBBox(svg, g);
|
|
431
|
+
const { x: initialXG, y: initialYG } = getTranslate(g);
|
|
432
|
+
const targetDragPosition = e.target.closest("circle[data-position]");
|
|
433
|
+
const { clientX, clientY } = e;
|
|
434
|
+
const hitPoint = document.elementFromPoint(clientX, clientY);
|
|
435
|
+
// CHECK FOR HIT ON SVG FOR SELECTION BOX
|
|
436
|
+
// MAKE AND UNMAKE SELECTION BOX START ------
|
|
437
|
+
const hadSelectionBox = ((_d = dataElementSelectionGroupRef.current) === null || _d === void 0 ? void 0 : _d.length) > 0 && !isSingleSelection;
|
|
438
|
+
const downInSelectionBox = hadSelectionBox && (hitPoint === null || hitPoint === void 0 ? void 0 : hitPoint.nodeName) !== "svg";
|
|
439
|
+
const downOutSelectionBox = hadSelectionBox && (hitPoint === null || hitPoint === void 0 ? void 0 : hitPoint.nodeName) === "svg";
|
|
440
|
+
const downBeforeHasSelectionBox = !downInSelectionBox &&
|
|
441
|
+
(hitPoint === null || hitPoint === void 0 ? void 0 : hitPoint.nodeName) === "svg" &&
|
|
442
|
+
activeTool === "select";
|
|
443
|
+
const isRotateSelectionBox = targetRotate && hadSelectionBox;
|
|
444
|
+
let currentRotation = 0;
|
|
445
|
+
if (isRotateSelectionBox) {
|
|
446
|
+
console.log("LAGI ROTATE SELECTION BOX");
|
|
447
|
+
currentRotation = rotationSelectionRef.current;
|
|
448
|
+
}
|
|
449
|
+
//move tanpa ada selection single element dan bisa move juga ketika ada selection box
|
|
450
|
+
//JIKA PUNYA SELECTION TAPI DOWN DI ELEMENT LAIN
|
|
451
|
+
const downInMatchSelectionBox = downInSelectionBox && (hitPoint === null || hitPoint === void 0 ? void 0 : hitPoint.nodeName) !== "svg" && isInSelectionTarget;
|
|
452
|
+
if (downInSelectionBox) {
|
|
453
|
+
console.log("HIT IN SELECTION BOX");
|
|
454
|
+
hadSelectionRef.current = true;
|
|
455
|
+
}
|
|
456
|
+
if (downOutSelectionBox) {
|
|
457
|
+
console.log("HIT OUT SELECTION BOX");
|
|
458
|
+
hadSelectionRef.current = false;
|
|
459
|
+
onMoveSelectionBoxRef.current = false;
|
|
460
|
+
handleUnSelectComponent();
|
|
461
|
+
}
|
|
462
|
+
if (downBeforeHasSelectionBox) {
|
|
463
|
+
console.log("HIT BEFORE HAS SELECTION BOX");
|
|
464
|
+
// RELEASE SELECT
|
|
465
|
+
releaseGroupRef.current = true;
|
|
466
|
+
// MAKING SELECTION BOX DOWN
|
|
467
|
+
onMakeSelectionRef.current = true;
|
|
468
|
+
onMoveSelectionBoxRef.current = false;
|
|
469
|
+
handleUnSelectComponent();
|
|
470
|
+
const boxSelection = createTableGhost({
|
|
471
|
+
x,
|
|
472
|
+
y,
|
|
473
|
+
width: 1,
|
|
474
|
+
height: 1,
|
|
475
|
+
fill: "transparent",
|
|
476
|
+
shape: nameShapeSelectionBoxGhost,
|
|
477
|
+
id: idSelectionBoxGhost,
|
|
478
|
+
});
|
|
479
|
+
(_e = svgRef.current) === null || _e === void 0 ? void 0 : _e.appendChild(boxSelection);
|
|
480
|
+
}
|
|
481
|
+
// MAKE AND UNMAKE SELECTION BOX END ------
|
|
482
|
+
// RESIZE SELECTION BOX
|
|
483
|
+
const resizeSide = (targetDragPosition === null || targetDragPosition === void 0 ? void 0 : targetDragPosition.dataset.position) || "{}";
|
|
484
|
+
const downAtResizePosition = resizeSide !== "{}";
|
|
485
|
+
const downOutResizePosition = resizeSide === "{}";
|
|
486
|
+
//down in selection box (need check element didalammnya)
|
|
487
|
+
const downOutResizePositionAndInSelectionBox = downOutResizePosition &&
|
|
488
|
+
hadSelectionBox &&
|
|
489
|
+
!downOutSelectionBox &&
|
|
490
|
+
isInSelectionTarget &&
|
|
491
|
+
!isSingleSelection &&
|
|
492
|
+
!isInTargetElement;
|
|
493
|
+
const downAtResizePositionAndHasSelectionBox = downAtResizePosition && hadSelectionBox && !isRotateSelectionBox;
|
|
494
|
+
const isMightResizeElement = !isEmpty(selectedComponent) &&
|
|
495
|
+
downAtResizePosition &&
|
|
496
|
+
downAtResizePosition &&
|
|
497
|
+
!hadSelectionBox;
|
|
498
|
+
const isMightMove = activeId &&
|
|
499
|
+
!targetPointPolygon &&
|
|
500
|
+
isInTargetElement &&
|
|
501
|
+
!isMightResizeElement;
|
|
502
|
+
const isMightMoveOneElementSelection = isSingleSelection && !isMightResizeElement;
|
|
503
|
+
console.log({ isMightResizeElement });
|
|
504
|
+
// if (
|
|
505
|
+
// !downInMatchSelectionBox &&
|
|
506
|
+
// !downAtResizePositionAndHasSelectionBox &&
|
|
507
|
+
// !targetRotate &&
|
|
508
|
+
// !isMightResizeElement &&
|
|
509
|
+
// !targetPointPolygon &&
|
|
510
|
+
// !isMightMove &&
|
|
511
|
+
// !targetSelection
|
|
512
|
+
// ) {
|
|
513
|
+
// console.log("MAUK UNSELET");
|
|
514
|
+
// hadSelectionRef.current = false;
|
|
515
|
+
// onMoveSelectionBoxRef.current = false;
|
|
516
|
+
// handleUnSelectComponent();
|
|
517
|
+
// selectionLinesRef.current = null;
|
|
746
518
|
// }
|
|
519
|
+
if (downOutResizePositionAndInSelectionBox) {
|
|
520
|
+
console.log("DOWN OUT RESIZE POSITION AND IN SELECTION BOX");
|
|
521
|
+
onMoveSelectionBoxRef.current = true;
|
|
522
|
+
}
|
|
523
|
+
if (downAtResizePosition) {
|
|
524
|
+
console.log("DOWN AT RESIZE POSITION");
|
|
525
|
+
onResizeSelectionRef.current = true;
|
|
526
|
+
}
|
|
527
|
+
// targetGroup?.removeAttribute("transform");
|
|
528
|
+
const mousePositionInGroup = {
|
|
529
|
+
x: x - (box === null || box === void 0 ? void 0 : box.x),
|
|
530
|
+
y: y - (box === null || box === void 0 ? void 0 : box.y),
|
|
531
|
+
};
|
|
532
|
+
const offset = {
|
|
533
|
+
x: x - initialXG,
|
|
534
|
+
y: y - initialYG,
|
|
535
|
+
};
|
|
536
|
+
// create polygon
|
|
537
|
+
const isInitialPolyGon = activeTool === "polygon" && !isCreateElementRef.current;
|
|
538
|
+
if (isInitialPolyGon && (selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.shape) !== "polygon") {
|
|
539
|
+
console.log("DOWN CREATE POLYGON");
|
|
540
|
+
const newPolygon = {
|
|
541
|
+
id: `${Date.now()}`,
|
|
542
|
+
shape: "polygon",
|
|
543
|
+
fill: "red",
|
|
544
|
+
points: [{ x, y }],
|
|
545
|
+
rotation: 0,
|
|
546
|
+
};
|
|
547
|
+
polygonElementRef.current = newPolygon;
|
|
548
|
+
// addComponents(newPolygon);
|
|
549
|
+
setSelectedComponent(newPolygon);
|
|
550
|
+
dispatch({
|
|
551
|
+
type: "panel/setSelectedComponent",
|
|
552
|
+
payload: newPolygon,
|
|
553
|
+
});
|
|
554
|
+
isOnMakePolygonRef.current = true;
|
|
555
|
+
}
|
|
556
|
+
// const selectionLines = svgRef.current?.querySelector(
|
|
557
|
+
// "#selection-lines"
|
|
558
|
+
// ) as SVGGElement;
|
|
559
|
+
// const boxSelection = svgRef.current?.querySelector(
|
|
560
|
+
// "#rect-box-selection"
|
|
561
|
+
// ) as SVGRectElement;
|
|
562
|
+
// const allElementInSelection = svgRef.current?.querySelectorAll(
|
|
563
|
+
// "#ghost-element-has-selection"
|
|
564
|
+
// );
|
|
565
|
+
const pointerHandleMove = (ev) => {
|
|
566
|
+
var _a;
|
|
567
|
+
//SVG POINTER
|
|
568
|
+
const pt = svg.createSVGPoint();
|
|
569
|
+
pt.x = ev.clientX;
|
|
570
|
+
pt.y = ev.clientY;
|
|
571
|
+
const pos = pt.matrixTransform(svg.getScreenCTM().inverse());
|
|
572
|
+
//RESIZE POLYGON
|
|
573
|
+
const onResizePolygon = (pos) => {
|
|
574
|
+
var _a, _b;
|
|
575
|
+
console.log("on resize polygon");
|
|
576
|
+
const dx = pos.x - x;
|
|
577
|
+
const dy = pos.y - y;
|
|
578
|
+
const { g, inner, element } = getAttributeElement(svg, activeId);
|
|
579
|
+
const angleDeg = getRotation(inner.transform.baseVal); // 0–360
|
|
580
|
+
const angleRad = (angleDeg * Math.PI) / 180;
|
|
581
|
+
const cos = Math.cos(-angleRad);
|
|
582
|
+
const sin = Math.sin(-angleRad);
|
|
583
|
+
const localDx = dx * cos - dy * sin;
|
|
584
|
+
const localDy = dx * sin + dy * cos;
|
|
585
|
+
const index = Number(targetPointPolygon.getAttribute("id"));
|
|
586
|
+
const points = element === null || element === void 0 ? void 0 : element.getAttribute("points");
|
|
587
|
+
let arrayPoints = pointsStringToArray(points);
|
|
588
|
+
const pointsStart = (selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.points) || [];
|
|
589
|
+
arrayPoints[index] = {
|
|
590
|
+
x: ((_a = pointsStart[index]) === null || _a === void 0 ? void 0 : _a.x) + localDx,
|
|
591
|
+
y: ((_b = pointsStart[index]) === null || _b === void 0 ? void 0 : _b.y) + localDy,
|
|
592
|
+
};
|
|
593
|
+
const newPointsAttr = arrayToSvgPointsAttr(arrayPoints);
|
|
594
|
+
element === null || element === void 0 ? void 0 : element.setAttribute("points", newPointsAttr);
|
|
595
|
+
};
|
|
596
|
+
if (targetPointPolygon && targetGroup) {
|
|
597
|
+
onResizePolygon(pos);
|
|
598
|
+
}
|
|
599
|
+
//ROTATE SELECTION BOX
|
|
600
|
+
const onRotateSelectionBox = (pos) => {
|
|
601
|
+
var _a, _b, _c, _d;
|
|
602
|
+
console.log("rotate selection");
|
|
603
|
+
const selectionLines = (_a = svgRef.current) === null || _a === void 0 ? void 0 : _a.querySelector("#selection-lines");
|
|
604
|
+
const circleHelper = svg.querySelector("#circle-help");
|
|
605
|
+
const lineHelper = svg.querySelector("#line-help");
|
|
606
|
+
const inner = (_b = selectionLines === null || selectionLines === void 0 ? void 0 : selectionLines.children) === null || _b === void 0 ? void 0 : _b[0];
|
|
607
|
+
const x0 = (selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.x) || 0;
|
|
608
|
+
const y0 = (selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.y) || 0;
|
|
609
|
+
const w0 = (selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.width) || 0;
|
|
610
|
+
const h0 = (selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.height) || 0;
|
|
611
|
+
const bbox = getGlobalBBox(svg, inner);
|
|
612
|
+
const cx = bbox.x + bbox.width / 2;
|
|
613
|
+
const cy = bbox.y + bbox.height / 2;
|
|
614
|
+
//start center
|
|
615
|
+
const dx0 = x - cx;
|
|
616
|
+
const dy0 = y - cy;
|
|
617
|
+
// ✅ ANGLE DARI CENTER
|
|
618
|
+
const dx = pos.x - cx;
|
|
619
|
+
const dy = pos.y - cy;
|
|
620
|
+
//start angle
|
|
621
|
+
const startAngle = Math.atan2(dy0, dx0);
|
|
622
|
+
const currentAngle = Math.atan2(dy, dx);
|
|
623
|
+
const newAngle = normalizeAngle(0 + ((currentAngle - startAngle) * 180) / Math.PI);
|
|
624
|
+
const angle = (0 * Math.PI) / 180;
|
|
625
|
+
// helper line
|
|
626
|
+
const centerX = w0 / 2;
|
|
627
|
+
const centerY = h0 / 2;
|
|
628
|
+
const cos = Math.cos(angle);
|
|
629
|
+
const sin = Math.sin(angle);
|
|
630
|
+
// GLOBAL → LOCAL
|
|
631
|
+
const localDx = dx * cos + dy * sin;
|
|
632
|
+
const localDy = -dx * sin + dy * cos;
|
|
633
|
+
// helper (LOCAL SPACE)
|
|
634
|
+
const x2 = centerX + localDx;
|
|
635
|
+
const y2 = centerY + localDy;
|
|
636
|
+
lineHelper === null || lineHelper === void 0 ? void 0 : lineHelper.setAttribute("x1", `${centerX}`);
|
|
637
|
+
lineHelper === null || lineHelper === void 0 ? void 0 : lineHelper.setAttribute("y1", `${centerY}`);
|
|
638
|
+
lineHelper === null || lineHelper === void 0 ? void 0 : lineHelper.setAttribute("x2", `${x2}`);
|
|
639
|
+
lineHelper === null || lineHelper === void 0 ? void 0 : lineHelper.setAttribute("y2", `${y2}`);
|
|
640
|
+
circleHelper === null || circleHelper === void 0 ? void 0 : circleHelper.setAttribute("cx", `${x2}`);
|
|
641
|
+
circleHelper === null || circleHelper === void 0 ? void 0 : circleHelper.setAttribute("cy", `${y2}`);
|
|
642
|
+
(_c = selectionLines === null || selectionLines === void 0 ? void 0 : selectionLines.children) === null || _c === void 0 ? void 0 : _c[0].setAttribute("transform", `rotate(${newAngle}, 0, 0)`);
|
|
643
|
+
const { tx, ty } = stabilizeRotation(x0, y0, w0, h0, 0, newAngle);
|
|
644
|
+
selectionLines === null || selectionLines === void 0 ? void 0 : selectionLines.setAttribute("transform", `translate(${tx}, ${ty}) `);
|
|
645
|
+
// ROTATE ALL ELEMENT IN SELECTION
|
|
646
|
+
const allID = (_d = dataElementSelectionGroupRef.current) === null || _d === void 0 ? void 0 : _d.map((el) => el.id);
|
|
647
|
+
const deltaAngle = newAngle - 0;
|
|
648
|
+
const rad = (deltaAngle * Math.PI) / 180;
|
|
649
|
+
const cosA = Math.cos(rad);
|
|
650
|
+
const sinA = Math.sin(rad);
|
|
651
|
+
const allGroupsAtrribute = getAttributeElements(svg, allID);
|
|
652
|
+
allGroupsAtrribute.forEach(({ g, inner }, i) => {
|
|
653
|
+
var _a;
|
|
654
|
+
const el = (_a = dataElementSelectionGroupRef.current) === null || _a === void 0 ? void 0 : _a[i];
|
|
655
|
+
if (!el)
|
|
656
|
+
return;
|
|
657
|
+
const rotateBefore = normalizeAngle(el.rotation);
|
|
658
|
+
const ex = el.x;
|
|
659
|
+
const ey = el.y;
|
|
660
|
+
// 🔑 ROTATE AROUND SELECTION CENTER
|
|
661
|
+
const dx = ex - cx;
|
|
662
|
+
const dy = ey - cy;
|
|
663
|
+
const nx = cx + dx * cosA - dy * sinA;
|
|
664
|
+
const ny = cy + dx * sinA + dy * cosA;
|
|
665
|
+
g.setAttribute("data-is-rotating", "1");
|
|
666
|
+
inner.setAttribute("transform", `rotate(${normalizeAngle(rotateBefore + deltaAngle)}, 0, 0)`);
|
|
667
|
+
g.setAttribute("transform", `translate(${nx}, ${ny})`);
|
|
668
|
+
});
|
|
669
|
+
};
|
|
670
|
+
if (isRotateSelectionBox) {
|
|
671
|
+
onRotateSelectionBox(pos);
|
|
672
|
+
}
|
|
673
|
+
//RESIZE SELECTION BOX
|
|
674
|
+
const onResizeSelectionBox = (ev) => {
|
|
675
|
+
var _a, _b;
|
|
676
|
+
console.log("RESIZE SELECTION BOX");
|
|
677
|
+
const dx = pos.x - x;
|
|
678
|
+
const dy = pos.y - y;
|
|
679
|
+
isResizeSelectionRef.current = true;
|
|
680
|
+
const oldSel = {
|
|
681
|
+
x: selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.x,
|
|
682
|
+
y: selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.y,
|
|
683
|
+
width: selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.width,
|
|
684
|
+
height: selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.height,
|
|
685
|
+
};
|
|
686
|
+
const allID = (_a = dataElementSelectionGroupRef.current) === null || _a === void 0 ? void 0 : _a.map((el) => el.id);
|
|
687
|
+
const allDataRealSelection = (_b = [
|
|
688
|
+
...componentsState,
|
|
689
|
+
...extraComponentsState,
|
|
690
|
+
]) === null || _b === void 0 ? void 0 : _b.filter((el) => allID.includes(el.id));
|
|
691
|
+
const allGroupsAttribute = getAttributeElements(svg, allID);
|
|
692
|
+
const resultSelection = resizeBox({
|
|
693
|
+
box: oldSel,
|
|
694
|
+
dx,
|
|
695
|
+
dy,
|
|
696
|
+
rotate: 0,
|
|
697
|
+
handle: resizeSide,
|
|
698
|
+
});
|
|
699
|
+
updateSelectionBox(svg, resultSelection);
|
|
700
|
+
const scaleX = resultSelection.width / oldSel.width;
|
|
701
|
+
const scaleY = resultSelection.height / oldSel.height;
|
|
702
|
+
allGroupsAttribute.forEach(({ g, element, inner, seatGroup, seats }, i) => {
|
|
703
|
+
var _a, _b;
|
|
704
|
+
const activeId = JSON.parse(g === null || g === void 0 ? void 0 : g.getAttribute("data-id"));
|
|
705
|
+
const elementOld = allDataRealSelection === null || allDataRealSelection === void 0 ? void 0 : allDataRealSelection.find((el) => el.id == activeId);
|
|
706
|
+
const { x: translateX, y: translateY } = getTranslate(g);
|
|
707
|
+
const newWidth = (elementOld === null || elementOld === void 0 ? void 0 : elementOld.width) * scaleX;
|
|
708
|
+
const newHeight = (elementOld === null || elementOld === void 0 ? void 0 : elementOld.height) * scaleY;
|
|
709
|
+
// Jarak relatif element dari pojok kiri atas selection (sebelum resize)
|
|
710
|
+
const relativeX = (elementOld === null || elementOld === void 0 ? void 0 : elementOld.x) - oldSel.x;
|
|
711
|
+
const relativeY = (elementOld === null || elementOld === void 0 ? void 0 : elementOld.y) - oldSel.y;
|
|
712
|
+
// Jarak relatif baru (sesudah resize)
|
|
713
|
+
const newX = resultSelection.x + relativeX * scaleX;
|
|
714
|
+
const newY = resultSelection.y + relativeY * scaleY;
|
|
715
|
+
const relativePoinst = ((_a = elementOld === null || elementOld === void 0 ? void 0 : elementOld.points) === null || _a === void 0 ? void 0 : _a.length) !== 0 &&
|
|
716
|
+
((_b = elementOld === null || elementOld === void 0 ? void 0 : elementOld.points) === null || _b === void 0 ? void 0 : _b.map((point) => {
|
|
717
|
+
const { x, y } = point;
|
|
718
|
+
const relativeX = x - oldSel.x;
|
|
719
|
+
const relativeY = y - oldSel.y;
|
|
720
|
+
return {
|
|
721
|
+
x: resultSelection.x + relativeX * scaleX,
|
|
722
|
+
y: resultSelection.y + relativeY * scaleY,
|
|
723
|
+
};
|
|
724
|
+
}));
|
|
725
|
+
const newElement = {
|
|
726
|
+
x: newX,
|
|
727
|
+
y: newY,
|
|
728
|
+
width: newWidth,
|
|
729
|
+
height: newHeight,
|
|
730
|
+
points: relativePoinst,
|
|
731
|
+
};
|
|
732
|
+
if (seats.length !== 0) {
|
|
733
|
+
const seatsPositions = elementOld === null || elementOld === void 0 ? void 0 : elementOld.seatPositions;
|
|
734
|
+
const openSpace = elementOld === null || elementOld === void 0 ? void 0 : elementOld.openSpace;
|
|
735
|
+
if ((elementOld === null || elementOld === void 0 ? void 0 : elementOld.shape) === "table-seat-circle") {
|
|
736
|
+
resizeSeatCircle({
|
|
737
|
+
seatCount: elementOld === null || elementOld === void 0 ? void 0 : elementOld.seatCount,
|
|
738
|
+
r: 10,
|
|
739
|
+
openSpace,
|
|
740
|
+
newElement,
|
|
741
|
+
seats,
|
|
742
|
+
seatGroup,
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
else if ((elementOld === null || elementOld === void 0 ? void 0 : elementOld.shape) === "table-seat-square") {
|
|
746
|
+
resizeSeatSquare({
|
|
747
|
+
seatsPositions,
|
|
748
|
+
r: 10,
|
|
749
|
+
openSpace,
|
|
750
|
+
newElement,
|
|
751
|
+
seats,
|
|
752
|
+
seatGroup,
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
applyResizeToSvgElement(element, g, newElement);
|
|
757
|
+
});
|
|
758
|
+
};
|
|
759
|
+
if (downAtResizePositionAndHasSelectionBox)
|
|
760
|
+
onResizeSelectionBox(ev);
|
|
761
|
+
//SELECTION BOX MOVE
|
|
762
|
+
const onMoveSelectionBox = () => {
|
|
763
|
+
var _a, _b;
|
|
764
|
+
console.log("move selection box");
|
|
765
|
+
const allID = (_a = dataElementSelectionGroupRef.current) === null || _a === void 0 ? void 0 : _a.map((el) => el.id);
|
|
766
|
+
const allDataRealSelection = (_b = [
|
|
767
|
+
...componentsState,
|
|
768
|
+
...extraComponentsState,
|
|
769
|
+
]) === null || _b === void 0 ? void 0 : _b.filter((el) => allID.includes(el.id));
|
|
770
|
+
allDataRealSelection.forEach((item) => {
|
|
771
|
+
const { g } = getAttributeElement(svg, item.id);
|
|
772
|
+
const newX = pos.x - x;
|
|
773
|
+
const newY = pos.y - y;
|
|
774
|
+
g.setAttribute("transform", `translate(${item.x + newX}, ${item.y + newY})`);
|
|
775
|
+
});
|
|
776
|
+
const newX = pos.x - x;
|
|
777
|
+
const newY = pos.y - y;
|
|
778
|
+
updateSelectionBox(svg, {
|
|
779
|
+
x: (selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.x) + newX,
|
|
780
|
+
y: (selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.y) + newY,
|
|
781
|
+
width: selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.width,
|
|
782
|
+
height: selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.height,
|
|
783
|
+
});
|
|
784
|
+
};
|
|
785
|
+
if (downOutResizePositionAndInSelectionBox && !isRotateSelectionBox)
|
|
786
|
+
onMoveSelectionBox();
|
|
787
|
+
// MAKING SELECTION BOX MOVE
|
|
788
|
+
const onMakeSelectionBox = (ev) => {
|
|
789
|
+
var _a, _b;
|
|
790
|
+
console.log("lagi bikin selection box");
|
|
791
|
+
const svgSize = svg.getBoundingClientRect();
|
|
792
|
+
let selectionBoxGhost = svg.querySelector("#selection-box-ghost");
|
|
793
|
+
const selX = Math.min(pos.x, x);
|
|
794
|
+
const selY = Math.min(pos.y, y);
|
|
795
|
+
const selW = Math.abs(pos.x - x);
|
|
796
|
+
const selH = Math.abs(pos.y - y);
|
|
797
|
+
selectionBoxGhost === null || selectionBoxGhost === void 0 ? void 0 : selectionBoxGhost.setAttribute("x", String(selX));
|
|
798
|
+
selectionBoxGhost === null || selectionBoxGhost === void 0 ? void 0 : selectionBoxGhost.setAttribute("y", String(selY));
|
|
799
|
+
selectionBoxGhost === null || selectionBoxGhost === void 0 ? void 0 : selectionBoxGhost.setAttribute("width", String(selW));
|
|
800
|
+
selectionBoxGhost === null || selectionBoxGhost === void 0 ? void 0 : selectionBoxGhost.setAttribute("height", String(selH));
|
|
801
|
+
// FIND ALL COMPONENTS INSIDE SELECTION BOX
|
|
802
|
+
const allGroups = (_a = svgRef.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll("g[data-id]");
|
|
803
|
+
const selLeft = selX;
|
|
804
|
+
const selTop = selY;
|
|
805
|
+
const selectedIds = [...allGroups]
|
|
806
|
+
.map((g) => JSON === null || JSON === void 0 ? void 0 : JSON.parse((g === null || g === void 0 ? void 0 : g.getAttribute("data-id")) || "{}"))
|
|
807
|
+
.filter((d) => {
|
|
808
|
+
const { g, element } = getAttributeElement(svg, d);
|
|
809
|
+
const box = getGlobalBBox(svg, element);
|
|
810
|
+
// console.log(
|
|
811
|
+
// box.x < selLeft + selW,
|
|
812
|
+
// "x",
|
|
813
|
+
// box.x + box.width > selLeft,
|
|
814
|
+
// "x2",
|
|
815
|
+
// box.y < selTop + selH,
|
|
816
|
+
// "y",
|
|
817
|
+
// box.y + box.height > selTop,
|
|
818
|
+
// "y2"
|
|
819
|
+
// );
|
|
820
|
+
return ((box === null || box === void 0 ? void 0 : box.x) < selLeft + selW &&
|
|
821
|
+
(box === null || box === void 0 ? void 0 : box.x) + box.width > selLeft &&
|
|
822
|
+
(box === null || box === void 0 ? void 0 : box.y) < selTop + selH &&
|
|
823
|
+
(box === null || box === void 0 ? void 0 : box.y) + box.height > selTop);
|
|
824
|
+
})
|
|
825
|
+
.map((d) => `${d}`);
|
|
826
|
+
if (selectedIds.length === 0)
|
|
827
|
+
return;
|
|
828
|
+
const selectedComps = (_b = [...componentsState, ...extraComponentsState]
|
|
829
|
+
.filter((c) => selectedIds.map(String).includes(String(c.id)))) === null || _b === void 0 ? void 0 : _b.map((item) => {
|
|
830
|
+
const { g } = getAttributeElement(svg, item.id);
|
|
831
|
+
const { x, y } = getTranslate(g);
|
|
832
|
+
const box = getGlobalBBox(svg, g);
|
|
833
|
+
return Object.assign(Object.assign({}, item), {
|
|
834
|
+
// x: box.x,
|
|
835
|
+
// y: box.y,
|
|
836
|
+
width: box.width, height: box.height });
|
|
837
|
+
});
|
|
838
|
+
dataElementSelectionGroupRef.current = selectedComps;
|
|
839
|
+
};
|
|
840
|
+
if (downBeforeHasSelectionBox)
|
|
841
|
+
onMakeSelectionBox(ev);
|
|
842
|
+
// CREATE GHOST ELEMENT ---
|
|
843
|
+
const onDrawNewElements = toolElement.includes(activeTool) && isCreateElementRef.current;
|
|
844
|
+
if (onDrawNewElements) {
|
|
845
|
+
const ghost = (_a = svgRef.current) === null || _a === void 0 ? void 0 : _a.querySelector("#ghost-element-create");
|
|
846
|
+
if (!ghost)
|
|
847
|
+
return;
|
|
848
|
+
const data = JSON.parse(ghost.getAttribute("data-table") || "{}");
|
|
849
|
+
const { x: ox, y: oy } = data;
|
|
850
|
+
// ---- HITUNG RECT BARU ----
|
|
851
|
+
const x1 = Math.min(ox, pos.x);
|
|
852
|
+
const y1 = Math.min(oy, pos.y);
|
|
853
|
+
const x2 = Math.max(ox, pos.x);
|
|
854
|
+
const y2 = Math.max(oy, pos.y);
|
|
855
|
+
const newX = x1;
|
|
856
|
+
const newY = y1;
|
|
857
|
+
const newW = x2 - x1;
|
|
858
|
+
const newH = y2 - y1;
|
|
859
|
+
// ---- RECT ----
|
|
860
|
+
if (["square", "table-seat-circle"].includes(activeTool)) {
|
|
861
|
+
ghost.setAttribute("x", String(newX));
|
|
862
|
+
ghost.setAttribute("y", String(newY));
|
|
863
|
+
ghost.setAttribute("width", String(newW));
|
|
864
|
+
ghost.setAttribute("height", String(newH));
|
|
865
|
+
}
|
|
866
|
+
// ---- CIRCLE (ambil dari bounding box) ----
|
|
867
|
+
if (activeTool === "circle") {
|
|
868
|
+
const cx = newX + newW / 2;
|
|
869
|
+
const cy = newY + newH / 2;
|
|
870
|
+
const r = Math.min(newW, newH) / 2;
|
|
871
|
+
ghost.setAttribute("cx", String(cx));
|
|
872
|
+
ghost.setAttribute("cy", String(cy));
|
|
873
|
+
ghost.setAttribute("r", String(r));
|
|
874
|
+
}
|
|
875
|
+
// ---- UPDATE DATA TABLE ----
|
|
876
|
+
ghost.setAttribute("data-table", JSON.stringify(Object.assign(Object.assign({}, data), { x: newX, y: newY, width: newW, height: newH })));
|
|
877
|
+
}
|
|
878
|
+
// RESIZE GHOST SINGLE ELEMENT ---
|
|
879
|
+
const onResize = (ev) => {
|
|
880
|
+
var _a, _b;
|
|
881
|
+
console.log("lagi resize single element");
|
|
882
|
+
const activeId = selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id;
|
|
883
|
+
const svg = svgRef.current;
|
|
884
|
+
console.log({ svg, activeId });
|
|
885
|
+
const { g, element, inner, seats, seatGroup } = getAttributeElement(svg, activeId);
|
|
886
|
+
const elementSelect = {
|
|
887
|
+
x: selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.x,
|
|
888
|
+
y: selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.y,
|
|
889
|
+
width: selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.width,
|
|
890
|
+
height: selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.height,
|
|
891
|
+
seatPositions: selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.seatPositions,
|
|
892
|
+
seatCount: selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.seatCount,
|
|
893
|
+
openSpace: selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.openSpace,
|
|
894
|
+
points: selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.points,
|
|
895
|
+
};
|
|
896
|
+
const oldSel = {
|
|
897
|
+
x: selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.x,
|
|
898
|
+
y: selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.y,
|
|
899
|
+
width: selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.width,
|
|
900
|
+
height: selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.height,
|
|
901
|
+
};
|
|
902
|
+
const dx = pos.x - x;
|
|
903
|
+
const dy = pos.y - y;
|
|
904
|
+
const resultSelection = resizeBox({
|
|
905
|
+
box: oldSel,
|
|
906
|
+
dx,
|
|
907
|
+
dy,
|
|
908
|
+
rotate: 0,
|
|
909
|
+
handle: resizeSide,
|
|
910
|
+
});
|
|
911
|
+
updateSelectionBox(svg, resultSelection, activeId);
|
|
912
|
+
const scaleX = resultSelection.width / oldSel.width;
|
|
913
|
+
const scaleY = resultSelection.height / oldSel.height;
|
|
914
|
+
const newWidth = elementSelect.width * scaleX;
|
|
915
|
+
const newHeight = elementSelect.height * scaleY;
|
|
916
|
+
// Jarak relatif element dari pojok kiri atas selection (sebelum resize)
|
|
917
|
+
const relativeX = elementSelect.x - oldSel.x;
|
|
918
|
+
const relativeY = elementSelect.y - oldSel.y;
|
|
919
|
+
// Jarak relatif baru (sesudah resize)
|
|
920
|
+
const newX = resultSelection.x + relativeX * scaleX;
|
|
921
|
+
const newY = resultSelection.y + relativeY * scaleY;
|
|
922
|
+
const relativePoinst = ((_a = elementSelect === null || elementSelect === void 0 ? void 0 : elementSelect.points) === null || _a === void 0 ? void 0 : _a.length) !== 0 &&
|
|
923
|
+
((_b = elementSelect === null || elementSelect === void 0 ? void 0 : elementSelect.points) === null || _b === void 0 ? void 0 : _b.map((point) => {
|
|
924
|
+
const { x, y } = point;
|
|
925
|
+
const relativeX = x - oldSel.x;
|
|
926
|
+
const relativeY = y - oldSel.y;
|
|
927
|
+
return {
|
|
928
|
+
x: resultSelection.x + relativeX * scaleX,
|
|
929
|
+
y: resultSelection.y + relativeY * scaleY,
|
|
930
|
+
};
|
|
931
|
+
}));
|
|
932
|
+
const newElement = {
|
|
933
|
+
x: newX,
|
|
934
|
+
y: newY,
|
|
935
|
+
width: newWidth,
|
|
936
|
+
height: newHeight,
|
|
937
|
+
points: relativePoinst,
|
|
938
|
+
};
|
|
939
|
+
if (seats.length !== 0) {
|
|
940
|
+
if ((selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.shape) === "table-seat-circle") {
|
|
941
|
+
resizeSeatCircle({
|
|
942
|
+
seatCount: elementSelect === null || elementSelect === void 0 ? void 0 : elementSelect.seatCount,
|
|
943
|
+
r: 10,
|
|
944
|
+
openSpace: elementSelect === null || elementSelect === void 0 ? void 0 : elementSelect.openSpace,
|
|
945
|
+
newElement,
|
|
946
|
+
seats,
|
|
947
|
+
seatGroup,
|
|
948
|
+
});
|
|
949
|
+
}
|
|
950
|
+
else if ((selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.shape) === "table-seat-square") {
|
|
951
|
+
resizeSeatSquare({
|
|
952
|
+
seatsPositions: elementSelect.seatPositions,
|
|
953
|
+
r: 10,
|
|
954
|
+
newElement,
|
|
955
|
+
openSpace: elementSelect.openSpace,
|
|
956
|
+
seats,
|
|
957
|
+
seatGroup,
|
|
958
|
+
});
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
applyResizeToSvgElement(element, g, newElement);
|
|
962
|
+
isResizeRef.current = true;
|
|
963
|
+
};
|
|
964
|
+
// const hasSelectedOneElement =
|
|
965
|
+
// !isEmpty(selectedComponent) &&
|
|
966
|
+
// onResizeSelectionRef.current &&
|
|
967
|
+
// downAtResizePosition;
|
|
968
|
+
if (!isEmpty(selectedComponent) && isMightResizeElement)
|
|
969
|
+
onResize(ev);
|
|
970
|
+
//ROTATE
|
|
971
|
+
const onRotate = (ev) => {
|
|
972
|
+
console.log("rotate single element");
|
|
973
|
+
const svg = svgRef.current;
|
|
974
|
+
if (!svg || !selectedComponent)
|
|
975
|
+
return;
|
|
976
|
+
const lineHelper = svg.querySelector("#line-help");
|
|
977
|
+
const circleHelper = svg.querySelector("#circle-help");
|
|
978
|
+
const { inner, g } = getAttributeElement(svg, selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id);
|
|
979
|
+
if (!inner || !g)
|
|
980
|
+
return;
|
|
981
|
+
// mouse → SVG space
|
|
982
|
+
// 🔴 GLOBAL BBOX (INI KUNCI)
|
|
983
|
+
const bbox = getGlobalBBox(svg, inner);
|
|
984
|
+
const boxSelection = getGlobalBBox(svg, g);
|
|
985
|
+
if (!bbox)
|
|
986
|
+
return;
|
|
987
|
+
const cx = bbox.x + bbox.width / 2;
|
|
988
|
+
const cy = bbox.y + bbox.height / 2;
|
|
989
|
+
// vector awal & sekarang (GLOBAL)
|
|
990
|
+
const dx0 = x - cx;
|
|
991
|
+
const dy0 = y - cy;
|
|
992
|
+
const dx = pos.x - cx;
|
|
993
|
+
const dy = pos.y - cy;
|
|
994
|
+
const startAngle = Math.atan2(dy0, dx0);
|
|
995
|
+
const currentAngle = Math.atan2(dy, dx);
|
|
996
|
+
const newAngle = (selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.rotation) +
|
|
997
|
+
((currentAngle - startAngle) * 180) / Math.PI;
|
|
998
|
+
// helper line
|
|
999
|
+
console.log({ selectedLines }, "haduuuhh");
|
|
1000
|
+
const centerX = selectedLines.width / 2;
|
|
1001
|
+
const centerY = selectedLines.height / 2;
|
|
1002
|
+
const angle = (0 * Math.PI) / 180;
|
|
1003
|
+
const cos = Math.cos(angle);
|
|
1004
|
+
const sin = Math.sin(angle);
|
|
1005
|
+
// GLOBAL → LOCAL
|
|
1006
|
+
const localDx = dx * cos + dy * sin;
|
|
1007
|
+
const localDy = -dx * sin + dy * cos;
|
|
1008
|
+
// helper (LOCAL SPACE)
|
|
1009
|
+
const x2 = centerX + localDx;
|
|
1010
|
+
const y2 = centerY + localDy;
|
|
1011
|
+
console.log({ centerX, centerY, localDx, localDy });
|
|
1012
|
+
lineHelper === null || lineHelper === void 0 ? void 0 : lineHelper.setAttribute("x1", `${centerX}`);
|
|
1013
|
+
lineHelper === null || lineHelper === void 0 ? void 0 : lineHelper.setAttribute("y1", `${centerY}`);
|
|
1014
|
+
lineHelper === null || lineHelper === void 0 ? void 0 : lineHelper.setAttribute("x2", `${x2}`);
|
|
1015
|
+
lineHelper === null || lineHelper === void 0 ? void 0 : lineHelper.setAttribute("y2", `${y2}`);
|
|
1016
|
+
circleHelper === null || circleHelper === void 0 ? void 0 : circleHelper.setAttribute("cx", `${x2}`);
|
|
1017
|
+
circleHelper === null || circleHelper === void 0 ? void 0 : circleHelper.setAttribute("cy", `${y2}`);
|
|
1018
|
+
// rotate di local space
|
|
1019
|
+
inner.setAttribute("transform", `rotate(${newAngle}, 0, 0)`);
|
|
1020
|
+
// stabilize translate
|
|
1021
|
+
const { tx, ty } = selectedComponent.shape === "polygon"
|
|
1022
|
+
? stabilizeTranslateOnRotate({
|
|
1023
|
+
points: selectedComponentProps === null || selectedComponentProps === void 0 ? void 0 : selectedComponentProps.points,
|
|
1024
|
+
oldAngle: selectedComponent.rotation,
|
|
1025
|
+
newAngle,
|
|
1026
|
+
tx: selectedComponent.x,
|
|
1027
|
+
ty: selectedComponent.y,
|
|
1028
|
+
})
|
|
1029
|
+
: stabilizeRotation(selectedComponent.x, selectedComponent.y, selectedComponent.width, selectedComponent.height, selectedComponent.rotation, newAngle);
|
|
1030
|
+
g.setAttribute("transform", `translate(${tx}, ${ty})`);
|
|
1031
|
+
ghostRotateElement.current = newAngle;
|
|
1032
|
+
updateSelectionBox(svg, boxSelection, selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id, true);
|
|
1033
|
+
};
|
|
1034
|
+
if (targetRotate && !isRotateSelectionBox)
|
|
1035
|
+
onRotate(ev);
|
|
1036
|
+
const onMove = (ev) => {
|
|
1037
|
+
console.log("movv");
|
|
1038
|
+
// const selectionLines = svg.querySelector("#selection-lines");
|
|
1039
|
+
const dx = ev.clientX - startX;
|
|
1040
|
+
const dy = ev.clientY - startY;
|
|
1041
|
+
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
1042
|
+
// onPanning(ev);
|
|
1043
|
+
if (!hasMoved && distance > 0) {
|
|
1044
|
+
// only move ghost if the mouse has moved more than 5 pixels
|
|
1045
|
+
hasMoved = true;
|
|
1046
|
+
}
|
|
1047
|
+
const newX = pos.x - offset.x;
|
|
1048
|
+
const newY = pos.y - offset.y;
|
|
1049
|
+
// let activeId = JSON.parse(targetGroup?.getAttribute("data-id") || "{}");
|
|
1050
|
+
const isMatchWithSelection = activeId === (selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id);
|
|
1051
|
+
const { g } = getAttributeElement(svg, activeId);
|
|
1052
|
+
console.log({ activeId });
|
|
1053
|
+
g === null || g === void 0 ? void 0 : g.setAttribute("transform", `translate(${newX}, ${newY})`);
|
|
1054
|
+
if (isMatchWithSelection) {
|
|
1055
|
+
const boxSelection = getGlobalBBox(svg, g);
|
|
1056
|
+
updateSelectionBox(svg, boxSelection, activeId);
|
|
1057
|
+
}
|
|
1058
|
+
};
|
|
1059
|
+
const moveSingleElement = (isMightMove &&
|
|
1060
|
+
!(!isEmpty(selectedComponent) && !isMightResizeElement) &&
|
|
1061
|
+
!targetRotate) ||
|
|
1062
|
+
(isMightMoveOneElementSelection && !isMightResizeElement) ||
|
|
1063
|
+
(isMightMove && !isEmpty(selectedComponent) && !isMightResizeElement);
|
|
1064
|
+
if (moveSingleElement) {
|
|
1065
|
+
onMove(ev);
|
|
1066
|
+
}
|
|
1067
|
+
};
|
|
1068
|
+
const pointerHandleUp = (e) => {
|
|
1069
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
1070
|
+
//POLYGON RESIZE
|
|
1071
|
+
if (targetSelection) {
|
|
1072
|
+
console.log("KLIK UP SELECTION");
|
|
1073
|
+
//show
|
|
1074
|
+
dispatch({ type: "panel/setShow", payload: true });
|
|
1075
|
+
}
|
|
1076
|
+
if (targetPointPolygon && targetGroup) {
|
|
1077
|
+
console.log("KLIK UP POINT POLYGON");
|
|
1078
|
+
const { element } = getAttributeElement(svg, targetGroup.dataset.id);
|
|
1079
|
+
const points = element === null || element === void 0 ? void 0 : element.getAttribute("points");
|
|
1080
|
+
const pointsArray = pointsStringToArray(points);
|
|
1081
|
+
const findById = [...componentsState, ...extraComponentsState].find((c) => c.id === targetGroup.dataset.id);
|
|
1082
|
+
const newDataComponent = Object.assign(Object.assign({}, findById), { points: pointsArray });
|
|
1083
|
+
updateComponentAttribute(newDataComponent);
|
|
1084
|
+
setSelectedComponent(newDataComponent);
|
|
1085
|
+
dispatch({
|
|
1086
|
+
type: "panel/setSelectedComponent",
|
|
1087
|
+
payload: newDataComponent,
|
|
1088
|
+
});
|
|
1089
|
+
selectionLinesRef.current = newDataComponent;
|
|
1090
|
+
}
|
|
1091
|
+
//POLYGON
|
|
1092
|
+
const isInitialPolyGon = activeTool === "polygon" && (selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.shape) === "polygon";
|
|
1093
|
+
if (isInitialPolyGon) {
|
|
1094
|
+
console.log("Create polygon");
|
|
1095
|
+
const closing = isClosingPolygon(x, y, selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.points);
|
|
1096
|
+
const newCoord = closing
|
|
1097
|
+
? {
|
|
1098
|
+
x: (_a = selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.points[0]) === null || _a === void 0 ? void 0 : _a.x,
|
|
1099
|
+
y: (_b = selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.points[0]) === null || _b === void 0 ? void 0 : _b.y,
|
|
1100
|
+
}
|
|
1101
|
+
: { x, y };
|
|
1102
|
+
const newPoints = Object.assign(Object.assign({}, selectedComponent), { points: [...selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.points, newCoord] });
|
|
1103
|
+
(_c = svg.querySelector("#polyline-helper")) === null || _c === void 0 ? void 0 : _c.setAttribute("opacity", "1");
|
|
1104
|
+
if (closing && ((_d = selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.points) === null || _d === void 0 ? void 0 : _d.length) > 2) {
|
|
1105
|
+
const { g, inner } = getAttributeElement(svg, selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id);
|
|
1106
|
+
const { height, width } = getGlobalBBox(svg, inner);
|
|
1107
|
+
isOnMakePolygonRef.current = false;
|
|
1108
|
+
setSelectedComponent(null);
|
|
1109
|
+
dispatch({
|
|
1110
|
+
type: "panel/setSelectedComponent",
|
|
1111
|
+
payload: null,
|
|
1112
|
+
});
|
|
1113
|
+
polygonElementRef.current = [];
|
|
1114
|
+
addComponents(Object.assign(Object.assign({}, newPoints), { x: 0, y: 0, width, height }));
|
|
1115
|
+
(_e = svg.querySelector("#selection-box-ghost")) === null || _e === void 0 ? void 0 : _e.remove();
|
|
1116
|
+
const polyline = svg.querySelector("#polyline-helper");
|
|
1117
|
+
// polyline?.remove();
|
|
1118
|
+
console.log({ polyline });
|
|
1119
|
+
(_f = svg.querySelector("#polyline-helper")) === null || _f === void 0 ? void 0 : _f.setAttribute("opacity", "0");
|
|
1120
|
+
}
|
|
1121
|
+
else {
|
|
1122
|
+
setSelectedComponent(newPoints);
|
|
1123
|
+
dispatch({
|
|
1124
|
+
type: "panel/setSelectedComponent",
|
|
1125
|
+
payload: newPoints,
|
|
1126
|
+
});
|
|
1127
|
+
polygonElementRef.current = newPoints;
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
// ROTATE
|
|
1131
|
+
if (targetRotate && !isRotateSelectionBox) {
|
|
1132
|
+
console.log("KLIK UP ROTATE");
|
|
1133
|
+
const activeId = selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id;
|
|
1134
|
+
const { g, inner, element } = getAttributeElement(svg, activeId);
|
|
1135
|
+
const boxLines = getGlobalBBox(svg, g);
|
|
1136
|
+
const findById = [...componentsState, ...extraComponentsState].find((c) => c.id === activeId);
|
|
1137
|
+
const { x, y } = getTranslate(g);
|
|
1138
|
+
const newDataComponent = Object.assign(Object.assign({}, findById), { x,
|
|
1139
|
+
y, rotation: ghostRotateElement.current });
|
|
1140
|
+
const boxSelection = Object.assign(Object.assign(Object.assign({
|
|
1141
|
+
// x,
|
|
1142
|
+
// y,
|
|
1143
|
+
// width,
|
|
1144
|
+
// height,
|
|
1145
|
+
// rotation: ghostRotateElement.current,
|
|
1146
|
+
shape: "selection-box", id: `${Date.now()}` }, findById), boxLines), { rotation: 0 });
|
|
1147
|
+
if (boxLines)
|
|
1148
|
+
setSelectedLines(boxSelection);
|
|
1149
|
+
updateComponentAttribute(newDataComponent);
|
|
1150
|
+
setSelectedComponent(newDataComponent);
|
|
1151
|
+
dispatch({
|
|
1152
|
+
type: "panel/setSelectedComponent",
|
|
1153
|
+
payload: newDataComponent,
|
|
1154
|
+
});
|
|
1155
|
+
//LOGIC FOR SET SHOW
|
|
1156
|
+
dispatch({ type: "panel/setShow", payload: false });
|
|
1157
|
+
}
|
|
1158
|
+
//CREATE NEW ELEMENT
|
|
1159
|
+
if (toolElement.includes(activeTool) && isCreateElementRef.current) {
|
|
1160
|
+
console.log("CREATE new element");
|
|
1161
|
+
const ghostElementNew = (_g = svgRef.current) === null || _g === void 0 ? void 0 : _g.querySelector("#ghost-element-create");
|
|
1162
|
+
if (!ghostElementNew)
|
|
1163
|
+
return;
|
|
1164
|
+
const dataOriginal = JSON.parse(ghostElementNew.getAttribute("data-table") || "{}");
|
|
1165
|
+
const newComponent = Object.assign(Object.assign({ id: `${Date.now()}` }, dataOriginal), { seatCount: 4 });
|
|
1166
|
+
const newExtraComponent = [...extraComponentsState, newComponent];
|
|
1167
|
+
//ADD TO REDUX
|
|
1168
|
+
setExtraComponentsState(newExtraComponent);
|
|
1169
|
+
// setComponentsState(newComponentState);
|
|
1170
|
+
addComponents(newComponent);
|
|
1171
|
+
// syncFromLocalToRedux(newComponentState);
|
|
1172
|
+
//REMOVE GHOST ELEMENT
|
|
1173
|
+
(_h = svgRef.current) === null || _h === void 0 ? void 0 : _h.querySelectorAll("#ghost-element-create").forEach((el) => el.remove());
|
|
1174
|
+
isCreateElementRef.current = false;
|
|
1175
|
+
}
|
|
1176
|
+
// CREATE POLYGON
|
|
1177
|
+
const hasSelectedOneElement = !isEmpty(selectedComponent) &&
|
|
1178
|
+
onResizeSelectionRef.current &&
|
|
1179
|
+
downAtResizePosition;
|
|
1180
|
+
const idDataset = targetGroup === null || targetGroup === void 0 ? void 0 : targetGroup.dataset.id;
|
|
1181
|
+
const isSelectElement = !hasMoved &&
|
|
1182
|
+
!releaseGroupRef.current &&
|
|
1183
|
+
!targetRotate &&
|
|
1184
|
+
!hasSelectedOneElement &&
|
|
1185
|
+
idDataset &&
|
|
1186
|
+
activeTool === "select";
|
|
1187
|
+
if (isSelectElement) {
|
|
1188
|
+
//KLIK UP
|
|
1189
|
+
console.log("KLIK UP");
|
|
1190
|
+
const findById = [...componentsState, ...extraComponentsState].find((component) => component.id === idDataset);
|
|
1191
|
+
console.log({ findById });
|
|
1192
|
+
if (!findById) {
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
const { g } = getAttributeElement(svg, idDataset);
|
|
1196
|
+
if (shiftActive) {
|
|
1197
|
+
const allElementSelectionGroup = dataElementSelectionGroupRef.current;
|
|
1198
|
+
// HITUNG BOUNDING BOX
|
|
1199
|
+
let xs = [];
|
|
1200
|
+
let ys = [];
|
|
1201
|
+
let x2 = [];
|
|
1202
|
+
let y2 = [];
|
|
1203
|
+
allElementSelectionGroup.forEach((element) => {
|
|
1204
|
+
const activeId = element.id;
|
|
1205
|
+
const { g } = getAttributeElement(svg, activeId);
|
|
1206
|
+
const { x, y, width, height } = getGlobalBBox(svg, g);
|
|
1207
|
+
xs.push(x);
|
|
1208
|
+
ys.push(y);
|
|
1209
|
+
x2.push(x + width);
|
|
1210
|
+
y2.push(y + height);
|
|
1211
|
+
});
|
|
1212
|
+
const selectionBox = {
|
|
1213
|
+
x: Math.min(...xs),
|
|
1214
|
+
y: Math.min(...ys),
|
|
1215
|
+
width: Math.max(...x2) - Math.min(...xs),
|
|
1216
|
+
height: Math.max(...y2) - Math.min(...ys),
|
|
1217
|
+
stroke: "red",
|
|
1218
|
+
shape: "selection-box",
|
|
1219
|
+
fill: "transparent",
|
|
1220
|
+
id: `${Date.now()}`,
|
|
1221
|
+
rotation: 0,
|
|
1222
|
+
};
|
|
1223
|
+
selectionLinesRef.current = selectionBox;
|
|
1224
|
+
setSelectedLines(selectionBox);
|
|
1225
|
+
dispatch({
|
|
1226
|
+
type: "panel/setSelectedGroup",
|
|
1227
|
+
payload: allElementSelectionGroup,
|
|
1228
|
+
});
|
|
1229
|
+
setSelectedComponent(null);
|
|
1230
|
+
dispatch({
|
|
1231
|
+
type: "panel/setSelectedComponent",
|
|
1232
|
+
payload: null,
|
|
1233
|
+
});
|
|
1234
|
+
}
|
|
1235
|
+
else {
|
|
1236
|
+
console.log("SELECT SINGLE ELEMENT");
|
|
1237
|
+
dataElementSelectionGroupRef.current = [];
|
|
1238
|
+
const boxGroup = getGlobalBBox(svg, g);
|
|
1239
|
+
let boxSelection = Object.assign(Object.assign(Object.assign({}, findById), boxGroup), {
|
|
1240
|
+
// x,
|
|
1241
|
+
// y,
|
|
1242
|
+
// width,
|
|
1243
|
+
// height: height ,
|
|
1244
|
+
// width,
|
|
1245
|
+
// height,
|
|
1246
|
+
// x:boxGroup.x,
|
|
1247
|
+
// y:boxGroup.y,
|
|
1248
|
+
shape: "selection-box", rotation: 0 });
|
|
1249
|
+
console.log({ boxSelection });
|
|
1250
|
+
// if (findById?.shape === "polygon") {
|
|
1251
|
+
// const boxGroup = getGlobalBBox(svg, g);
|
|
1252
|
+
// boxSelection = {
|
|
1253
|
+
// ...boxSelection,
|
|
1254
|
+
// ...(boxGroup ? { x: boxGroup.x } : {}),
|
|
1255
|
+
// ...(boxGroup ? { y: boxGroup.y } : {}),
|
|
1256
|
+
// ...(boxGroup ? { width: boxGroup.width } : {}),
|
|
1257
|
+
// ...(boxGroup ? { height: boxGroup.height } : {}),
|
|
1258
|
+
// shape: "selection-box",
|
|
1259
|
+
// };
|
|
1260
|
+
// }
|
|
1261
|
+
if ((boxSelection === null || boxSelection === void 0 ? void 0 : boxSelection.width) &&
|
|
1262
|
+
(boxSelection === null || boxSelection === void 0 ? void 0 : boxSelection.height)) {
|
|
1263
|
+
console.log({ boxSelection });
|
|
1264
|
+
setSelectedLines(boxSelection);
|
|
1265
|
+
setSelectedComponent(findById);
|
|
1266
|
+
dispatch({
|
|
1267
|
+
type: "panel/setSelectedComponent",
|
|
1268
|
+
payload: findById,
|
|
1269
|
+
});
|
|
1270
|
+
selectionLinesRef.current = boxSelection;
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
//LOGIC FOR SET SHOW
|
|
1274
|
+
dispatch({ type: "panel/setShow", payload: true });
|
|
1275
|
+
}
|
|
1276
|
+
//UPDATE DATASET TO STATE IF RESIZE
|
|
1277
|
+
if (isMightResizeElement) {
|
|
1278
|
+
console.log("KLIK UP RESIZE SINGLE ELEMENT");
|
|
1279
|
+
const activeId = selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id;
|
|
1280
|
+
const svg = svgRef.current;
|
|
1281
|
+
const { g, element, points } = getAttributeElement(svg, activeId);
|
|
1282
|
+
const selectionBox = getGlobalBBox(svg, g);
|
|
1283
|
+
const { width, height } = getSvgElementSize(element);
|
|
1284
|
+
const { x, y } = getTranslate(g);
|
|
1285
|
+
const newSelectedComponent = Object.assign(Object.assign({}, selectedComponent), { x: x, y: y, width: width, height: height, points: points });
|
|
1286
|
+
const newSelection = Object.assign({ shape: "selection-box", id: `${Date.now()}` }, selectionBox);
|
|
1287
|
+
setSelectedLines(newSelection);
|
|
1288
|
+
// dragGhostRef.current = false;
|
|
1289
|
+
setSelectedComponent(newSelectedComponent);
|
|
1290
|
+
dispatch({
|
|
1291
|
+
type: "panel/setSelectedComponent",
|
|
1292
|
+
payload: newSelectedComponent,
|
|
1293
|
+
});
|
|
1294
|
+
updateComponentAttribute(newSelectedComponent);
|
|
1295
|
+
//LOGIC FOR SET SHOW
|
|
1296
|
+
dispatch({ type: "panel/setShow", payload: false });
|
|
1297
|
+
// isResizeRef.current = false;
|
|
1298
|
+
}
|
|
1299
|
+
//MAKING SELECTION BOX UP
|
|
1300
|
+
const isMakingSelectionBoxUp = downBeforeHasSelectionBox && activeTool === "select";
|
|
1301
|
+
if (isMakingSelectionBoxUp
|
|
1302
|
+
// &&
|
|
1303
|
+
// !hadSelectionRef.current &&
|
|
1304
|
+
// !isResizeSelectionRef.current
|
|
1305
|
+
) {
|
|
1306
|
+
console.log("MAKING SELECTION BOX UP");
|
|
1307
|
+
const allElementSelectionGroup = dataElementSelectionGroupRef.current;
|
|
1308
|
+
let xs = [];
|
|
1309
|
+
let ys = [];
|
|
1310
|
+
let x2 = [];
|
|
1311
|
+
let y2 = [];
|
|
1312
|
+
allElementSelectionGroup.forEach((element) => {
|
|
1313
|
+
const activeId = element.id;
|
|
1314
|
+
const { g, inner, element: el } = getAttributeElement(svg, activeId);
|
|
1315
|
+
const { x, y, width, height } = getGlobalBBox(svg, g);
|
|
1316
|
+
xs.push(x);
|
|
1317
|
+
ys.push(y);
|
|
1318
|
+
x2.push(x + width);
|
|
1319
|
+
y2.push(y + height);
|
|
1320
|
+
});
|
|
1321
|
+
const selectionBox = {
|
|
1322
|
+
x: Math.min(...xs),
|
|
1323
|
+
y: Math.min(...ys),
|
|
1324
|
+
width: Math.max(...x2) - Math.min(...xs),
|
|
1325
|
+
height: Math.max(...y2) - Math.min(...ys),
|
|
1326
|
+
stroke: "red",
|
|
1327
|
+
shape: "selection-box",
|
|
1328
|
+
fill: "transparent",
|
|
1329
|
+
id: `${Date.now()}`,
|
|
1330
|
+
rotation: 0,
|
|
1331
|
+
};
|
|
1332
|
+
function hasInvalidNumber(obj) {
|
|
1333
|
+
return Object.values(obj).some((v) => typeof v === "number" && !Number.isFinite(v));
|
|
1334
|
+
}
|
|
1335
|
+
if (!hasInvalidNumber(selectionBox)) {
|
|
1336
|
+
selectionLinesRef.current = selectionBox;
|
|
1337
|
+
setSelectedLines(selectionBox);
|
|
1338
|
+
dispatch({
|
|
1339
|
+
type: "panel/setSelectedGroup",
|
|
1340
|
+
payload: allElementSelectionGroup,
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
setSelectedComponent(null);
|
|
1344
|
+
dispatch({
|
|
1345
|
+
type: "panel/setSelectedComponent",
|
|
1346
|
+
payload: null,
|
|
1347
|
+
});
|
|
1348
|
+
rotationSelectionRef.current = 0;
|
|
1349
|
+
(_k = (_j = svgRef.current) === null || _j === void 0 ? void 0 : _j.querySelectorAll("#selection-box-ghost")) === null || _k === void 0 ? void 0 : _k.forEach((el) => el.remove());
|
|
1350
|
+
}
|
|
1351
|
+
//RESIZE SELECTION BOX UP
|
|
1352
|
+
if (downAtResizePositionAndHasSelectionBox || isRotateSelectionBox) {
|
|
1353
|
+
console.log("Resize selection and rotate selection");
|
|
1354
|
+
const selectionLines = (_l = svgRef.current) === null || _l === void 0 ? void 0 : _l.querySelector("#selection-lines");
|
|
1355
|
+
isResizeSelectionRef.current = false;
|
|
1356
|
+
const results = (_m = dataElementSelectionGroupRef.current) === null || _m === void 0 ? void 0 : _m.map((item) => {
|
|
1357
|
+
const { g, element, inner, points } = getAttributeElement(svg, item.id);
|
|
1358
|
+
const { x, y } = getTranslate(g);
|
|
1359
|
+
const { width, height } = getSvgElementSize(element);
|
|
1360
|
+
const rotate = getRotation(inner.transform.baseVal);
|
|
1361
|
+
const selectionBox = getGlobalBBox(svg, g);
|
|
1362
|
+
console.log({ points });
|
|
1363
|
+
const newDataComponent = Object.assign(Object.assign({}, item), { points,
|
|
1364
|
+
x,
|
|
1365
|
+
y,
|
|
1366
|
+
width,
|
|
1367
|
+
height, rotation: rotate });
|
|
1368
|
+
const newDataSelection = Object.assign(Object.assign({}, newDataComponent), { x: selectionBox.x, y: selectionBox.y, width: selectionBox.width, height: selectionBox.height, shape: "selection-box", id: `${Date.now()}`, rotate: 0 });
|
|
1369
|
+
return {
|
|
1370
|
+
newDataComponent,
|
|
1371
|
+
newDataSelection,
|
|
1372
|
+
};
|
|
1373
|
+
});
|
|
1374
|
+
const newDataComponent = results.map((r) => r.newDataComponent);
|
|
1375
|
+
const dataSelection = results.map((r) => r.newDataSelection);
|
|
1376
|
+
// const currentRotation = getRotation(
|
|
1377
|
+
// (selectionLines?.children[0] as SVGGraphicsElement)?.transform
|
|
1378
|
+
// ?.baseVal
|
|
1379
|
+
// );
|
|
1380
|
+
// rotationSelectionRef.current = currentRotation;
|
|
1381
|
+
const sizeSelection = getSvgElementSize((_o = selectionLines === null || selectionLines === void 0 ? void 0 : selectionLines.children[0]) === null || _o === void 0 ? void 0 : _o.children[0]);
|
|
1382
|
+
// const newBoxSelection = getGlobalBBox(svg, selectionLines);
|
|
1383
|
+
updateComponentsAttribute(newDataComponent);
|
|
1384
|
+
const newDataSelection = {
|
|
1385
|
+
x: Math.min(...dataSelection.map((d) => d.x)),
|
|
1386
|
+
y: Math.min(...dataSelection.map((d) => d.y)),
|
|
1387
|
+
width: Math.max(...dataSelection.map((d) => d.x + d.width)) -
|
|
1388
|
+
Math.min(...dataSelection.map((d) => d.x)),
|
|
1389
|
+
height: Math.max(...dataSelection.map((d) => d.y + d.height)) -
|
|
1390
|
+
Math.min(...dataSelection.map((d) => d.y)),
|
|
1391
|
+
shape: "selection-box",
|
|
1392
|
+
id: `${Date.now()}`,
|
|
1393
|
+
};
|
|
1394
|
+
dispatch({
|
|
1395
|
+
type: "panel/setSelectedGroup",
|
|
1396
|
+
payload: newDataComponent,
|
|
1397
|
+
});
|
|
1398
|
+
setSelectedComponent(null);
|
|
1399
|
+
dispatch({
|
|
1400
|
+
type: "panel/setSelectedComponent",
|
|
1401
|
+
payload: null,
|
|
1402
|
+
});
|
|
1403
|
+
setSelectedLines(newDataSelection);
|
|
1404
|
+
dataElementSelectionGroupRef.current = newDataComponent;
|
|
1405
|
+
// // remove ghost element
|
|
1406
|
+
// svgRef.current
|
|
1407
|
+
// ?.querySelectorAll("#ghost-element-has-selection")
|
|
1408
|
+
// .forEach((el) => el.remove());
|
|
1409
|
+
hadSelectionRef.current = false;
|
|
1410
|
+
}
|
|
1411
|
+
//MOVE SELECTION BOX UP
|
|
1412
|
+
if (downOutResizePositionAndInSelectionBox &&
|
|
1413
|
+
!shiftActive &&
|
|
1414
|
+
!isRotateSelectionBox) {
|
|
1415
|
+
console.log("MOVE SELECTION BOX UP");
|
|
1416
|
+
const selectionLines = (_p = svgRef.current) === null || _p === void 0 ? void 0 : _p.querySelector("#selection-lines");
|
|
1417
|
+
isResizeSelectionRef.current = false;
|
|
1418
|
+
const results = (_q = dataElementSelectionGroupRef.current) === null || _q === void 0 ? void 0 : _q.map((item) => {
|
|
1419
|
+
const { g, element, inner } = getAttributeElement(svg, item.id);
|
|
1420
|
+
const { x, y } = getTranslate(g);
|
|
1421
|
+
const getBBox = getGlobalBBox(svg, g);
|
|
1422
|
+
const findComponent = [
|
|
1423
|
+
...componentsState,
|
|
1424
|
+
...extraComponentsState,
|
|
1425
|
+
].find((c) => c.id === item.id);
|
|
1426
|
+
const newDataComponent = Object.assign(Object.assign({}, findComponent), { x,
|
|
1427
|
+
y });
|
|
1428
|
+
const newDataSelection = Object.assign({}, getBBox);
|
|
1429
|
+
return {
|
|
1430
|
+
newDataComponent,
|
|
1431
|
+
newDataSelection,
|
|
1432
|
+
};
|
|
1433
|
+
});
|
|
1434
|
+
const newDataComponent = results.map((r) => r.newDataComponent);
|
|
1435
|
+
const dataSelection = results.map((r) => r.newDataSelection);
|
|
1436
|
+
const newSelection = {
|
|
1437
|
+
x: Math.min(...dataSelection.map((d) => d.x)),
|
|
1438
|
+
y: Math.min(...dataSelection.map((d) => d.y)),
|
|
1439
|
+
width: Math.max(...dataSelection.map((d) => d.x + d.width)) -
|
|
1440
|
+
Math.min(...dataSelection.map((d) => d.x)),
|
|
1441
|
+
height: Math.max(...dataSelection.map((d) => d.y + d.height)) -
|
|
1442
|
+
Math.min(...dataSelection.map((d) => d.y)),
|
|
1443
|
+
};
|
|
1444
|
+
updateComponentsAttribute(newDataComponent);
|
|
1445
|
+
const newDataSelection = Object.assign(Object.assign({}, newSelection), { shape: "selection-box", id: `${Date.now()}-from-move`, rotation: 0 });
|
|
1446
|
+
dispatch({
|
|
1447
|
+
type: "panel/setSelectedGroup",
|
|
1448
|
+
payload: newDataComponent,
|
|
1449
|
+
});
|
|
1450
|
+
setSelectedComponent(null);
|
|
1451
|
+
dispatch({
|
|
1452
|
+
type: "panel/setSelectedComponent",
|
|
1453
|
+
payload: null,
|
|
1454
|
+
});
|
|
1455
|
+
setSelectedLines(newDataSelection);
|
|
1456
|
+
// if (newDataSelection?.height?.id) {
|
|
1457
|
+
// newDataSelection.height = newDataSelection.height.id;
|
|
1458
|
+
// }
|
|
1459
|
+
// if (newDataSelection?.x) {
|
|
1460
|
+
// setSelectedLines(newDataSelection);
|
|
1461
|
+
// }
|
|
1462
|
+
dataElementSelectionGroupRef.current = newDataComponent;
|
|
1463
|
+
hadSelectionRef.current = false;
|
|
1464
|
+
}
|
|
1465
|
+
//DELETE GHOST ELEMENT BISA MEMBU
|
|
1466
|
+
(_r = svgRef.current) === null || _r === void 0 ? void 0 : _r.querySelectorAll("#ghost-element").forEach((el) => el.remove());
|
|
1467
|
+
dataSetGhost.current = null;
|
|
1468
|
+
//UPDATE DATASET TO STATE IF MOVEk
|
|
1469
|
+
// if (releaseGroupRef.current) return;
|
|
1470
|
+
if ((isMightMove &&
|
|
1471
|
+
!isMakingSelectionBoxUp &&
|
|
1472
|
+
!isSelectElement &&
|
|
1473
|
+
!isMightResizeElement) ||
|
|
1474
|
+
isMightMoveOneElementSelection) {
|
|
1475
|
+
console.log("MOVE ONE ELEMENT");
|
|
1476
|
+
const findData = [...componentsState, ...extraComponentsState].find((item) => item.id == activeId);
|
|
1477
|
+
const { g } = getAttributeElement(svg, activeId);
|
|
1478
|
+
const bbox = getGlobalBBox(svg, g);
|
|
1479
|
+
const bboxSelection = getTranslate(g);
|
|
1480
|
+
const updateComponent = Object.assign(Object.assign({}, findData), { x: bboxSelection === null || bboxSelection === void 0 ? void 0 : bboxSelection.x, y: bboxSelection === null || bboxSelection === void 0 ? void 0 : bboxSelection.y });
|
|
1481
|
+
const selectionLines = Object.assign(Object.assign(Object.assign({}, selectedLines), bbox), { shape: "selection-box" });
|
|
1482
|
+
if (findData) {
|
|
1483
|
+
if (isSingleSelection) {
|
|
1484
|
+
setSelectedLines(selectionLines);
|
|
1485
|
+
setSelectedComponent(updateComponent);
|
|
1486
|
+
dispatch({
|
|
1487
|
+
type: "panel/updateSelectedComponent",
|
|
1488
|
+
payload: updateComponent,
|
|
1489
|
+
});
|
|
1490
|
+
}
|
|
1491
|
+
updateComponentAttribute(updateComponent);
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
window.removeEventListener("pointermove", pointerHandleMove);
|
|
1495
|
+
window.removeEventListener("pointerup", pointerHandleUp);
|
|
1496
|
+
};
|
|
1497
|
+
window.addEventListener("pointermove", pointerHandleMove);
|
|
1498
|
+
window.addEventListener("pointerup", pointerHandleUp);
|
|
747
1499
|
};
|
|
748
|
-
const
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
1500
|
+
const handlePointerMove = (e) => {
|
|
1501
|
+
const svg = svgRef.current;
|
|
1502
|
+
const pt = svg.createSVGPoint();
|
|
1503
|
+
pt.x = e.clientX;
|
|
1504
|
+
pt.y = e.clientY;
|
|
1505
|
+
const pos = pt.matrixTransform(svg.getScreenCTM().inverse());
|
|
1506
|
+
if (isOnMakePolygonRef === null || isOnMakePolygonRef === void 0 ? void 0 : isOnMakePolygonRef.current) {
|
|
1507
|
+
const polylineHelper = svg === null || svg === void 0 ? void 0 : svg.querySelector("#polyline-helper");
|
|
1508
|
+
// const startPoint =
|
|
1509
|
+
// selectedComponent?.points[selectedComponent?.points?.length - 1];
|
|
1510
|
+
const newPoints = [...selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.points, { x: pos.x, y: pos.y }];
|
|
1511
|
+
const points = newPoints.map((item) => `${item.x},${item.y}`).join(" ");
|
|
1512
|
+
polylineHelper === null || polylineHelper === void 0 ? void 0 : polylineHelper.setAttribute("points", points);
|
|
1513
|
+
//lin helper from start to move
|
|
1514
|
+
}
|
|
754
1515
|
};
|
|
755
|
-
return (_jsxs(_Fragment, { children: [_jsx(ModalPreview, { children: _jsx(LayerView, { statusKey: "status" }) }),
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
1516
|
+
return (_jsxs(_Fragment, { children: [_jsx(ModalPreview, { children: _jsx(LayerView, { statusKey: "status" }) }), _jsxs("div", { className: "relative w-full h-screen flex-1 overflow-hidden", ref: containerRef, children: [_jsx("div", { className: "absolute bottom-5 left-1/2 transform -translate-x-1/2 z-10", children: _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { icon: _jsx(ZoomIn, {}), onClick: handelZoomIn }), _jsx(Button, { icon: _jsx(ZoomOut, {}), onClick: handleZoomOut })] }) }), _jsx(TransformWrapper, { ref: transformRef,
|
|
1517
|
+
// limitToBounds={true}
|
|
1518
|
+
panning: {
|
|
1519
|
+
disabled: [
|
|
1520
|
+
"node",
|
|
1521
|
+
"select",
|
|
1522
|
+
"square",
|
|
1523
|
+
"circle",
|
|
1524
|
+
"table-seat-circle",
|
|
1525
|
+
].includes(activeTool),
|
|
1526
|
+
},
|
|
1527
|
+
// centerZoomedOut={true}
|
|
1528
|
+
// onTransformed={handleTransformed}
|
|
1529
|
+
minScale: 0.1, maxScale: 1000, initialScale: scale, pinch: { step: 1 }, wheel: { disabled: true }, smooth: true, doubleClick: { step: 1, disabled: activeTool === "select" }, disablePadding: true, centerOnInit: true, children: _jsxs(TransformComponent, { wrapperStyle: {
|
|
1530
|
+
width: "100%",
|
|
1531
|
+
height: "100%",
|
|
1532
|
+
}, contentStyle: { width: boardSize.width, height: boardSize.height }, children: [isLoading && (_jsx("div", { className: "absolute z-20 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2", children: "Loading..." })), _jsxs("svg", { id: "workspace", ref: svgRef, width: boardSize.width, height: boardSize.height, viewBox: `${minCoords.x} ${minCoords.y} ${boardSize.width} ${boardSize.height}`, onPointerDown: handlePointerDown, onPointerMove: handlePointerMove, xmlns: "http://www.w3.org/2000/svg", preserveAspectRatio: "xMidYMid meet", style: {
|
|
772
1533
|
background: backgroundColor,
|
|
773
1534
|
display: "block",
|
|
774
1535
|
cursor: activeTool === "ruler" ? "crosshair" : "auto",
|
|
775
1536
|
touchAction: "none",
|
|
776
|
-
|
|
1537
|
+
pointerEvents: "all",
|
|
1538
|
+
userSelect: "none",
|
|
1539
|
+
}, children: [_jsx(Layers, { shadowShape: shadowShape, components: [
|
|
1540
|
+
...extraComponentsState,
|
|
1541
|
+
...componentsState,
|
|
1542
|
+
polygonElementRef === null || polygonElementRef === void 0 ? void 0 : polygonElementRef.current,
|
|
1543
|
+
], style: {
|
|
777
1544
|
cursor: getCursorStyle(),
|
|
778
|
-
},
|
|
779
|
-
// onClick={handleSelectComponent}
|
|
780
|
-
onMouseDown: handleMouseDown,
|
|
781
|
-
// onMouseUp={handleMouseUp}
|
|
782
|
-
// onBlur={handleUnSelectComponent}
|
|
783
|
-
selectedComponent: selectedComponent, activeTool: activeTool, onTouchStart: handleMouseDown }), activeTool === "ruler" && (_jsxs(_Fragment, { children: [_jsxs("g", { id: "horizontal-ruler", children: [_jsx("rect", { x: "0", y: "0", width: window.innerWidth, height: "30", fill: "#e0e0e0" }), _jsx("g", { stroke: "#888", "font-size": "10", "text-anchor": "middle", children: Array.from({ length: window.innerWidth / 50 }, (_, i) => (_jsxs("g", { children: [_jsx("line", { x1: i * 50, y1: "0", x2: i * 50, y2: "10" }), _jsx("text", { x: i * 50, y: "15", children: i * 50 })] }, i))) })] }), _jsxs("g", { id: "vertical-ruler", children: [_jsx("rect", { x: "0", y: "0", width: "30", height: window.innerHeight, fill: "#e0e0e0" }), _jsx("g", { stroke: "#888", "font-size": "10", "text-anchor": "middle", children: Array.from({ length: window.innerHeight / 10 }, (_, i) => (_jsxs("g", { children: [_jsx("line", { x1: "0", y1: i * 50, x2: "10", y2: i * 50 }), _jsx("text", { x: "15", y: i * 50, children: i * 50 })] }, i))) })] })] })), grid && (_jsxs("g", { stroke: "#ddd", strokeWidth: 0.5, children: [Array.from({ length: widthBoard / (10 * scale) }, (_, i) => (_jsx("line", { x1: i * 10 * scale, y1: 0, x2: i * 10 * scale, y2: heightBoard }, `v-${i}`))), Array.from({ length: heightBoard / (10 * scale) }, (_, i) => (_jsx("line", { x1: 0, y1: i * 10 * scale, x2: widthBoard, y2: i * 10 * scale }, `h-${i}`)))] }))] }) })] })] })] }));
|
|
1545
|
+
}, selectedComponent: selectedComponent, selectionLines: selectedLines, activeTool: activeTool }), activeTool === "polygon" && (_jsx("polyline", { id: "polyline-helper", stroke: "#4a90e2", fill: "transparent", strokeWidth: 2 })), activeTool === "ruler" && (_jsxs(_Fragment, { children: [_jsxs("g", { id: "horizontal-ruler", children: [_jsx("rect", { x: "0", y: "0", width: window.innerWidth, height: "30", fill: "#e0e0e0" }), _jsx("g", { stroke: "#888", "font-size": "10", "text-anchor": "middle", children: Array.from({ length: window.innerWidth / 50 }, (_, i) => (_jsxs("g", { children: [_jsx("line", { x1: i * 50, y1: "0", x2: i * 50, y2: "10" }), _jsx("text", { x: i * 50, y: "15", children: i * 50 })] }, i))) })] }), _jsxs("g", { id: "vertical-ruler", children: [_jsx("rect", { x: "0", y: "0", width: "30", height: window.innerHeight, fill: "#e0e0e0" }), _jsx("g", { stroke: "#888", "font-size": "10", "text-anchor": "middle", children: Array.from({ length: window.innerHeight / 10 }, (_, i) => (_jsxs("g", { children: [_jsx("line", { x1: "0", y1: i * 50, x2: "10", y2: i * 50 }), _jsx("text", { x: "15", y: i * 50, children: i * 50 })] }, i))) })] })] })), grid && (_jsxs("g", { stroke: "#ddd", strokeWidth: 0.5, children: [Array.from({ length: widthBoard / (10 * scale) }, (_, i) => (_jsx("line", { x1: i * 10 * scale, y1: 0, x2: i * 10 * scale, y2: heightBoard }, `v-${i}`))), Array.from({ length: heightBoard / (10 * scale) }, (_, i) => (_jsx("line", { x1: 0, y1: i * 10 * scale, x2: widthBoard, y2: i * 10 * scale }, `h-${i}`)))] }))] })] }) })] })] }));
|
|
784
1546
|
};
|
|
785
1547
|
export default BoardTemplate;
|