From e984208adf4574d5da457114da815ff1522fa7e2 Mon Sep 17 00:00:00 2001 From: azmy60 Date: Tue, 13 Feb 2024 18:58:45 +0700 Subject: [PATCH] Resize row & column with guidelines --- src/js/core/row/Row.js | 28 ++-- src/js/modules/ResizeColumns/ResizeColumns.js | 126 ++++++++++++------ src/js/modules/ResizeRows/ResizeRows.js | 41 +++++- src/scss/tabulator.scss | 24 +++- 4 files changed, 160 insertions(+), 59 deletions(-) diff --git a/src/js/core/row/Row.js b/src/js/core/row/Row.js index 87823598f..8cf9afd8c 100644 --- a/src/js/core/row/Row.js +++ b/src/js/core/row/Row.js @@ -138,20 +138,11 @@ export default class Row extends CoreFeature{ //get heights when doing bulk row style calcs in virtual DOM calcHeight(force){ - var maxHeight = 0, - minHeight; - if(this.table.options.rowHeight){ this.height = this.table.options.rowHeight; }else{ - minHeight = this.table.options.resizableRows ? this.element.clientHeight : 0; - - this.cells.forEach(function(cell){ - var height = cell.getHeight(); - if(height > maxHeight){ - maxHeight = height; - } - }); + var minHeight = this.calcMinHeight(), + maxHeight = this.calcMaxHeight(); if(force){ this.height = Math.max(maxHeight, minHeight); @@ -163,6 +154,21 @@ export default class Row extends CoreFeature{ this.heightStyled = this.height ? this.height + "px" : ""; this.outerHeight = this.element.offsetHeight; } + + calcMinHeight(){ + return this.table.options.resizableRows ? this.element.clientHeight : 0; + } + + calcMaxHeight(){ + var maxHeight = 0; + this.cells.forEach(function(cell){ + var height = cell.getHeight(); + if(height > maxHeight){ + maxHeight = height; + } + }); + return maxHeight; + } //set of cells setCellHeight(){ diff --git a/src/js/modules/ResizeColumns/ResizeColumns.js b/src/js/modules/ResizeColumns/ResizeColumns.js index b105e60bb..331fa2b41 100644 --- a/src/js/modules/ResizeColumns/ResizeColumns.js +++ b/src/js/modules/ResizeColumns/ResizeColumns.js @@ -16,6 +16,7 @@ class ResizeColumns extends Module{ this.initialized = false; this.registerColumnOption("resizable", true); this.registerTableOption("resizableColumnFit", false); + this.registerTableOption("resizableColumnGuide", false); } initialize(){ @@ -208,60 +209,97 @@ class ResizeColumns extends Module{ } } + resize(e, column){ + var x = typeof e.clientX === "undefined" ? e.touches[0].clientX : e.clientX, + startDiff = x - this.startX, + moveDiff = x - this.latestX, + blockedBefore, blockedAfter; + + this.latestX = x; + + if(this.table.rtl){ + startDiff = -startDiff; + moveDiff = -moveDiff; + } + + blockedBefore = column.width == column.minWidth || column.width == column.maxWidth; + + column.setWidth(this.startWidth + startDiff); + + blockedAfter = column.width == column.minWidth || column.width == column.maxWidth; + + if(moveDiff < 0){ + this.nextColumn = this.initialNextColumn; + } + + if(this.table.options.resizableColumnFit && this.nextColumn && !(blockedBefore && blockedAfter)){ + let colWidth = this.nextColumn.getWidth(); + + if(moveDiff > 0){ + if(colWidth <= this.nextColumn.minWidth){ + this.nextColumn = this.nextColumn.nextColumn(); + } + } + + if(this.nextColumn){ + this.nextColumn.setWidth(this.nextColumn.getWidth() - moveDiff); + } + } + + this.table.columnManager.rerenderColumns(true); + + if(!this.table.browserSlow && column.modules.resize && column.modules.resize.variableHeight){ + column.checkCellHeights(); + } + } + + calcGuidePosition(e, column, handle) { + var mouseX = typeof e.clientX === "undefined" ? e.touches[0].clientX : e.clientX, + handleX = handle.getBoundingClientRect().x - this.table.element.getBoundingClientRect().x, + tableX = this.table.element.getBoundingClientRect().x, + columnX = column.element.getBoundingClientRect().left - tableX, + mouseDiff = mouseX - this.startX, + pos = Math.max(handleX + mouseDiff, columnX + column.minWidth); + + if(column.maxWidth){ + pos = Math.min(pos, columnX + column.maxWidth); + } + + return pos; + } + _checkResizability(column){ return column.definition.resizable; } _mouseDown(e, column, handle){ - var self = this; - + var self = this, + guideEl; + + if(self.table.options.resizableColumnGuide){ + guideEl = document.createElement("span"); + guideEl.classList.add('tabulator-col-resize-guide'); + self.table.element.appendChild(guideEl); + setTimeout(() => { + guideEl.style.left = self.calcGuidePosition(e, column, handle) + "px"; + }) + } + self.table.element.classList.add("tabulator-block-select"); - + function mouseMove(e){ - var x = typeof e.screenX === "undefined" ? e.touches[0].screenX : e.screenX, - startDiff = x - self.startX, - moveDiff = x - self.latestX, - blockedBefore, blockedAfter; - - self.latestX = x; - - if(self.table.rtl){ - startDiff = -startDiff; - moveDiff = -moveDiff; - } - - blockedBefore = column.width == column.minWidth || column.width == column.maxWidth; - - column.setWidth(self.startWidth + startDiff); - - blockedAfter = column.width == column.minWidth || column.width == column.maxWidth; - - if(moveDiff < 0){ - self.nextColumn = self.initialNextColumn; - } - - if(self.table.options.resizableColumnFit && self.nextColumn && !(blockedBefore && blockedAfter)){ - let colWidth = self.nextColumn.getWidth(); - - if(moveDiff > 0){ - if(colWidth <= self.nextColumn.minWidth){ - self.nextColumn = self.nextColumn.nextColumn(); - } - } - - if(self.nextColumn){ - self.nextColumn.setWidth(self.nextColumn.getWidth() - moveDiff); - } - } - - self.table.columnManager.rerenderColumns(true); - - if(!self.table.browserSlow && column.modules.resize && column.modules.resize.variableHeight){ - column.checkCellHeights(); + if(self.table.options.resizableColumnGuide){ + guideEl.style.left = self.calcGuidePosition(e, column, handle) + "px"; + }else{ + self.resize(e, column); } } function mouseUp(e){ + if(self.table.options.resizableColumnGuide){ + self.resize(e, column); + guideEl.remove(); + } //block editor from taking action while resizing is taking place if(self.startColumn.modules.edit){ @@ -295,7 +333,7 @@ class ResizeColumns extends Module{ self.startColumn.modules.edit.blocked = true; } - self.startX = typeof e.screenX === "undefined" ? e.touches[0].screenX : e.screenX; + self.startX = typeof e.clientX === "undefined" ? e.touches[0].clientX : e.clientX; self.latestX = self.startX; self.startWidth = column.getWidth(); diff --git a/src/js/modules/ResizeRows/ResizeRows.js b/src/js/modules/ResizeRows/ResizeRows.js index f1b95b73d..515a4d9df 100644 --- a/src/js/modules/ResizeRows/ResizeRows.js +++ b/src/js/modules/ResizeRows/ResizeRows.js @@ -12,6 +12,7 @@ class ResizeRows extends Module{ this.prevHandle = null; this.registerTableOption("resizableRows", false); //resizable rows + this.registerTableOption("resizableRowGuide", false); } initialize(){ @@ -62,16 +63,50 @@ class ResizeRows extends Module{ rowEl.appendChild(prevHandle); } + resize(e, row) { + row.setHeight(self.startHeight + ((typeof e.clientY === "undefined" ? e.touches[0].clientY : e.clientY) - self.startY)); + } + + calcGuidePosition(e, row, handle) { + var mouseY = typeof e.clientY === "undefined" ? e.touches[0].clientY : e.clientY, + handleY = handle.getBoundingClientRect().y - this.table.element.getBoundingClientRect().y, + tableY = this.table.element.getBoundingClientRect().y, + rowY = row.element.getBoundingClientRect().top - tableY, + mouseDiff = mouseY - this.startY, + minHeight = row.calcMinHeight(), + maxHeight = row.calcMaxHeight(); + + return Math.min(Math.max(handleY + mouseDiff, rowY + minHeight), rowY + maxHeight); + } + _mouseDown(e, row, handle){ - var self = this; + var self = this, + guideEl; + + if(self.table.options.resizableRowGuide){ + guideEl = document.createElement("span"); + guideEl.classList.add('tabulator-row-resize-guide'); + self.table.element.appendChild(guideEl); + setTimeout(() => { + guideEl.style.top = self.calcGuidePosition(e, row, handle) + "px"; + }) + } self.table.element.classList.add("tabulator-block-select"); function mouseMove(e){ - row.setHeight(self.startHeight + ((typeof e.screenY === "undefined" ? e.touches[0].screenY : e.screenY) - self.startY)); + if(self.table.options.resizableRowGuide){ + guideEl.style.top = self.calcGuidePosition(e, row, handle) + "px"; + }else{ + self.resize(e, row); + } } function mouseUp(e){ + if(self.table.options.resizableRowGuide){ + self.resize(e, row); + guideEl.remove(); + } // //block editor from taking action while resizing is taking place // if(self.startColumn.modules.edit){ @@ -96,7 +131,7 @@ class ResizeRows extends Module{ // self.startColumn.modules.edit.blocked = true; // } - self.startY = typeof e.screenY === "undefined" ? e.touches[0].screenY : e.screenY; + self.startY = typeof e.clientY === "undefined" ? e.touches[0].clientY : e.clientY; self.startHeight = row.getHeight(); document.body.addEventListener("mousemove", mouseMove); diff --git a/src/scss/tabulator.scss b/src/scss/tabulator.scss index 37a5e2a3c..4eec43777 100644 --- a/src/scss/tabulator.scss +++ b/src/scss/tabulator.scss @@ -16,6 +16,8 @@ $sortArrowHover: #555 !default; $sortArrowActive: #666 !default; $sortArrowInactive: #bbb !default; +$columnResizeGuideColor:#999 !default; + //row theming $rowBackgroundColor:#fff !default; //table row background color $rowAltBackgroundColor:#EFEFEF !default; //table row background color @@ -1580,4 +1582,24 @@ body.tabulator-print-fullscreen-hide>*:not(.tabulator-print-fullscreen){ } } } -} \ No newline at end of file +} + +.tabulator-col-resize-guide { + position: absolute; + top: 0; + width: 4px; + height: 100%; + margin-left: -0.5px; + background-color: $columnResizeGuideColor; + opacity: .5; +} + +.tabulator-row-resize-guide { + position: absolute; + left: 0; + width: 100%; + height: 4px; + margin-top: -0.5px; + background-color: $columnResizeGuideColor; + opacity: .5; +}