polarvo-layout 1.0.69 → 1.0.71
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/package.json +1 -1
- package/src/components/Layout/FreeLayout.vue +1 -2
- package/src/components/Layout/GridLayout.vue +1 -0
- package/src/configs/resources/elementResource.js +12 -24
- package/src/configs/resources/layoutResource.js +22 -10
- package/src/core/engines/DisplayEngine.js +5 -2
- package/src/core/engines/FreeDropEngine.js +49 -5
- package/src/core/engines/GridDropEngine.js +11 -5
- package/src/core/engines/LayoutEngine.js +1 -0
- package/src/core/managers/EngineManager.js +104 -58
- package/src/library/FreeDropLibrary.js +2 -2
- package/src/library/GridDropLibrary.js +2 -2
package/package.json
CHANGED
|
@@ -85,9 +85,8 @@ watch(
|
|
|
85
85
|
if (newId && activeElement.value?.section !== props.sectionKey) return;
|
|
86
86
|
|
|
87
87
|
if (!newId) {
|
|
88
|
-
console.l;
|
|
89
88
|
setActiveDesign(null);
|
|
90
|
-
setActiveMenu(null);
|
|
89
|
+
// setActiveMenu(null);
|
|
91
90
|
}
|
|
92
91
|
_isElementSwitching = true;
|
|
93
92
|
// selectedElement.value = structuredClone(toRaw(activeElement.value));
|
|
@@ -23,32 +23,20 @@ export const elementResource = {
|
|
|
23
23
|
w: 300,
|
|
24
24
|
h: 200,
|
|
25
25
|
},
|
|
26
|
-
|
|
27
|
-
w:
|
|
28
|
-
h:
|
|
29
|
-
},
|
|
30
|
-
basicPagination: {
|
|
31
|
-
w: 150,
|
|
32
|
-
h: 40,
|
|
33
|
-
},
|
|
34
|
-
basicRadio: {
|
|
35
|
-
w: 120,
|
|
36
|
-
h: 40,
|
|
37
|
-
},
|
|
38
|
-
basicSearch: {
|
|
39
|
-
w: 260,
|
|
40
|
-
h: 40,
|
|
26
|
+
email: {
|
|
27
|
+
w: 480,
|
|
28
|
+
h: 580,
|
|
41
29
|
},
|
|
42
|
-
|
|
43
|
-
w:
|
|
44
|
-
h:
|
|
30
|
+
fax: {
|
|
31
|
+
w: 440,
|
|
32
|
+
h: 420,
|
|
45
33
|
},
|
|
46
|
-
|
|
47
|
-
w:
|
|
48
|
-
h:
|
|
34
|
+
colorMake: {
|
|
35
|
+
w: 960,
|
|
36
|
+
h: 600,
|
|
49
37
|
},
|
|
50
|
-
|
|
51
|
-
w:
|
|
52
|
-
h:
|
|
38
|
+
dyeMaker: {
|
|
39
|
+
w: 860,
|
|
40
|
+
h: 620,
|
|
53
41
|
},
|
|
54
42
|
};
|
|
@@ -15,9 +15,13 @@ const defaultConfig = {
|
|
|
15
15
|
},
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
const createSections = (count,
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
const createSections = (count, positions = {}) => {
|
|
19
|
+
return Object.fromEntries(
|
|
20
|
+
Array.from({ length: count }, (_, i) => {
|
|
21
|
+
const key = `section${i + 1}`;
|
|
22
|
+
return [key, { ...defaultConfig, layoutPosition: positions[key] }];
|
|
23
|
+
}),
|
|
24
|
+
);
|
|
21
25
|
};
|
|
22
26
|
|
|
23
27
|
// 기본 아이콘 import
|
|
@@ -34,49 +38,57 @@ export const layoutResource = (icons = {}) => ({
|
|
|
34
38
|
name: '전체화면',
|
|
35
39
|
columnNumber: 1,
|
|
36
40
|
rowNumber: 1,
|
|
37
|
-
sections: createSections(1),
|
|
41
|
+
sections: createSections(1, { section1: { col: 0, row: 0 } }),
|
|
38
42
|
icon: markRaw(icons.NoSplitIcon || NoSplitIcon),
|
|
39
43
|
},
|
|
40
44
|
TopBottomSplit: {
|
|
41
45
|
name: '상하 분할',
|
|
42
46
|
columnNumber: 1,
|
|
43
47
|
rowNumber: 2,
|
|
44
|
-
sections: createSections(2),
|
|
48
|
+
sections: createSections(2, { section1: { col: 0, row: 0 }, section2: { col: 0, row: 1 } }),
|
|
45
49
|
icon: markRaw(icons.TopBottomSplitIcon || TopBottomSplitIcon),
|
|
46
50
|
},
|
|
47
51
|
LeftRightSplit: {
|
|
48
52
|
name: '좌우 분할',
|
|
49
53
|
columnNumber: 2,
|
|
50
54
|
rowNumber: 1,
|
|
51
|
-
sections: createSections(2),
|
|
55
|
+
sections: createSections(2, { section1: { col: 0, row: 0 }, section2: { col: 1, row: 0 } }),
|
|
52
56
|
icon: markRaw(icons.LeftRightSplitIcon || LeftRightSplitIcon),
|
|
53
57
|
},
|
|
54
58
|
ThreeRowSplit: {
|
|
55
59
|
name: '수평 3분할',
|
|
56
60
|
columnNumber: 1,
|
|
57
61
|
rowNumber: 3,
|
|
58
|
-
sections: createSections(3),
|
|
62
|
+
sections: createSections(3, { section1: { col: 0, row: 0 }, section2: { col: 0, row: 1 }, section3: { col: 0, row: 2 } }),
|
|
59
63
|
icon: markRaw(icons.ThreeRowSplitIcon || ThreeRowSplitIcon),
|
|
60
64
|
},
|
|
61
65
|
ThreeColumnSplit: {
|
|
62
66
|
name: '수직 3분할',
|
|
63
67
|
columnNumber: 3,
|
|
64
68
|
rowNumber: 1,
|
|
65
|
-
sections: createSections(3),
|
|
69
|
+
sections: createSections(3, { section1: { col: 0, row: 0 }, section2: { col: 1, row: 0 }, section3: { col: 2, row: 0 } }),
|
|
66
70
|
icon: markRaw(icons.ThreeColumnSplitIcon || ThreeColumnSplitIcon),
|
|
67
71
|
},
|
|
68
72
|
MainBottomSplit: {
|
|
69
73
|
name: '메인-하단 분할',
|
|
70
74
|
columnNumber: 2,
|
|
71
75
|
rowNumber: 2,
|
|
72
|
-
sections: createSections(3
|
|
76
|
+
sections: createSections(3, {
|
|
77
|
+
section1: { col: 0, row: 0, colSpan: 2 },
|
|
78
|
+
section2: { col: 0, row: 1 },
|
|
79
|
+
section3: { col: 1, row: 1 },
|
|
80
|
+
}),
|
|
73
81
|
icon: markRaw(icons.MainBottomSplitIcon || MainBottomSplitIcon),
|
|
74
82
|
},
|
|
75
83
|
MainTopSplit: {
|
|
76
84
|
name: '메인-상단 분할',
|
|
77
85
|
columnNumber: 2,
|
|
78
86
|
rowNumber: 2,
|
|
79
|
-
sections: createSections(3
|
|
87
|
+
sections: createSections(3, {
|
|
88
|
+
section1: { col: 0, row: 0 },
|
|
89
|
+
section2: { col: 1, row: 0 },
|
|
90
|
+
section3: { col: 0, row: 1, colSpan: 2 },
|
|
91
|
+
}),
|
|
80
92
|
icon: markRaw(icons.MainTopSplitIcon || MainTopSplitIcon),
|
|
81
93
|
},
|
|
82
94
|
});
|
|
@@ -62,7 +62,9 @@ class DisplayEngine {
|
|
|
62
62
|
});
|
|
63
63
|
|
|
64
64
|
this._subscribe('freeDrop:setActiveElement', ({ action }) => {
|
|
65
|
-
if (
|
|
65
|
+
if (['update', 'sectionChange'].includes(action)) return;
|
|
66
|
+
if (action === 'click' && this.activeMenu === 'layout') return;
|
|
67
|
+
|
|
66
68
|
this.setActiveMenu(null);
|
|
67
69
|
this.setActiveDesign(null);
|
|
68
70
|
});
|
|
@@ -74,7 +76,8 @@ class DisplayEngine {
|
|
|
74
76
|
// });
|
|
75
77
|
|
|
76
78
|
this._subscribe('gridDrop:setActiveElement', ({ action }) => {
|
|
77
|
-
if (
|
|
79
|
+
if (['update', 'sectionChange'].includes(action)) return;
|
|
80
|
+
if (action === 'click' && this.activeMenu === 'layout') return;
|
|
78
81
|
this.setActiveMenu(null);
|
|
79
82
|
this.setActiveDesign(null);
|
|
80
83
|
});
|
|
@@ -89,7 +89,7 @@ class FreeDropEngine {
|
|
|
89
89
|
this._activeMode = $mode;
|
|
90
90
|
this._activeConfig = $config;
|
|
91
91
|
|
|
92
|
-
this.setActiveElement(null);
|
|
92
|
+
this.setActiveElement(null, 'sectionChange');
|
|
93
93
|
});
|
|
94
94
|
|
|
95
95
|
this._subscribe('system:setElements', ({ $elements }) => {
|
|
@@ -114,7 +114,7 @@ class FreeDropEngine {
|
|
|
114
114
|
this._elements = $elements;
|
|
115
115
|
this._elementsUpdate = true;
|
|
116
116
|
|
|
117
|
-
this.setActiveElement(this._elements.find((x) => x.id === $elementId));
|
|
117
|
+
this.setActiveElement(this._elements.find((x) => x.id === $elementId) ?? null);
|
|
118
118
|
|
|
119
119
|
this.eventBus.emit('freeDrop:requestUpdateData', {
|
|
120
120
|
elements: cloneDeep(this.freeElements),
|
|
@@ -226,7 +226,9 @@ class FreeDropEngine {
|
|
|
226
226
|
if (this._elementsUpdate) {
|
|
227
227
|
this._elementsUpdate = false;
|
|
228
228
|
|
|
229
|
-
|
|
229
|
+
// mode 관계없이 모든 요소 렌더링
|
|
230
|
+
// const base = this._elements.filter((x) => x.mode === 'free');
|
|
231
|
+
const base = this._elements;
|
|
230
232
|
|
|
231
233
|
if (this._activeElement) {
|
|
232
234
|
const exists = base.find((x) => x.id === this._activeElement?.id);
|
|
@@ -384,6 +386,29 @@ class FreeDropEngine {
|
|
|
384
386
|
}
|
|
385
387
|
|
|
386
388
|
/** ---------------------------------- 배치요소 관련 메소드 ---------------------------------- **/
|
|
389
|
+
getCurrentPosition() {
|
|
390
|
+
const currentElements = this.freeElements.filter((x) => x.section === this._activeSection);
|
|
391
|
+
if (!currentElements?.length) return { col: 1, row: 1 };
|
|
392
|
+
|
|
393
|
+
let lastRow = 0;
|
|
394
|
+
let lastCol = 0;
|
|
395
|
+
|
|
396
|
+
for (const element of currentElements) {
|
|
397
|
+
const endRow = element?.position.row + element?.size.rowSpan - 1;
|
|
398
|
+
const endCol = element?.position.col + element?.size.colSpan - 1;
|
|
399
|
+
|
|
400
|
+
// 최대 행 위치보다 크거나 같은 행에서 열 위치가 더 큰 경우 업데이트
|
|
401
|
+
if (endRow > lastRow || (endRow === lastRow && endCol > lastCol)) {
|
|
402
|
+
lastRow = endRow;
|
|
403
|
+
lastCol = endCol;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const { gridColumns = 2 } = this._activeConfig ?? {};
|
|
408
|
+
// 마지막 행의 최대 열 위치가 columnCount 이상이면 다음 행으로 이동
|
|
409
|
+
return lastCol >= gridColumns ? { col: 1, row: lastRow + 1 } : { col: lastCol + 1, row: lastRow };
|
|
410
|
+
}
|
|
411
|
+
|
|
387
412
|
/** 배치요소 신규 추가 - 메뉴에서 추가 아이템 선택
|
|
388
413
|
* @param {MouseEvent} event - 마우스 이벤트
|
|
389
414
|
* @param {object} item - 추가할 아이템 정보
|
|
@@ -395,12 +420,15 @@ class FreeDropEngine {
|
|
|
395
420
|
this._startPos = { x: event.clientX, y: event.clientY };
|
|
396
421
|
|
|
397
422
|
const elementSource = this.getResourceByName('elements');
|
|
423
|
+
|
|
398
424
|
const element = {
|
|
399
425
|
id: elName + '_' + Date.now().toString(36) + Math.random().toString(36).slice(2, 7),
|
|
400
426
|
type: elName,
|
|
401
427
|
mode: 'free',
|
|
402
|
-
position: this._startPos,
|
|
403
|
-
|
|
428
|
+
// position: this._startPos,
|
|
429
|
+
position: { ...this.getCurrentPosition(), ...this._startPos },
|
|
430
|
+
// size: elementSource[elName] || { w: 100, h: 100 },
|
|
431
|
+
size: { ...(elementSource[elName] || { w: 100, h: 100 }), colSpan: 1, rowSpan: 1 },
|
|
404
432
|
section: this._activeSection,
|
|
405
433
|
isLocked: false,
|
|
406
434
|
...(item.propDefaults || {}), // 아이템의 기본 props 설정
|
|
@@ -578,6 +606,22 @@ class FreeDropEngine {
|
|
|
578
606
|
newW = this._snapToGrid(this._startSize.w + deltaX);
|
|
579
607
|
}
|
|
580
608
|
|
|
609
|
+
// 섹션 경계 제한 (반대쪽 끝은 고정한 채 넘친 만큼만 축소)
|
|
610
|
+
const layoutRect = this._getLayoutRect();
|
|
611
|
+
if (layoutRect) {
|
|
612
|
+
if (newY < 0) {
|
|
613
|
+
newH += newY;
|
|
614
|
+
newY = 0;
|
|
615
|
+
}
|
|
616
|
+
if (newX < 0) {
|
|
617
|
+
newW += newX;
|
|
618
|
+
newX = 0;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
newH = Math.round(Math.min(newH, layoutRect.height - newY));
|
|
622
|
+
newW = Math.round(Math.min(newW, layoutRect.width - newX));
|
|
623
|
+
}
|
|
624
|
+
|
|
581
625
|
// 최소 크기 제한
|
|
582
626
|
newW = Math.max(40, newW);
|
|
583
627
|
newH = Math.max(20, newH);
|
|
@@ -57,7 +57,7 @@ class GridDropEngine {
|
|
|
57
57
|
this._activeMode = $mode;
|
|
58
58
|
this._activeConfig = $config;
|
|
59
59
|
|
|
60
|
-
this.setActiveElement(null);
|
|
60
|
+
this.setActiveElement(null, 'sectionChange');
|
|
61
61
|
});
|
|
62
62
|
|
|
63
63
|
this._subscribe('system:setElements', ({ $elements }) => {
|
|
@@ -82,7 +82,8 @@ class GridDropEngine {
|
|
|
82
82
|
this._elements = $elements;
|
|
83
83
|
this._elementsUpdate = true;
|
|
84
84
|
|
|
85
|
-
this.setActiveElement(this._elements.find((x) => x.id === $elementId));
|
|
85
|
+
this.setActiveElement(this._elements.find((x) => x.id === $elementId) ?? null);
|
|
86
|
+
|
|
86
87
|
this.eventBus.emit('gridDrop:requestUpdateData', {
|
|
87
88
|
elements: cloneDeep(this.gridElements),
|
|
88
89
|
timestamp: Date.now(),
|
|
@@ -177,7 +178,9 @@ class GridDropEngine {
|
|
|
177
178
|
if (this._elementsUpdate) {
|
|
178
179
|
this._elementsUpdate = false;
|
|
179
180
|
|
|
180
|
-
|
|
181
|
+
// mode 관계없이 모든 요소 렌더링
|
|
182
|
+
// const base = this._elements.filter((x) => x.mode === 'grid');
|
|
183
|
+
const base = this._elements;
|
|
181
184
|
|
|
182
185
|
if (this._activeElement) {
|
|
183
186
|
const exists = base.find((x) => x.id === this._activeElement?.id);
|
|
@@ -346,13 +349,16 @@ class GridDropEngine {
|
|
|
346
349
|
if (this._activeMode !== 'grid') return;
|
|
347
350
|
|
|
348
351
|
const elName = item.elName;
|
|
352
|
+
const elementSource = this.elementResource;
|
|
349
353
|
|
|
350
354
|
const element = {
|
|
351
355
|
id: elName + '_' + Date.now().toString(36) + Math.random().toString(36).slice(2, 7),
|
|
352
356
|
type: elName,
|
|
353
357
|
mode: 'grid',
|
|
354
|
-
position: { ...this._dragState.activeCell },
|
|
355
|
-
|
|
358
|
+
// position: { ...this._dragState.activeCell },
|
|
359
|
+
position: { x: 0, y: 0, ...this._dragState.activeCell },
|
|
360
|
+
// size: { colSpan: 1, rowSpan: 1 },
|
|
361
|
+
size: { ...(elementSource[elName] || { w: 100, h: 100 }), colSpan: 1, rowSpan: 1 },
|
|
356
362
|
section: this._activeSection,
|
|
357
363
|
isLocked: false,
|
|
358
364
|
...(item.propDefaults || {}), // 아이템의 기본 props 설정
|
|
@@ -121,6 +121,7 @@ class EngineManager {
|
|
|
121
121
|
// layoutEngine
|
|
122
122
|
case 'layout': {
|
|
123
123
|
const prevRatio = this.getEngine('layout').gridRatio; // 복원 전 현재 비율
|
|
124
|
+
const prevLayoutData = this.state.layoutData; // 복원 전 layoutData (섹션 layoutPosition 비교용)
|
|
124
125
|
this.getEngine('layout')?.setState(state);
|
|
125
126
|
this.state.layoutData = state.layoutData;
|
|
126
127
|
this.setActiveSection(null, true);
|
|
@@ -129,7 +130,7 @@ class EngineManager {
|
|
|
129
130
|
prevRatio.column.length !== state.gridRatio.column.length || prevRatio.column.some((v, i) => v !== state.gridRatio.column[i]);
|
|
130
131
|
|
|
131
132
|
if (ratioChanged) {
|
|
132
|
-
this._updateElementsScaleByRatio('column', prevRatio, state.gridRatio);
|
|
133
|
+
this._updateElementsScaleByRatio('column', prevRatio, state.gridRatio, prevLayoutData);
|
|
133
134
|
}
|
|
134
135
|
break;
|
|
135
136
|
}
|
|
@@ -249,6 +250,22 @@ class EngineManager {
|
|
|
249
250
|
...safeChanges,
|
|
250
251
|
};
|
|
251
252
|
|
|
253
|
+
// free 모드 요소의 크기 직접 입력 시, 섹션 경계를 넘지 않도록 제한
|
|
254
|
+
if (updatedElement.mode === 'free' && safeChanges.size) {
|
|
255
|
+
const layoutEl = document.getElementById(`${updatedElement.section}Layout`);
|
|
256
|
+
if (layoutEl) {
|
|
257
|
+
const { width, height } = layoutEl.getBoundingClientRect();
|
|
258
|
+
const maxW = width - updatedElement.position.x;
|
|
259
|
+
const maxH = height - updatedElement.position.y;
|
|
260
|
+
|
|
261
|
+
updatedElement.size = {
|
|
262
|
+
...updatedElement.size,
|
|
263
|
+
w: Math.round(Math.max(40, Math.min(updatedElement.size.w, maxW))),
|
|
264
|
+
h: Math.round(Math.max(20, Math.min(updatedElement.size.h, maxH))),
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
252
269
|
this.state.elements = [...this.state.elements.slice(0, index), updatedElement, ...this.state.elements.slice(index + 1)];
|
|
253
270
|
|
|
254
271
|
// 변경된 element만 전달
|
|
@@ -328,12 +345,14 @@ class EngineManager {
|
|
|
328
345
|
});
|
|
329
346
|
|
|
330
347
|
this._subscribe('layout:updateLayoutName', ({ $layoutData, $gridRatio, $prev }) => {
|
|
348
|
+
const prevLayoutData = this.state.layoutData; // 레이아웃 전환 전 layoutData (섹션 layoutPosition 비교용)
|
|
331
349
|
this.state.layoutData = $layoutData;
|
|
350
|
+
|
|
332
351
|
this.setActiveSection(null, true);
|
|
333
352
|
|
|
334
353
|
const prevGridRatio = $prev?.gridRatio || { column: [100], row: [100] };
|
|
335
|
-
this._updateElementsScaleByRatio('column', prevGridRatio, $gridRatio);
|
|
336
|
-
this._updateElementsScaleByRatio('row', prevGridRatio, $gridRatio);
|
|
354
|
+
this._updateElementsScaleByRatio('column', prevGridRatio, $gridRatio, prevLayoutData);
|
|
355
|
+
this._updateElementsScaleByRatio('row', prevGridRatio, $gridRatio, prevLayoutData);
|
|
337
356
|
|
|
338
357
|
nextTick(() => {
|
|
339
358
|
this.eventBus.emit('system:historyCheckpoint', {
|
|
@@ -361,50 +380,50 @@ class EngineManager {
|
|
|
361
380
|
});
|
|
362
381
|
}
|
|
363
382
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
383
|
+
/** [내부함수] gridRatio 변경에 따라 요소 position/size 재계산
|
|
384
|
+
* @param {string} type - 'column' | 'row'
|
|
385
|
+
* @param {object} oldValue - 변경 전 gridRatio ({ column, row })
|
|
386
|
+
* @param {object} newValue - 변경 후 gridRatio ({ column, row })
|
|
387
|
+
* @param {object} oldLayoutData - 변경 전 layoutData.
|
|
388
|
+
* 생략 시: 섹션 비율만 조정하는 경우
|
|
389
|
+
* 레이아웃 자체가 바뀌는 호출은 변경 전 layoutData를 넘겨야 함
|
|
390
|
+
*/
|
|
391
|
+
_updateElementsScaleByRatio(type, oldValue, newValue, oldLayoutData = this.state.layoutData) {
|
|
392
|
+
// 축(column, row)에 따라 positionKey, sizeKey 결정
|
|
393
|
+
const positionKey = type === 'column' ? 'x' : 'y';
|
|
394
|
+
const sizeKey = type === 'column' ? 'w' : 'h';
|
|
395
|
+
|
|
396
|
+
// 요소를 받아서 좌표, 크기에 대해 배율을 곱해 새 요소 객체 반환하는 헬퍼
|
|
397
|
+
// column이면 x, w만 수정 / row면 y, h만 수정
|
|
398
|
+
const scaleElement = (el, scaleFactor) => ({
|
|
399
|
+
...el,
|
|
400
|
+
position: { ...el.position, [positionKey]: el.position[positionKey] * scaleFactor },
|
|
401
|
+
size: { ...el.size, [sizeKey]: el.size[sizeKey] * scaleFactor },
|
|
402
|
+
});
|
|
367
403
|
|
|
368
|
-
|
|
404
|
+
// 섹션이 전체 너비/높이에서 차지하는 퍼센트 계산
|
|
405
|
+
const axisRatio = (ratios, pos) => {
|
|
406
|
+
const start = type === 'column' ? pos.col : pos.row; // 섹션이 시작하는 인덱스
|
|
407
|
+
const span = (type === 'column' ? pos.colSpan : pos.rowSpan) ?? 1; // 섹션이 차지하는 칸 수
|
|
408
|
+
return ratios.slice(start, start + span).reduce((sum, v) => sum + v, 0) / 100;
|
|
409
|
+
};
|
|
369
410
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
}
|
|
375
|
-
// 열 또는 행 개수가 줄어드는 경우 - 요소 크기 늘리기
|
|
376
|
-
else if (oldLength > newLength) {
|
|
377
|
-
newDisplaySize.px = newDisplaySize.px / oldLength;
|
|
378
|
-
this._updateElementsScale(newDisplaySize, this._displaySize);
|
|
379
|
-
}
|
|
380
|
-
// 열 또는 행 개수는 동일하지만 비율이 변경되는 경우 - 요소 크기 조정
|
|
381
|
-
else {
|
|
382
|
-
this.state.elements = this.state.elements.map((el) => {
|
|
383
|
-
const sectionIndex = el.section ? parseInt(el.section.replace('section', '')) - 1 : 0;
|
|
384
|
-
const oldRatio = oldValue[type][sectionIndex] / 100;
|
|
385
|
-
const newRatio = newValue[type][sectionIndex] / 100;
|
|
386
|
-
|
|
387
|
-
const scaleFactor = newRatio / oldRatio;
|
|
388
|
-
return type === 'column'
|
|
389
|
-
? {
|
|
390
|
-
...el,
|
|
391
|
-
position: { ...el.position, x: el.position.x * scaleFactor },
|
|
392
|
-
size: { ...el.size, w: el.size.w * scaleFactor },
|
|
393
|
-
}
|
|
394
|
-
: {
|
|
395
|
-
...el,
|
|
396
|
-
position: { ...el.position, y: el.position.y * scaleFactor },
|
|
397
|
-
size: { ...el.size, h: el.size.h * scaleFactor },
|
|
398
|
-
};
|
|
399
|
-
});
|
|
411
|
+
this.state.elements = this.state.elements.map((el) => {
|
|
412
|
+
const oldPos = oldLayoutData?.[el.section]?.layoutPosition; // 변경 전 요소의 섹션 위치
|
|
413
|
+
const newPos = this.state.layoutData?.[el.section]?.layoutPosition; // 변경 후 요소의 섹션 위치
|
|
414
|
+
if (!oldPos || !newPos) return el;
|
|
400
415
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
416
|
+
const oldRatio = axisRatio(oldValue[type], oldPos);
|
|
417
|
+
if (!oldRatio) return el;
|
|
418
|
+
const newRatio = axisRatio(newValue[type], newPos);
|
|
419
|
+
|
|
420
|
+
return scaleElement(el, newRatio / oldRatio);
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
this.eventBus.emit('system:requestElementsScale', {
|
|
424
|
+
$elements: this.state.elements,
|
|
425
|
+
timestamp: Date.now(),
|
|
426
|
+
});
|
|
408
427
|
}
|
|
409
428
|
|
|
410
429
|
/** activeSection 변경
|
|
@@ -434,23 +453,34 @@ class EngineManager {
|
|
|
434
453
|
}
|
|
435
454
|
|
|
436
455
|
if (!this.activeData || this.activeData.mode === mode) return;
|
|
456
|
+
// mode 관계없이 모든 요소 렌더링
|
|
437
457
|
const updates = {
|
|
438
458
|
mode: mode,
|
|
439
|
-
elementIds: this.state.elements.filter((x) => x.section === this.state.activeSection
|
|
459
|
+
elementIds: this.state.elements.filter((x) => x.section === this.state.activeSection).map((x) => x.id),
|
|
460
|
+
// elementIds: this.state.elements.filter((x) => x.section === this.state.activeSection && x.mode === mode).map((x) => x.id),
|
|
440
461
|
};
|
|
441
462
|
|
|
442
|
-
if (mode === 'grid') {
|
|
463
|
+
// if (mode === 'grid') {
|
|
464
|
+
// updates.config = {
|
|
465
|
+
// gridColumns: this.activeData.config?.gridColumns || 2,
|
|
466
|
+
// gridRows: this.activeData.config?.gridRows || 2,
|
|
467
|
+
// gridGap: this.activeData.config?.gridGap || 4,
|
|
468
|
+
// gridRowRatio: this.activeData.config?.gridRowRatio || [],
|
|
469
|
+
// gridColumnRatio: this.activeData.config?.gridColumnRatio || [],
|
|
470
|
+
// };
|
|
471
|
+
// } else if (mode === 'free') {
|
|
472
|
+
// updates.config = {
|
|
473
|
+
// showGuideLine: this.activeData.config?.showGuideLine || false,
|
|
474
|
+
// };
|
|
475
|
+
// }
|
|
476
|
+
|
|
443
477
|
updates.config = {
|
|
444
478
|
gridColumns: this.activeData.config?.gridColumns || 2,
|
|
445
479
|
gridRows: this.activeData.config?.gridRows || 2,
|
|
446
480
|
gridGap: this.activeData.config?.gridGap || 4,
|
|
447
481
|
gridRowRatio: this.activeData.config?.gridRowRatio || [],
|
|
448
482
|
gridColumnRatio: this.activeData.config?.gridColumnRatio || [],
|
|
449
|
-
};
|
|
450
|
-
} else if (mode === 'free') {
|
|
451
|
-
updates.config = {
|
|
452
483
|
showGuideLine: this.activeData.config?.showGuideLine || false,
|
|
453
|
-
};
|
|
454
484
|
}
|
|
455
485
|
|
|
456
486
|
this._updateActiveSectionConfig('mode', updates);
|
|
@@ -536,7 +566,11 @@ class EngineManager {
|
|
|
536
566
|
|
|
537
567
|
this.state.elements.push(element);
|
|
538
568
|
const targetSectionData = this.state.layoutData?.[element.section];
|
|
539
|
-
this._updateActiveSectionConfig(
|
|
569
|
+
this._updateActiveSectionConfig(
|
|
570
|
+
'elementIds',
|
|
571
|
+
{ elementIds: [...(targetSectionData?.elementIds || []), element.id] },
|
|
572
|
+
element.section,
|
|
573
|
+
);
|
|
540
574
|
|
|
541
575
|
this.eventBus.emit('system:requestUpdateElement', {
|
|
542
576
|
action: 'add',
|
|
@@ -556,9 +590,13 @@ class EngineManager {
|
|
|
556
590
|
const target = this.state.elements.find((el) => el.id === elementId);
|
|
557
591
|
this.state.elements = this.state.elements.filter((el) => el.id !== elementId);
|
|
558
592
|
const targetSectionData = this.state.layoutData?.[target?.section];
|
|
559
|
-
this._updateActiveSectionConfig(
|
|
560
|
-
elementIds
|
|
561
|
-
|
|
593
|
+
this._updateActiveSectionConfig(
|
|
594
|
+
'elementIds',
|
|
595
|
+
{
|
|
596
|
+
elementIds: (targetSectionData?.elementIds || []).filter((elId) => elId !== elementId),
|
|
597
|
+
},
|
|
598
|
+
target?.section,
|
|
599
|
+
);
|
|
562
600
|
// this._updateActiveElementIds(this.activeData.elementIds.filter((elId) => elId !== elementId));
|
|
563
601
|
|
|
564
602
|
this.eventBus.emit('system:requestUpdateElement', {
|
|
@@ -610,7 +648,11 @@ class EngineManager {
|
|
|
610
648
|
|
|
611
649
|
this.state.elements.push(element);
|
|
612
650
|
const targetSectionData = this.state.layoutData?.[element.section];
|
|
613
|
-
this._updateActiveSectionConfig(
|
|
651
|
+
this._updateActiveSectionConfig(
|
|
652
|
+
'elementIds',
|
|
653
|
+
{ elementIds: [...(targetSectionData?.elementIds || []), element.id] },
|
|
654
|
+
element.section,
|
|
655
|
+
);
|
|
614
656
|
// this._updateActiveElementIds([...this.activeData.elementIds, element.id]);
|
|
615
657
|
|
|
616
658
|
this.eventBus.emit('system:requestUpdateElement', {
|
|
@@ -631,9 +673,13 @@ class EngineManager {
|
|
|
631
673
|
const target = this.state.elements.find((el) => el.id === elementId);
|
|
632
674
|
this.state.elements = this.state.elements.filter((el) => el.id !== elementId);
|
|
633
675
|
const targetSectionData = this.state.layoutData?.[target?.section];
|
|
634
|
-
this._updateActiveSectionConfig(
|
|
635
|
-
elementIds
|
|
636
|
-
|
|
676
|
+
this._updateActiveSectionConfig(
|
|
677
|
+
'elementIds',
|
|
678
|
+
{
|
|
679
|
+
elementIds: (targetSectionData?.elementIds || []).filter((elId) => elId !== elementId),
|
|
680
|
+
},
|
|
681
|
+
target?.section,
|
|
682
|
+
);
|
|
637
683
|
// this._updateActiveElementIds(this.activeData.elementIds.filter((elId) => elId !== elementId));
|
|
638
684
|
|
|
639
685
|
this.eventBus.emit('system:requestUpdateElement', {
|
|
@@ -143,9 +143,9 @@ function useFreeDrop(api) {
|
|
|
143
143
|
}
|
|
144
144
|
};
|
|
145
145
|
|
|
146
|
-
const setActiveElement = (element,
|
|
146
|
+
const setActiveElement = (element, action) => {
|
|
147
147
|
try {
|
|
148
|
-
api.freeDrop.setActiveElement(element,
|
|
148
|
+
api.freeDrop.setActiveElement(element, action);
|
|
149
149
|
} catch (error) {
|
|
150
150
|
console.warn('[FreeDropLibrary] setActiveElement 실행 중 오류 발생:', error);
|
|
151
151
|
}
|
|
@@ -118,9 +118,9 @@ function useGridDrop(api) {
|
|
|
118
118
|
}
|
|
119
119
|
};
|
|
120
120
|
|
|
121
|
-
const setActiveElement = (element,
|
|
121
|
+
const setActiveElement = (element, action) => {
|
|
122
122
|
try {
|
|
123
|
-
api.gridDrop.setActiveElement(element,
|
|
123
|
+
api.gridDrop.setActiveElement(element, action);
|
|
124
124
|
} catch (error) {
|
|
125
125
|
console.warn('[GridDropLibrary] setActiveElement 실행 중 오류 발생:', error);
|
|
126
126
|
}
|