polarvo-layout 1.0.21 → 1.0.23

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polarvo-layout",
3
- "version": "1.0.21",
3
+ "version": "1.0.23",
4
4
  "type": "module",
5
5
  "author": "unigence <unigencelab@gmail.com>",
6
6
  "repository": {
@@ -2,8 +2,9 @@
2
2
  <div
3
3
  :id="preview ? 'previewLayout' : 'baseLayout'"
4
4
  class="grid h-full p-2 bg-transparent rounded-lg"
5
- :class="[layoutType + '-layout', `grid-cols-${gridNumber?.column}`, 'mb-4' ? layoutType === 'three-column-split' : '']"
5
+ :class="[layoutType + '-layout', `grid-cols-${gridNumber?.column}`, { 'mb-4': layoutType === 'three-column-split' }]"
6
6
  :style="getBaseStyle"
7
+ @contextmenu.prevent
7
8
  >
8
9
  <template v-for="(section, key) in layoutData" :key="key">
9
10
  <PolarLayout
@@ -50,9 +51,9 @@ import FreeLayout from './FreeLayout.vue';
50
51
  import GridLayout from './GridLayout.vue';
51
52
 
52
53
  // 우클릭 방지
53
- window.oncontextmenu = () => {
54
- return false;
55
- };
54
+ // window.oncontextmenu = () => {
55
+ // return false;
56
+ // };
56
57
 
57
58
  const emit = defineEmits(['click:section']);
58
59
  const props = defineProps({
@@ -67,7 +68,7 @@ const props = defineProps({
67
68
  });
68
69
 
69
70
  const layoutType = computed(() => {
70
- if (layoutName.value.eng == null) return 'no-split';
71
+ if (layoutName.value.eng === null) return 'no-split';
71
72
  return layoutName.value.eng
72
73
  .replace(/([A-Z])/g, '-$1')
73
74
  .toLowerCase()
@@ -86,8 +87,8 @@ const getBaseStyle = computed(() => {
86
87
  });
87
88
 
88
89
  const getSectionStyle = (section) => ({
89
- '--grid-columns': section.config?.gridColumns || 3,
90
- '--grid-gap': `${section.config?.gridGap || 5}px`,
90
+ '--grid-columns': section.config?.gridColumns ?? 3,
91
+ '--grid-gap': `${section.config?.gridGap ?? 5}px`,
91
92
  position: 'relative',
92
93
  });
93
94
 
@@ -95,7 +96,7 @@ const getSectionClass = (key, section) => ({
95
96
  [key]: true,
96
97
  [section.mode]: true,
97
98
  'section-active': activeSection.value === key,
98
- disabled: activeSection.value != key && !props.preview,
99
+ disabled: activeSection.value !== key && !props.preview,
99
100
  });
100
101
  </script>
101
102
 
@@ -5,7 +5,7 @@
5
5
  <div class="grid gap-1 grid-cols-1 mx-1 mb-3">
6
6
  <div
7
7
  class="item flex flex-col items-center gap-1 p-2 border border-gray-200 rounded-md bg-white cursor-pointer hover:border-gray-400"
8
- :class="{ active: layoutName.eng == 'NoSplit' }"
8
+ :class="{ active: layoutName.eng === 'NoSplit' }"
9
9
  @click="setLayoutName('NoSplit')"
10
10
  >
11
11
  <component class="text-gray-600" :is="layoutSource.noSplit.icon"></component>
@@ -18,7 +18,7 @@
18
18
  v-for="(layout, key) in layoutSource.split"
19
19
  :key="key"
20
20
  class="item flex flex-col items-center gap-1 p-2 border border-gray-200 rounded-md bg-white cursor-pointer hover:border-gray-400"
21
- :class="{ active: layoutName.eng == key }"
21
+ :class="{ active: layoutName.eng === key }"
22
22
  @click="setLayoutName(key)"
23
23
  >
24
24
  <component class="text-gray-600" :is="layout.icon"></component>
@@ -46,7 +46,6 @@ watch(
46
46
  () => {
47
47
  emits('click:layout');
48
48
  },
49
- { deep: true }
50
49
  );
51
50
  </script>
52
51
 
@@ -10,7 +10,7 @@
10
10
  </button>
11
11
  </div>
12
12
 
13
- <div v-if="layoutName.eng != 'NoSplit'">
13
+ <div v-if="layoutName.eng !== 'NoSplit'">
14
14
  <h5 class="mt-4 block text-sm font-bold text-gray-600">레이아웃 설정</h5>
15
15
  <div class="mt-2 border border-gray-200 rounded-md bg-gray-100">
16
16
  <div class="px-4 py-2">
@@ -21,7 +21,7 @@
21
21
  type="number"
22
22
  id="section-gap"
23
23
  :value="gapSize"
24
- @change="setGapSize($event.target.value)"
24
+ @change="handleGapSize($event)"
25
25
  />
26
26
  </div>
27
27
  </div>
@@ -91,10 +91,25 @@ function handleGridRatio(type, index, event) {
91
91
  return;
92
92
  }
93
93
 
94
- const { result, message } = setRatio(type, index, value)
94
+ const { result, message } = setRatio(type, index, Number(value));
95
95
 
96
96
  if (!result) {
97
- alert(message)
97
+ alert(message);
98
+ }
99
+ }
100
+
101
+ function handleGapSize(event) {
102
+ const value = event.target.value;
103
+ if (Number(value) < 0 || isNaN(Number(value))) {
104
+ alert('갭 크기는 0 이상의 숫자여야 합니다.');
105
+ event.target.value = gapSize.value; // 원래 값으로 복원
106
+ return;
107
+ }
108
+
109
+ const { result, message } = setGapSize(Number(value));
110
+
111
+ if (!result) {
112
+ alert(message);
98
113
  }
99
114
  }
100
115
  </script>
@@ -171,6 +171,7 @@ class LayoutEngine {
171
171
  // 1. layoutName(내부 변수) 변경
172
172
  this._layoutName = name;
173
173
 
174
+ const currentGridRatio = { ...this.gridRatio };
174
175
  const { layoutData: userData, gridRatio, gapSize } = screenConfig || {};
175
176
  // 2. layoutData 기본값 세팅
176
177
  this._prepareLayoutData(name, userData);
@@ -179,7 +180,7 @@ class LayoutEngine {
179
180
  this._prepareLayoutConfig(name, gridRatio ?? null, gapSize ?? null);
180
181
 
181
182
  // 초기 설정인 경우 설정값 전파
182
- if (screenConfig) {
183
+ if (setting) {
183
184
  this.eventBus.emit('layout:setLayoutName', {
184
185
  $screenConfig: screenConfig,
185
186
  $layoutData: this.layoutData,
@@ -196,6 +197,7 @@ class LayoutEngine {
196
197
  $gridNumber: this.gridNumber,
197
198
  $gridRatio: this.gridRatio,
198
199
  $gapSize: this.gapSize,
200
+ $prev: { gridRatio: currentGridRatio },
199
201
  timestamp: Date.now(),
200
202
  });
201
203
  }
@@ -267,14 +269,14 @@ class LayoutEngine {
267
269
  * @param {number} size - 새로운 갭 사이즈
268
270
  */
269
271
  setGapSize(size) {
270
- if (Number(size) < 0 || isNaN(Number(size))) return;
271
-
272
272
  this.gapSize = size;
273
273
 
274
274
  this.eventBus.emit('layout:updateGapSize', {
275
275
  $gapSize: this.gapSize,
276
276
  timestamp: Date.now(),
277
277
  });
278
+
279
+ return { result: true, message: '갭 사이즈가 성공적으로 변경되었습니다.' };
278
280
  }
279
281
 
280
282
  /** 섹션 비율 변경
@@ -283,6 +285,11 @@ class LayoutEngine {
283
285
  * @param {number} ratio - 새로운 비율 값
284
286
  */
285
287
  setRatio(type, index, ratio) {
288
+ const prevRatio = {
289
+ column: [...this.gridRatio.column],
290
+ row: [...this.gridRatio.row],
291
+ };
292
+
286
293
  const ratioArray = this.gridRatio[type];
287
294
  ratioArray[index] = Number(ratio);
288
295
 
@@ -328,6 +335,7 @@ class LayoutEngine {
328
335
  this.eventBus.emit('layout:updateRatio', {
329
336
  $type: type,
330
337
  $gridRatio: this.gridRatio,
338
+ $prev: { gridRatio: prevRatio },
331
339
  timestamp: Date.now(),
332
340
  });
333
341
 
@@ -34,6 +34,7 @@ class EngineManager {
34
34
  // (캐시) dataConverter에서 사용하는 현재 컨테이너 크기
35
35
  this._containerWidth = 1920;
36
36
  this._containerHeight = 1080;
37
+ this._displaySize = { px: 1920, aspectRatio: '16/9' };
37
38
 
38
39
  this._subscriptions = [];
39
40
  this._initialized = false;
@@ -172,6 +173,7 @@ class EngineManager {
172
173
  /** [내부함수] displayEngine 연결 설정 */
173
174
  _setupDisplayEngineConnections() {
174
175
  this._subscribe('display:displayChanged', ({ $displaySize, prev }) => {
176
+ this._displaySize = $displaySize;
175
177
  this._updateElementsScale(prev.displaySize, $displaySize);
176
178
  });
177
179
  }
@@ -202,14 +204,25 @@ class EngineManager {
202
204
  /** ---------------------------------- layout Engine ---------------------------------- **/
203
205
  /** [내부함수] layoutEngine 연결 설정 */
204
206
  _setupLayoutEngineConnections() {
207
+ this._subscribe('layout:updateRatio', ({ $type, $gridRatio, $prev }) => {
208
+ const prevGridRatio = $prev?.gridRatio || { column: [100], row: [100] };
209
+ this._updateElementsScaleByRatio($type, prevGridRatio, $gridRatio);
210
+ });
211
+
205
212
  // layoutName 변경에 따른 activeSection 초기화
206
- this._subscribe('layout:setLayoutName', ({ $layoutData }) => {
213
+ this._subscribe('layout:setLayoutName', ({ $layoutData, $screenConfig }) => {
214
+ this._displaySize = { ...$screenConfig.displaySize };
215
+
207
216
  this.state.layoutData = $layoutData;
208
217
  this.setActiveSection('section1', true);
209
218
  });
210
- this._subscribe('layout:updateLayoutName', ({ $layoutData }) => {
219
+
220
+ this._subscribe('layout:updateLayoutName', ({ $layoutData, $gridRatio, $prev }) => {
211
221
  this.state.layoutData = $layoutData;
212
222
  this.setActiveSection(null, true);
223
+
224
+ const prevGridRatio = $prev?.gridRatio || { column: [100], row: [100] };
225
+ this._updateElementsScaleByRatio('column', prevGridRatio, $gridRatio);
213
226
  });
214
227
 
215
228
  this._subscribe('layout:updateLayoutData', ({ $layoutData, activeSection }) => {
@@ -217,6 +230,53 @@ class EngineManager {
217
230
  });
218
231
  }
219
232
 
233
+ _updateElementsScaleByRatio(type, oldValue, newValue) {
234
+ const oldLength = oldValue[type].length;
235
+ const newLength = newValue[type].length;
236
+
237
+ let newDisplaySize = { ...this._displaySize };
238
+
239
+ // 열 또는 행 개수가 늘어나는 경우 - 요소 크기 줄이기
240
+ if (oldLength < newLength) {
241
+ newDisplaySize.px = newDisplaySize.px / newLength;
242
+ this._updateElementsScale(this._displaySize, newDisplaySize);
243
+ }
244
+ // 열 또는 행 개수가 줄어드는 경우 - 요소 크기 늘리기
245
+ else if (oldLength > newLength) {
246
+ newDisplaySize.px = newDisplaySize.px / oldLength;
247
+ this._updateElementsScale(newDisplaySize, this._displaySize);
248
+ }
249
+ // 열 또는 행 개수는 동일하지만 비율이 변경되는 경우 - 요소 크기 조정
250
+ else {
251
+ this.state.elements = this.state.elements.map((el) => {
252
+ const sectionIndex = el.section ? parseInt(el.section.replace('section', '')) - 1 : 0;
253
+ const oldRatio = oldValue[type][sectionIndex] / 100;
254
+ const newRatio = newValue[type][sectionIndex] / 100;
255
+
256
+ const scaleFactor = newRatio / oldRatio;
257
+ return type === 'column'
258
+ ? {
259
+ ...el,
260
+ position: { ...el.position, x: el.position.x * scaleFactor },
261
+ size: { ...el.size, w: el.size.w * scaleFactor },
262
+ }
263
+ : {
264
+ ...el,
265
+ position: { ...el.position, y: el.position.y * scaleFactor },
266
+ size: { ...el.size, h: el.size.h * scaleFactor },
267
+ };
268
+ });
269
+ }
270
+
271
+ // nextTick(() => {
272
+ this.eventBus.emit('system:requestElementsScale', {
273
+ historyEvent: true,
274
+ $elements: this.state.elements,
275
+ timestamp: Date.now(),
276
+ });
277
+ // });
278
+ }
279
+
220
280
  /** activeSection 변경
221
281
  * @param {string} name - 섹션 이름
222
282
  * @param {boolean} setting - 설정모드 여부
@@ -177,7 +177,7 @@ function useLayout(api) {
177
177
 
178
178
  const setGapSize = (size) => {
179
179
  try {
180
- api.layout.setGapSize(size);
180
+ return api.layout.setGapSize(size);
181
181
  } catch (error) {
182
182
  console.error('[useLayout] setGapSize 실행 중 오류 발생:', error);
183
183
  }