evui 3.3.35 → 3.3.36

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": "evui",
3
- "version": "3.3.35",
3
+ "version": "3.3.36",
4
4
  "description": "A EXEM Library project",
5
5
  "author": "exem <dev_client@ex-em.com>",
6
6
  "license": "MIT",
@@ -97,51 +97,59 @@ import { onMounted, onBeforeUnmount, watch, onDeactivated } from 'vue';
97
97
  }
98
98
  };
99
99
 
100
+ watch(() => props.options, (chartOpt) => {
101
+ const newOpt = getNormalizedOptions(chartOpt);
102
+
103
+ const isUpdateLegendType = !isEqual(newOpt.legend.table, evChart.options.legend.table);
104
+
105
+ evChart.options = cloneDeep(newOpt);
106
+
107
+ evChart.update({
108
+ updateSeries: false,
109
+ updateSelTip: { update: false, keepDomain: false },
110
+ updateLegend: isUpdateLegendType,
111
+ });
112
+ }, { deep: true });
113
+
114
+ watch(() => props.data, (chartData) => {
115
+ const newData = getNormalizedData(chartData);
116
+
117
+ const isUpdateSeries = !isEqual(newData.series, evChart.data.series)
118
+ || !isEqual(newData.groups, evChart.data.groups)
119
+ || props.options.type === 'heatMap';
120
+
121
+ const isUpdateData = !isEqual(newData.data, evChart.data);
122
+
123
+ evChart.data = cloneDeep(newData);
124
+
125
+ evChart.update({
126
+ updateSeries: isUpdateSeries,
127
+ updateSelTip: { update: true, keepDomain: false },
128
+ updateData: isUpdateData,
129
+ });
130
+ }, { deep: true });
131
+
132
+ watch(() => props.selectedItem, (newValue) => {
133
+ const chartType = props.options?.type;
134
+
135
+ evChart.selectItemByData(newValue, chartType);
136
+ }, { deep: true });
137
+
138
+ watch(() => props.selectedLabel, (newValue) => {
139
+ if (newValue.dataIndex) {
140
+ evChart.renderWithSelected(newValue.dataIndex);
141
+ }
142
+ }, { deep: true });
143
+
144
+ watch(() => props.selectedSeries, (newValue) => {
145
+ if (newValue.seriesId) {
146
+ evChart.renderWithSelected(newValue.seriesId);
147
+ }
148
+ }, { deep: true });
149
+
100
150
  onMounted(async () => {
101
151
  await createChart();
102
152
  await drawChart();
103
-
104
- await watch(() => props.options, (chartOpt) => {
105
- const newOpt = getNormalizedOptions(chartOpt);
106
- const isUpdateLegend = !isEqual(newOpt.legend, evChart.options.legend);
107
- evChart.options = cloneDeep(newOpt);
108
- evChart.update({
109
- updateSeries: false,
110
- updateSelTip: { update: false, keepDomain: false },
111
- updateLegend: isUpdateLegend,
112
- });
113
- }, { deep: true });
114
-
115
- await watch(() => props.data, (chartData) => {
116
- const newData = getNormalizedData(chartData);
117
- const isUpdateSeries = !isEqual(newData.series, evChart.data.series)
118
- || !isEqual(newData.groups, evChart.data.groups)
119
- || props.options.type === 'heatMap';
120
- const isUpdateData = !isEqual(newData.data, evChart.data);
121
- evChart.data = cloneDeep(newData);
122
- evChart.update({
123
- updateSeries: isUpdateSeries,
124
- updateSelTip: { update: true, keepDomain: false },
125
- updateData: isUpdateData,
126
- });
127
- }, { deep: true });
128
-
129
- await watch(() => props.selectedItem, (newValue) => {
130
- const chartType = props.options?.type;
131
- evChart.selectItemByData(newValue, chartType);
132
- }, { deep: true });
133
-
134
- await watch(() => props.selectedLabel, (newValue) => {
135
- if (newValue.dataIndex) {
136
- evChart.renderWithSelected(newValue.dataIndex);
137
- }
138
- }, { deep: true });
139
-
140
- await watch(() => props.selectedSeries, (newValue) => {
141
- if (newValue.seriesId) {
142
- evChart.renderWithSelected(newValue.seriesId);
143
- }
144
- }, { deep: true });
145
153
  });
146
154
 
147
155
  onBeforeUnmount(() => {
@@ -792,9 +792,11 @@ class EvChart {
792
792
  * @returns {undefined}
793
793
  */
794
794
  render(hitInfo) {
795
- this.clear();
796
- this.chartRect = this.getChartRect();
797
- this.drawChart(hitInfo);
795
+ if (this.isInit) {
796
+ this.clear();
797
+ this.chartRect = this.getChartRect();
798
+ this.drawChart(hitInfo);
799
+ }
798
800
  }
799
801
 
800
802
  /**
@@ -112,7 +112,7 @@ const modules = {
112
112
  */
113
113
  this.onClick = (e) => {
114
114
  const args = { e };
115
- if (this.options.selectItem.use) {
115
+ if (this.options.selectItem.use && this.options.selectItem.useClick) {
116
116
  const offset = this.getMousePosition(e);
117
117
  const hitInfo = this.getItemByPosition(offset, false);
118
118
 
@@ -127,14 +127,14 @@ const modules = {
127
127
  maxIndex: args.dataIndex,
128
128
  acc: args.acc,
129
129
  } = hitInfo);
130
- } else if (this.options.selectLabel.use) {
130
+ } else if (this.options.selectLabel.use && this.options.selectLabel.useClick) {
131
131
  const offset = this.getMousePosition(e);
132
132
  const clickedLabelInfo = this.getLabelInfoByPosition(offset);
133
133
  const selected = this.selectLabel(clickedLabelInfo.labelIndex);
134
134
  this.renderWithSelected(selected.dataIndex);
135
135
 
136
136
  args.selected = cloneDeep(this.defaultSelectInfo);
137
- } else if (this.options.selectSeries.use) {
137
+ } else if (this.options.selectSeries.use && this.options.selectSeries.useClick) {
138
138
  const offset = this.getMousePosition(e);
139
139
  const hitInfo = this.getSeriesIdByPosition(offset);
140
140
  if (hitInfo.sId !== null) {
@@ -103,6 +103,7 @@ const DEFAULT_OPTIONS = {
103
103
  },
104
104
  selectItem: {
105
105
  use: false,
106
+ useClick: true,
106
107
  showTextTip: false,
107
108
  tipText: 'value',
108
109
  showTip: false,
@@ -116,6 +117,7 @@ const DEFAULT_OPTIONS = {
116
117
  },
117
118
  selectLabel: {
118
119
  use: false,
120
+ useClick: true,
119
121
  limit: 1,
120
122
  useDeselectOverflow: false,
121
123
  showTip: false,
@@ -127,6 +129,7 @@ const DEFAULT_OPTIONS = {
127
129
  },
128
130
  selectSeries: {
129
131
  use: false,
132
+ useClick: true,
130
133
  limit: 1,
131
134
  useDeselectOverflow: false,
132
135
  },
@@ -79,6 +79,8 @@
79
79
  :style="{
80
80
  width: `${column.width}px`,
81
81
  'min-width': `${isRenderer(column) ? rendererMinWidth : minWidth}px`,
82
+ 'margin-right': (orderedColumns.length - 1 === index
83
+ && hasVerticalScrollBar && hasHorizontalScrollBar) ? `${scrollWidth}px` : '0px',
82
84
  }"
83
85
  >
84
86
  <!-- Filter Status -->
@@ -142,7 +144,7 @@
142
144
  :style="`height: ${vScrollTopHeight}px;`"
143
145
  class="vscroll-spacer"
144
146
  />
145
- <table>
147
+ <table ref="table">
146
148
  <tbody>
147
149
  <!-- Row List -->
148
150
  <tr
@@ -359,6 +361,7 @@ export default {
359
361
  const elementInfo = reactive({
360
362
  body: null,
361
363
  header: null,
364
+ table: null,
362
365
  resizeLine: null,
363
366
  'grid-wrapper': null,
364
367
  });
@@ -417,6 +420,7 @@ export default {
417
420
  vScrollTopHeight: 0,
418
421
  vScrollBottomHeight: 0,
419
422
  hasVerticalScrollBar: false,
423
+ hasHorizontalScrollBar: false,
420
424
  });
421
425
  const selectInfo = reactive({
422
426
  selectedRow: props.selected,
@@ -443,7 +447,7 @@ export default {
443
447
  rendererMinWidth: 80,
444
448
  iconWidth: 42,
445
449
  showResizeLine: false,
446
- adjust: computed(() => (props.option.adjust || false)),
450
+ adjust: props.option.adjust || false,
447
451
  columnWidth: props.option.columnWidth || 80,
448
452
  scrollWidth: props.option.scrollWidth || 17,
449
453
  rowHeight: computed(() =>
@@ -552,6 +556,7 @@ export default {
552
556
  filterInfo,
553
557
  isRenderer,
554
558
  updateVScroll,
559
+ updateHScroll,
555
560
  });
556
561
 
557
562
  const {
@@ -692,7 +697,7 @@ export default {
692
697
  },
693
698
  );
694
699
  watch(
695
- () => [resizeInfo.adjust, props.option.columnWidth, resizeInfo.gridWidth],
700
+ () => [props.option.columnWidth, resizeInfo.gridWidth],
696
701
  () => {
697
702
  resizeInfo.columnWidth = props.option.columnWidth;
698
703
  const gridWrapper = elementInfo['grid-wrapper'];
@@ -59,9 +59,6 @@
59
59
  }
60
60
  &:nth-last-child(1) {
61
61
  border-right: 0;
62
- .column-resize {
63
- cursor: default !important;
64
- }
65
62
  }
66
63
  .sort-icon {
67
64
  display: inline-block;
@@ -102,9 +102,11 @@ export const scrollEvent = (params) => {
102
102
  const lastVisibleIndex = firstVisibleIndex + rowCount + 1;
103
103
  const firstIndex = Math.max(firstVisibleIndex, 0);
104
104
  const lastIndex = lastVisibleIndex;
105
+ const tableEl = elementInfo.table;
105
106
 
106
107
  stores.viewStore = store.slice(firstIndex, lastIndex);
107
- scrollInfo.hasVerticalScrollBar = rowCount < store.length;
108
+ scrollInfo.hasVerticalScrollBar = rowCount < store.length
109
+ || bodyEl.clientHeight < tableEl.clientHeight;
108
110
  scrollInfo.vScrollTopHeight = firstIndex * rowHeight;
109
111
  scrollInfo.vScrollBottomHeight = totalScrollHeight - (stores.viewStore.length * rowHeight)
110
112
  - scrollInfo.vScrollTopHeight;
@@ -122,9 +124,11 @@ export const scrollEvent = (params) => {
122
124
  const updateHScroll = () => {
123
125
  const headerEl = elementInfo.header;
124
126
  const bodyEl = elementInfo.body;
127
+ const tableEl = elementInfo.table;
125
128
 
126
129
  headerEl.scrollLeft = bodyEl.scrollLeft;
127
130
  summaryScroll.value = bodyEl.scrollLeft;
131
+ scrollInfo.hasHorizontalScrollBar = bodyEl.clientWidth < tableEl.clientWidth;
128
132
  };
129
133
  /**
130
134
  * scroll 이벤트를 처리한다.
@@ -154,26 +158,15 @@ export const scrollEvent = (params) => {
154
158
 
155
159
  export const resizeEvent = (params) => {
156
160
  const { props } = getCurrentInstance();
157
- const { resizeInfo, elementInfo, checkInfo, stores, isRenderer, updateVScroll } = params;
158
- /**
159
- * 해당 컬럼 인덱스가 마지막인지 확인한다.
160
- *
161
- * @param {number} index - 컬럼 인덱스
162
- * @returns {boolean} 마지막 컬럼 유무
163
- */
164
- const isLastColumn = (index) => {
165
- const columns = stores.orderedColumns;
166
- let lastIndex = -1;
167
-
168
- for (let ix = columns.length - 1; ix >= 0; ix--) {
169
- if (!columns[ix].hide) {
170
- lastIndex = ix;
171
- break;
172
- }
173
- }
174
-
175
- return lastIndex === index;
176
- };
161
+ const {
162
+ resizeInfo,
163
+ elementInfo,
164
+ checkInfo,
165
+ stores,
166
+ isRenderer,
167
+ updateVScroll,
168
+ updateHScroll,
169
+ } = params;
177
170
  /**
178
171
  * 고정 너비, 스크롤 유무 등에 따른 컬럼 너비를 계산한다.
179
172
  */
@@ -264,6 +257,9 @@ export const resizeEvent = (params) => {
264
257
  if (elementInfo.body?.clientHeight) {
265
258
  updateVScroll();
266
259
  }
260
+ if (elementInfo.body?.clientWidth) {
261
+ updateHScroll();
262
+ }
267
263
  });
268
264
  };
269
265
 
@@ -280,62 +276,54 @@ export const resizeEvent = (params) => {
280
276
  * @param {object} event - 이벤트 객체
281
277
  */
282
278
  const onColumnResize = (columnIndex, event) => {
283
- let nextColumnIndex = columnIndex + 1;
284
279
  const headerEl = elementInfo.header;
280
+ const bodyEl = elementInfo.body;
285
281
  const headerLeft = headerEl.getBoundingClientRect().left;
286
282
  const columnEl = headerEl.querySelector(`li[data-index="${columnIndex}"]`);
287
- if (!isLastColumn(columnIndex) && !columnEl.className.includes('db-icon')
288
- && !columnEl.className.includes('user-icon')) {
289
- while (stores.orderedColumns[nextColumnIndex].hide) {
290
- nextColumnIndex++;
283
+ const minWidth = isRenderer(stores.orderedColumns[columnIndex])
284
+ ? resizeInfo.rendererMinWidth : resizeInfo.minWidth;
285
+ const columnRect = columnEl.getBoundingClientRect();
286
+ const maxRight = bodyEl.getBoundingClientRect().right - headerLeft;
287
+ const resizeLineEl = elementInfo.resizeLine;
288
+ const minLeft = columnRect.left - headerLeft + minWidth;
289
+ const startLeft = columnRect.right - headerLeft;
290
+ const startMouseLeft = event.clientX;
291
+ const startColumnLeft = columnRect.left - headerLeft;
292
+
293
+ resizeLineEl.style.left = `${startLeft}px`;
294
+
295
+ resizeInfo.showResizeLine = true;
296
+
297
+ const handleMouseMove = (evt) => {
298
+ const deltaLeft = evt.clientX - startMouseLeft;
299
+ const proxyLeft = startLeft + deltaLeft;
300
+ let resizeWidth = Math.max(minLeft, proxyLeft);
301
+
302
+ resizeWidth = Math.min(maxRight, resizeWidth);
303
+
304
+ resizeLineEl.style.left = `${resizeWidth}px`;
305
+ };
306
+
307
+ const handleMouseUp = () => {
308
+ const destLeft = parseInt(resizeLineEl.style.left, 10);
309
+ const changedWidth = destLeft - startColumnLeft;
310
+
311
+ if (stores.orderedColumns[columnIndex]) {
312
+ stores.orderedColumns[columnIndex].width = changedWidth;
313
+ stores.orderedColumns.map((column) => {
314
+ const item = column;
315
+ item.resized = true;
316
+ return item;
317
+ });
291
318
  }
292
- const minWidth = isRenderer(stores.orderedColumns[columnIndex])
293
- ? resizeInfo.rendererMinWidth : resizeInfo.minWidth;
294
- const nextMinWidth = isRenderer(stores.orderedColumns[nextColumnIndex])
295
- ? resizeInfo.rendererMinWidth : resizeInfo.minWidth;
296
- const nextColumnEl = headerEl.querySelector(`li[data-index="${nextColumnIndex}"]`);
297
- const columnRect = columnEl.getBoundingClientRect();
298
- const maxRight = nextColumnEl.getBoundingClientRect().right - headerLeft - nextMinWidth;
299
- const resizeLineEl = elementInfo.resizeLine;
300
- const minLeft = columnRect.left - headerLeft + minWidth;
301
- const startLeft = columnRect.right - headerLeft;
302
- const startMouseLeft = event.clientX;
303
- const startColumnLeft = columnRect.left - headerLeft;
304
-
305
- resizeLineEl.style.left = `${startLeft}px`;
306
-
307
- resizeInfo.showResizeLine = true;
308
-
309
- const handleMouseMove = (evt) => {
310
- const deltaLeft = evt.clientX - startMouseLeft;
311
- const proxyLeft = startLeft + deltaLeft;
312
- let resizeWidth = Math.max(minLeft, proxyLeft);
313
-
314
- resizeWidth = Math.min(maxRight, resizeWidth);
315
-
316
- resizeLineEl.style.left = `${resizeWidth}px`;
317
- };
318
-
319
- const handleMouseUp = () => {
320
- const destLeft = parseInt(resizeLineEl.style.left, 10);
321
- const changedWidth = destLeft - startColumnLeft;
322
-
323
- if (stores.orderedColumns[columnIndex]) {
324
- const columnWidth = stores.orderedColumns[columnIndex].width;
325
- stores.orderedColumns[columnIndex].width = changedWidth;
326
- stores.orderedColumns[columnIndex].resized = true;
327
- stores.orderedColumns[nextColumnIndex].width += (columnWidth - changedWidth);
328
- stores.orderedColumns[nextColumnIndex].resized = true;
329
- }
330
319
 
331
- resizeInfo.showResizeLine = false;
332
- document.removeEventListener('mousemove', handleMouseMove);
333
- onResize();
334
- };
320
+ resizeInfo.showResizeLine = false;
321
+ document.removeEventListener('mousemove', handleMouseMove);
322
+ onResize();
323
+ };
335
324
 
336
- document.addEventListener('mousemove', handleMouseMove);
337
- document.addEventListener('mouseup', handleMouseUp, { once: true });
338
- }
325
+ document.addEventListener('mousemove', handleMouseMove);
326
+ document.addEventListener('mouseup', handleMouseUp, { once: true });
339
327
  };
340
328
  return { calculatedColumn, onResize, onShow, onColumnResize };
341
329
  };
@@ -793,9 +781,9 @@ export const filterEvent = (params) => {
793
781
  let isShow = false;
794
782
  for (let ix = 0; ix < stores.orderedColumns.length; ix++) {
795
783
  const column = stores.orderedColumns[ix] || {};
796
- let columnValue = row[ROW_DATA_INDEX][ix];
784
+ let columnValue = row[ROW_DATA_INDEX][ix] ?? null;
797
785
  column.type = column.type || 'string';
798
- if (columnValue) {
786
+ if (columnValue !== null) {
799
787
  if (typeof columnValue === 'object') {
800
788
  columnValue = columnValue[column.field];
801
789
  }
@@ -59,7 +59,7 @@
59
59
  v-if="!column.hide"
60
60
  :data-index="index"
61
61
  :class="getColumnClass(column)"
62
- :style="getColumnStyle(column)"
62
+ :style="getColumnStyle(column, index)"
63
63
  >
64
64
  <!-- Column Name -->
65
65
  <span
@@ -90,7 +90,7 @@
90
90
  :style="`height: ${vScrollTopHeight}px;`"
91
91
  class="vscroll-spacer"
92
92
  />
93
- <table>
93
+ <table ref="table">
94
94
  <tbody>
95
95
  <tree-grid-node
96
96
  v-for="(node, idx) in viewStore"
@@ -264,6 +264,7 @@ export default {
264
264
  const elementInfo = reactive({
265
265
  body: null,
266
266
  header: null,
267
+ table: null,
267
268
  resizeLine: null,
268
269
  'grid-wrapper': null,
269
270
  });
@@ -322,6 +323,7 @@ export default {
322
323
  vScrollTopHeight: 0,
323
324
  vScrollBottomHeight: 0,
324
325
  hasVerticalScrollBar: false,
326
+ hasHorizontalScrollBar: false,
325
327
  });
326
328
  const selectInfo = reactive({
327
329
  selectedRow: props.selected,
@@ -342,7 +344,7 @@ export default {
342
344
  minWidth: 40,
343
345
  rendererMinWidth: 80,
344
346
  showResizeLine: false,
345
- adjust: computed(() => props.option.adjust || false),
347
+ adjust: props.option.adjust || false,
346
348
  columnWidth: props.option.columnWidth || 80,
347
349
  scrollWidth: props.option.scrollWidth || 17,
348
350
  rowHeight: computed(() => props.option.rowHeight || 35),
@@ -426,6 +428,7 @@ export default {
426
428
  stores,
427
429
  isRenderer,
428
430
  updateVScroll,
431
+ updateHScroll,
429
432
  });
430
433
 
431
434
  const {
@@ -595,7 +598,7 @@ export default {
595
598
  },
596
599
  );
597
600
  watch(
598
- () => [props.width, props.height, resizeInfo.adjust, props.option.columnWidth],
601
+ () => [props.width, props.height, props.option.columnWidth],
599
602
  (value) => {
600
603
  resizeInfo.columnWidth = value[3];
601
604
  stores.orderedColumns.map((column) => {
@@ -690,11 +693,14 @@ export default {
690
693
  'non-border': !!styleInfo.borderStyle,
691
694
  };
692
695
  };
693
- const getColumnStyle = (column) => {
696
+ const getColumnStyle = (column, index) => {
694
697
  const render = isRenderer(column);
695
698
  return {
696
699
  width: `${column.width}px`,
697
700
  'min-width': render ? `${resizeInfo.rendererMinWidth}px;` : `${resizeInfo.minWidth}px`,
701
+ 'margin-right': (stores.orderedColumns.length - 1 === index
702
+ && scrollInfo.hasVerticalScrollBar
703
+ && scrollInfo.hasHorizontalScrollBar) ? `${resizeInfo.scrollWidth}px` : '0px',
698
704
  };
699
705
  };
700
706
  const getSlotName = column => `${column}Node`;
@@ -55,9 +55,6 @@
55
55
  }
56
56
  &:nth-last-child(1) {
57
57
  border-right: 0;
58
- .column-resize {
59
- cursor: default !important;
60
- }
61
58
  }
62
59
  .sort-icon {
63
60
  display: inline-block;