fin-hypergrid / core

A canvas-based super high performant grid renderer API
MIT License
897 stars 144 forks source link

Column resize behavior - resize only adjacent columns, not entire grid #749

Closed RandomGHUser closed 6 years ago

RandomGHUser commented 6 years ago

The default column resize behavior is to stretch/shrink the column to the left of the mouse cursor, while just moving the rest of the canvas on the right side of the cursor. Is there a way to change this behavior, so that only the column to the right of the cursor gets expand/shrunk with the left, so that the rest of the grid does not get affected by column resize?

joneit commented 6 years ago

Yes, but it's not a feature. You would have to monkey-patch at least the handleMouseDown and handleMouseDrag method in the column resizing feature, something like the following (untested):

In handleMouseDown add following lines to note the next column (column to the right) and its starting width:

this.nextColumn = grid.behavior.columns[grid.behavior.columns.findIndex(function(column) {
    return column === this.dragColumn;
}, this)];
if (this.nextColumn) {
    this.nextColumnStart = this.nextColumn.getWidth();
}

In handleMouseDrag add following lines to add a second call to setColumnWidth for the next column when there is one (there won't be one on the last column):

if (this.nextColumn) {
    grid.behavior.setColumnWidth(this.nextColumn, this.nextColumnStart - delta);
}

To install the patches:

var ColumnResizing = require('fin-hypergrid/src/features/ColumnResizing'); // CommonJS
// or:
var ColumnResizing = fin.Hypergrid.require('fin-hypergrid/src/features').get('columnResizing'); // at run-time
// then:
Object.assign(ColumnResizing.prototype, {
    handleMouseDown: function myMouseDownPatch() { ... },
    handleMouseDrag: function myMouseDragPatch() { ... },
});

I leave up to you the edge case when the next (right) column is smaller than the left and therefore must be clamped to a minimum width.

RandomGHUser commented 6 years ago

I tried your code, but it didn't seem to work, I put in a version that quasi-works Under handleMouseDown:

this.nextColumn = grid.behavior.getColumn(columnIndex+1);
this.nextColStartWidth = grid.renderer.visibleColumns[visibleColIndex+1].width;

Under handleMouseDrag:

grid.behavior.setColumnWidth(this.nextColumn, this.nextColStartWidth - delta);

It works ~ 80% of the time, but sometimes it will not find the next column, or decides to resize a column that is not adjacent to the current one. Any ideas on correcting the code above?

joneit commented 6 years ago

Hmmm.... so the problem I think is that your columnIndex + 1 is too simplistic because columnIndex is a data index from the ordered set of all columns (behavior.allColumns), but you need the next grid index from the ordered set of active columns (behavior.columns). (Sorry about the confusion of the internal namings which is due to historical reasons.)

As for my code, it was incomplete. I meant to get the current column and then get the next column, something more like this:

var gridColumnIndex = grid.behavior.columns.findIndex(function(column) {
    return column === this.dragColumn;
}, this);
this.nextColumn = grid.behavior.columns[gridColumnIndex + 1];
if (this.nextColumn) {
    this.nextColumnStart = this.nextColumn.getWidth();
}

(I forgot the + 1 !)

RandomGHUser commented 6 years ago

Thank you for your response, the behavior is still erratic with sliding columns. While it works the majority of the time, sometimes it will drag two columns or resize oddly.

Example (all dummy data): Slide Example

joneit commented 6 years ago

I'm adding this as a feature for v3.0.2:

I hope to release v3.0.2 tonight but certainly by EOW.

joneit commented 6 years ago

Here is the jsdoc comment for the default definition:

    /**
     * Resizing a column through the UI (by clicking and dragging on the column's
     * right border in the column header row) normally affects the width of the whole grid.
     * Set this property to truthy for selected columns (`myColumn.properties.resizeNextColumn`)
     * or for the whole grid (`myGrid.properties.resizeNextColumn`)
     * to have the column resize the column to its right inversely.
     * In other words, if you expand (say) third column, then fourth column will contract;
     * and _vice versa_ — without therefore affecting the width of the whole grid.
     *
     * Note that the current implementation does not allow expanding a
     * column beyond the width it can borrow from the column to its right
     * (except for the last column which is free to grow the grid width).
     * @default
     * @type {boolean}
     * @memberOf module:defaults
     */
    resizeNextColumn: false,
joneit commented 6 years ago

I'm changing the property name to resizeColumnInPlace to make it more descriptive and to the point.

joneit commented 6 years ago

@RandomGHUser Did you try 3.0.2 (released this morning)? lmk thx

RandomGHUser commented 6 years ago

Tested 3.0.2 with the resizeColumnInPlace attribute, it is working quite well so far, I will report any issues if they occur, thank you for taking the time to implement this.