From 7de6f56e91e7e6faa787d63227d5d4f2d96e0e4e Mon Sep 17 00:00:00 2001 From: Itay Dafna Date: Mon, 21 Jun 2021 17:34:48 -0700 Subject: [PATCH 1/9] Fix wrong width edge case for column headers Signed-off-by: Itay Dafna --- packages/datagrid/src/datagrid.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/datagrid/src/datagrid.ts b/packages/datagrid/src/datagrid.ts index 355a11c70..7b696993b 100644 --- a/packages/datagrid/src/datagrid.ts +++ b/packages/datagrid/src/datagrid.ts @@ -4622,6 +4622,15 @@ class DataGrid extends Widget { continue; } } + else { + /** + * Reset column width if we're rendering a column-header + * which is not part of a merged cell group. + */ + if (rgn.region == 'column-header') { + width = this._getColumnSize(config.region, row); + } + } // Clear the buffer rect for the cell. gc.clearRect(x, y, width, height); From a24b6eb2ea8c46291b9e98fd8a40b114862c0030 Mon Sep 17 00:00:00 2001 From: Itay Dafna Date: Mon, 21 Jun 2021 19:04:37 -0700 Subject: [PATCH 2/9] Use correct column size Signed-off-by: Itay Dafna --- packages/datagrid/src/datagrid.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/datagrid/src/datagrid.ts b/packages/datagrid/src/datagrid.ts index 7b696993b..69421b53d 100644 --- a/packages/datagrid/src/datagrid.ts +++ b/packages/datagrid/src/datagrid.ts @@ -4628,7 +4628,7 @@ class DataGrid extends Widget { * which is not part of a merged cell group. */ if (rgn.region == 'column-header') { - width = this._getColumnSize(config.region, row); + width = rgn.columnSizes[i]; } } From 7e67047719d2d2bedd34aa0dc6a19e81fa0523a3 Mon Sep 17 00:00:00 2001 From: Itay Dafna Date: Fri, 2 Jul 2021 19:38:25 -0700 Subject: [PATCH 3/9] Greatly simplify rendering logic for grid with merged cells Signed-off-by: Itay Dafna --- packages/datagrid/src/datagrid.ts | 390 ++++++++++++------------------ 1 file changed, 159 insertions(+), 231 deletions(-) diff --git a/packages/datagrid/src/datagrid.ts b/packages/datagrid/src/datagrid.ts index 69421b53d..a62abbbe7 100644 --- a/packages/datagrid/src/datagrid.ts +++ b/packages/datagrid/src/datagrid.ts @@ -3109,6 +3109,24 @@ class DataGrid extends Widget { return; } + // Render entire grid if scrolling merged cells grid + const colGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'column-header'); + const rowHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'row-header'); + const cornerHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'corner-header'); + const bodyGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'body'); + const paintEverything = ( + colGroups.length > 0 + || rowHeaderGroups.length > 0 + || cornerHeaderGroups.length > 0 + || bodyGroups.length > 0); + + if (paintEverything) { + this.paintContent(0, 0, vw, vh); + this._paintOverlay(); + this._syncScrollState(); + return; + } + // Compute the size delta. let delta = newSize - oldSize; @@ -3161,15 +3179,12 @@ class DataGrid extends Widget { dy = sy + delta; } - // Offset values - const [mergeStartOffset, mergeEndOffset] = CellGroup.calculateMergeOffsets(this.dataModel!, ['body','row-header'], 'row', list, index); - // Blit the valid content to the destination. - this._blitContent(this._canvas, sx, sy + mergeEndOffset, sw, sh - mergeEndOffset, dx, dy + mergeEndOffset); + this._blitContent(this._canvas, sx, sy, sw, sh, dx, dy); // Repaint the section if needed. if (newSize > 0 && offset + newSize > hh) { - this.paintContent(0, pos - mergeStartOffset, vw, offset + newSize - pos + mergeStartOffset + mergeEndOffset); + this.paintContent(0, pos, vw, offset + newSize - pos); } // Paint the trailing space as needed. @@ -3178,7 +3193,7 @@ class DataGrid extends Widget { let y = hh + this._rowSections.offsetOf(r); this.paintContent(0, y, vw, vh - y); } else if (delta < 0) { - this.paintContent(0, vh + delta, vw, -delta + 1); + this.paintContent(0, vh + delta, vw, -delta); } // Paint the overlay. @@ -3224,6 +3239,24 @@ class DataGrid extends Widget { return; } + // Render entire grid if scrolling merged cells grid + const colGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'column-header'); + const rowHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'row-header'); + const cornerHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'corner-header'); + const bodyGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'body'); + const paintEverything = ( + colGroups.length > 0 + || rowHeaderGroups.length > 0 + || cornerHeaderGroups.length > 0 + || bodyGroups.length > 0); + + if (paintEverything) { + this.paintContent(0, 0, vw, vh); + this._paintOverlay(); + this._syncScrollState(); + return; + } + // Compute the size delta. let delta = newSize - oldSize; @@ -3276,14 +3309,12 @@ class DataGrid extends Widget { dx = sx + delta; } - const [mergeStartOffset, mergeEndOffset] = CellGroup.calculateMergeOffsets(this.dataModel!, ['body','column-header'], 'column', list, index); - // Blit the valid content to the destination. - this._blitContent(this._canvas, sx + mergeEndOffset, sy, sw - mergeEndOffset, sh, dx + mergeEndOffset, dy); + this._blitContent(this._canvas, sx, sy, sw, sh, dx, dy); // Repaint the section if needed. if (newSize > 0 && offset + newSize > hw) { - this.paintContent(pos - mergeStartOffset, 0, offset + newSize - pos + mergeStartOffset + mergeEndOffset, vh); + this.paintContent(pos, 0, offset + newSize - pos, vh); } // Paint the trailing space as needed. @@ -3292,7 +3323,7 @@ class DataGrid extends Widget { let x = hw + this._columnSections.offsetOf(c); this.paintContent(x, 0, vw - x, vh); } else if (delta < 0) { - this.paintContent(0, 0, vw, vh); + this.paintContent(vw + delta, 0, -delta, vh); } // Paint the overlay. @@ -3338,6 +3369,24 @@ class DataGrid extends Widget { return; } + // Render entire grid if scrolling merged cells grid + const colGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'column-header'); + const rowHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'row-header'); + const cornerHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'corner-header'); + const bodyGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'body'); + const paintEverything = ( + colGroups.length > 0 + || rowHeaderGroups.length > 0 + || cornerHeaderGroups.length > 0 + || bodyGroups.length > 0); + + if (paintEverything) { + this.paintContent(0, 0, vw, vh); + this._paintOverlay(); + this._syncScrollState(); + return; + } + // Compute the size delta. let delta = newSize - oldSize; @@ -3366,14 +3415,12 @@ class DataGrid extends Widget { let dx = sx + delta; let dy = 0; - const [mergeStartOffset, mergeEndOffset] = CellGroup.calculateMergeOffsets(this.dataModel!, ['row-header'], 'column', list, index); - // Blit the valid content to the destination. - this._blitContent(this._canvas, sx + mergeEndOffset, sy, sw - mergeEndOffset, sh, dx + mergeEndOffset, dy); + this._blitContent(this._canvas, sx, sy, sw, sh, dx, dy); // Repaint the header section if needed. if (newSize > 0) { - this.paintContent(offset - mergeStartOffset, 0, newSize + mergeStartOffset + mergeEndOffset, vh); + this.paintContent(offset, 0, newSize, vh); } // Paint the trailing space as needed. @@ -3428,6 +3475,24 @@ class DataGrid extends Widget { return; } + // Render entire grid if scrolling merged cells grid + const colGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'column-header'); + const rowHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'row-header'); + const cornerHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'corner-header'); + const bodyGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'body'); + const paintEverything = ( + colGroups.length > 0 + || rowHeaderGroups.length > 0 + || cornerHeaderGroups.length > 0 + || bodyGroups.length > 0); + + if (paintEverything) { + this.paintContent(0, 0, vw, vh); + this._paintOverlay(); + this._syncScrollState(); + return; + } + // Paint the overlay. this._paintOverlay(); @@ -3459,14 +3524,12 @@ class DataGrid extends Widget { let dx = 0; let dy = sy + delta; - const [mergeStartOffset, mergeEndOffset] = CellGroup.calculateMergeOffsets(this.dataModel!, ['column-header'], 'row', list, index); - // Blit the valid contents to the destination. - this._blitContent(this._canvas, sx, sy + mergeEndOffset, sw, sh - mergeEndOffset, dx, dy + mergeEndOffset); + this._blitContent(this._canvas, sx, sy, sw, sh, dx, dy); // Repaint the header section if needed. if (newSize > 0) { - this.paintContent(0, offset - mergeStartOffset, vw, newSize + mergeStartOffset + mergeEndOffset); + this.paintContent(0, offset, vw, newSize); } // Paint the trailing space as needed. @@ -3485,10 +3548,18 @@ class DataGrid extends Widget { this._syncScrollState(); } - /** - * Scroll immediately to the specified offset position. - */ private _scrollTo(x: number, y: number): void { + // Render entire grid if scrolling merged cells grid + const colGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'column-header'); + const rowHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'row-header'); + const cornerHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'corner-header'); + const bodyGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'body'); + const paintEverything = ( + colGroups.length > 0 + || rowHeaderGroups.length > 0 + || cornerHeaderGroups.length > 0 + || bodyGroups.length > 0); + // Floor and clamp the position to the allowable range. x = Math.max(0, Math.min(Math.floor(x), this.maxScrollX)); y = Math.max(0, Math.min(Math.floor(y), this.maxScrollY)); @@ -3568,226 +3639,48 @@ class DataGrid extends Widget { return; } - const scrollYRegions:DataModel.CellRegion[] = ['body','row-header']; - let rowIndex = this._rowSections.indexOf(dy < 0 ? this._scrollY : this._scrollY + contentHeight); - let rowGroupAtAxis: CellGroup[] = []; - let rowAxis: 'row' | 'column' = 'row'; - if (rowAxis === 'row') { - for (const region of scrollYRegions) { - rowGroupAtAxis = rowGroupAtAxis.concat(CellGroup.getCellGroupsAtRow(this.dataModel!, region, rowIndex)); - } - } else { - for (const region of scrollYRegions) { - rowGroupAtAxis = rowGroupAtAxis.concat(CellGroup.getCellGroupsAtColumn(this.dataModel!, region, rowIndex)); - } - } - - const _isCellGroupAbove = (group1: CellGroup, group2: CellGroup): boolean => { - return group2.r2 >= group1.r1; - }; - - const _isCellGroupBelow = (group1: CellGroup, group2: CellGroup): boolean => { - return group2.r1 <= group1.r2; - }; - - let borderY = dy > 0 ? - (this._rowSections.offsetOf(rowIndex) - this._scrollY) : - this._rowSections.offsetOf(rowIndex + 1); - - - if (rowGroupAtAxis.length > 0) { - let mergedGroupAtAxis:CellGroup = CellGroup.joinCellGroups(rowGroupAtAxis); - let mergedCellGroups: CellGroup[] = []; - for (const region of scrollYRegions) { - mergedCellGroups = mergedCellGroups.concat(CellGroup.getCellGroupsAtRegion(this.dataModel!, region)); - } - - for (let g = 0; g < mergedCellGroups.length; g++) { - const group = mergedCellGroups[g]; - - // Scrolling down - if (dy > 0) { - if (!_isCellGroupAbove(mergedGroupAtAxis, group)) { - continue; - } - } else { - if (!_isCellGroupBelow(mergedGroupAtAxis, group)) { - continue; - } - } - - if (CellGroup.areCellGroupsIntersectingAtAxis(mergedGroupAtAxis, group, rowAxis)) { - mergedGroupAtAxis = CellGroup.joinCellGroups([group, mergedGroupAtAxis]); - mergedCellGroups.splice(g, 1); - g = 0; - } - } - if (mergedGroupAtAxis.r1 !== Number.MAX_VALUE) { - if (dy > 0) { - borderY = this._rowSections.offsetOf(mergedGroupAtAxis.r1) - this._scrollY; - } else { - borderY = this._rowSections.offsetOf(mergedGroupAtAxis.r2 + 1); - } - } - } - - const prevScrollY = this._scrollY; - // Update the internal Y scroll position. this._scrollY = y; - let blitSrcX, blitSrcY, blitDstX, blitDstY, blitWidth, blitHeight; - let paintX, paintY, paintWidth, paintHeight; - // Scroll the Y axis if needed. If the scroll distance exceeds // the visible height, paint everything. Otherwise, blit the // valid content and paint the dirty region. - if (dy !== 0 && contentHeight > 0) { - if (Math.abs(dy) >= contentHeight) { - this.paintContent(0, contentY, width, contentHeight); - } else { - // Scrolling down - if (dy > 0) { - - blitSrcX = 0; - blitSrcY = contentY + dy; - blitDstX = 0; - blitDstY = contentY; - blitWidth = width; - blitHeight = borderY - dy; - paintX = 0; - paintY = contentY + borderY - dy; - paintWidth = width; - paintHeight = contentHeight - borderY + dy; - - this._blitContent(this._canvas, blitSrcX, blitSrcY, blitWidth, blitHeight, blitDstX, blitDstY); - this.paintContent(paintX, paintY, paintWidth, paintHeight); - } else { - blitSrcX = 0; - blitSrcY = contentY + borderY - prevScrollY; - blitDstX = 0; - blitDstY = contentY + borderY - prevScrollY - dy; - blitWidth = width; - blitHeight = contentHeight - borderY + prevScrollY; - paintX = 0; - paintY = contentY; - paintWidth = width; - paintHeight = borderY - prevScrollY - dy; - - this._blitContent(this._canvas, blitSrcX, blitSrcY, blitWidth, blitHeight, blitDstX, blitDstY); - this.paintContent(paintX, paintY, paintWidth, paintHeight); - } - } - } - - /** - * Horizontal scrolling logic - */ - const scrollXRegions:DataModel.CellRegion[] = ['body','column-header']; - let columnIndex = this._columnSections.indexOf(dx < 0 ? this._scrollX : this._scrollX + contentWidth); - let columnGroupAtAxis: CellGroup[] = []; - let columnAxis: 'column' | 'row' = 'column'; - if (columnAxis === 'column') { - for (const region of scrollXRegions) { - columnGroupAtAxis = columnGroupAtAxis.concat(CellGroup.getCellGroupsAtColumn(this.dataModel!, region, columnIndex)); - } + if (paintEverything) { + this.paintContent(0, 0, this._viewportWidth, this.viewportWidth); } else { - for (const region of scrollXRegions) { - columnGroupAtAxis = columnGroupAtAxis.concat(CellGroup.getCellGroupsAtColumn(this.dataModel!, region, columnIndex)); - } - } - - const _isCellGroupBefore = (group1: CellGroup, group2: CellGroup): boolean => { - return group2.c2 >= group1.c1; - }; - - const _isCellGroupAfter = (group1: CellGroup, group2: CellGroup): boolean => { - return group2.c1 <= group1.c2; - }; - - let borderX = dx > 0 ? - (this._columnSections.offsetOf(columnIndex) - this._scrollX) : - this._columnSections.offsetOf(columnIndex + 1); - - - if (columnGroupAtAxis.length > 0) { - let mergedGroupAtAxis:CellGroup = CellGroup.joinCellGroups(columnGroupAtAxis); - let mergedCellGroups: CellGroup[] = []; - for (const region of scrollXRegions) { - mergedCellGroups = mergedCellGroups.concat(CellGroup.getCellGroupsAtRegion(this.dataModel!, region)); - } - - for (let g = 0; g < mergedCellGroups.length; g++) { - const group = mergedCellGroups[g]; - - // Scrolling right - if (dx > 0) { - if (!_isCellGroupBefore(mergedGroupAtAxis, group)) { - continue; - } - } else { - if (!_isCellGroupAfter(mergedGroupAtAxis, group)) { - continue; - } - } - - if (CellGroup.areCellGroupsIntersectingAtAxis(mergedGroupAtAxis, group, columnAxis)) { - mergedGroupAtAxis = CellGroup.joinCellGroups([group, mergedGroupAtAxis]); - mergedCellGroups.splice(g, 1); - g = 0; - } - } - if (mergedGroupAtAxis.c1 !== Number.MAX_VALUE) { - if (dx > 0) { - borderX = this._columnSections.offsetOf(mergedGroupAtAxis.c1) - this._scrollX; + if (dy !== 0 && contentHeight > 0) { + if (Math.abs(dy) >= contentHeight) { + this.paintContent(0, contentY, width, contentHeight); } else { - borderX = this._columnSections.offsetOf(mergedGroupAtAxis.c2 + 1); + let x = 0; + let y = dy < 0 ? contentY : contentY + dy; + let w = width; + let h = contentHeight - Math.abs(dy); + this._blitContent(this._canvas, x, y, w, h, x, y - dy); + this.paintContent(0, dy < 0 ? contentY : height - dy, width, Math.abs(dy)); } } } - const prevScrollX = this._scrollX; - // Update the internal X scroll position. this._scrollX = x; // Scroll the X axis if needed. If the scroll distance exceeds // the visible width, paint everything. Otherwise, blit the // valid content and paint the dirty region. - if (dx !== 0 && contentWidth > 0) { - if (Math.abs(dx) >= contentWidth) { - this.paintContent(contentX, 0, contentWidth, height); - } else { - // Scrolling right - if (dx > 0) { - - blitSrcX = contentX + dx;//0; - blitSrcY = 0;//contentY + dy; - blitDstX = contentX;//0; - blitDstY = 0;//contentY; - blitWidth = borderX - dx;//width; - blitHeight = height;//borderY - dy; - paintX = contentX + borderX - dx;//0; - paintY = 0;//contentY + borderY - dy; - paintWidth = contentWidth - borderX + dx;//width; - paintHeight = height;//contentHeight - borderY + dy; - - this._blitContent(this._canvas, blitSrcX, blitSrcY, blitWidth, blitHeight, blitDstX, blitDstY); - this.paintContent(paintX, paintY, paintWidth, paintHeight); + if (paintEverything) { + this.paintContent(0, 0, this._viewportWidth, this._viewportHeight); + } else { + if (dx !== 0 && contentWidth > 0) { + if (Math.abs(dx) >= contentWidth) { + this.paintContent(contentX, 0, contentWidth, height); } else { - blitSrcX = contentX + borderX - prevScrollX;//0; - blitSrcY = 0;//contentY + borderY - prevScrollY; - blitDstX = contentX + borderX - prevScrollX - dx;//0; - blitDstY = 0;//contentY + borderY - prevScrollY - dy; - blitWidth = contentWidth - borderX + prevScrollX;//width; - blitHeight = height;//contentHeight - borderY + prevScrollY; - paintX = contentX;//0; - paintY = 0;//contentY; - paintWidth = borderX - prevScrollX - dx;//width; - paintHeight = height;//borderY - prevScrollY - dy; - - this._blitContent(this._canvas, blitSrcX, blitSrcY, blitWidth, blitHeight, blitDstX, blitDstY); - this.paintContent(paintX, paintY, paintWidth, paintHeight); + let x = dx < 0 ? contentX : contentX + dx; + let y = 0; + let w = contentWidth - Math.abs(dx); + let h = height; + this._blitContent(this._canvas, x, y, w, h, x - dx, y); + this.paintContent(dx < 0 ? contentX : width - dx, 0, Math.abs(dx), height); } } } @@ -3795,7 +3688,6 @@ class DataGrid extends Widget { // Paint the overlay. this._paintOverlay(); } - /** * Blit content into the on-screen grid canvas. * @@ -4789,9 +4681,27 @@ class DataGrid extends Widget { // Draw the line if it's in range of the dirty rect. if (pos >= rgn.yMin && pos <= rgn.yMax) { - for (const line of lines) { - this._canvasGC.moveTo(line[0], pos + 0.5); - this._canvasGC.lineTo(line[1], pos + 0.5); + // Render entire grid if scrolling merged cells grid + const colGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'column-header'); + const rowHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'row-header'); + const cornerHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'corner-header'); + const bodyGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'body'); + const extendLines = ( + colGroups.length > 0 + || rowHeaderGroups.length > 0 + || cornerHeaderGroups.length > 0 + || bodyGroups.length > 0 + ); + + if (extendLines) { + for (const line of lines) { + this._canvasGC.moveTo(line[0], pos + 0.5); + this._canvasGC.lineTo(line[1], pos + 0.5); + } + } else { + let x2 = Math.min(rgn.x + rgn.width, rgn.xMax + 1); + this._canvasGC.moveTo(x1, pos + 0.5); + this._canvasGC.lineTo(x2, pos + 0.5); } } @@ -4883,10 +4793,28 @@ class DataGrid extends Widget { // Draw the line if it's in range of the dirty rect. if (pos >= rgn.xMin && pos <= rgn.xMax) { - for (const line of lines) { - this._canvasGC.strokeStyle = color; - this._canvasGC.moveTo(pos + 0.5, line[0]); - this._canvasGC.lineTo(pos + 0.5, line[1]); + // Render entire grid if scrolling merged cells grid + const colGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'column-header'); + const rowHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'row-header'); + const cornerHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'corner-header'); + const bodyGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'body'); + const extendLines = ( + colGroups.length > 0 + || rowHeaderGroups.length > 0 + || cornerHeaderGroups.length > 0 + || bodyGroups.length > 0 + ); + if (extendLines) { + for (const line of lines) { + // this._canvasGC.strokeStyle = color; + this._canvasGC.moveTo(pos + 0.5, line[0]); + this._canvasGC.lineTo(pos + 0.5, line[1]); + } + } + else { + let y2 = Math.min(rgn.y + rgn.height, rgn.yMax + 1); + this._canvasGC.moveTo(pos + 0.5, y1); + this._canvasGC.lineTo(pos + 0.5, y2); } } From 3caae17288325b1ec9a3d3a7aa9485a9ce0bbace Mon Sep 17 00:00:00 2001 From: Itay Dafna Date: Fri, 16 Jul 2021 10:19:20 -0700 Subject: [PATCH 4/9] Fix typo Signed-off-by: Itay Dafna --- packages/datagrid/src/cellgroup.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/datagrid/src/cellgroup.ts b/packages/datagrid/src/cellgroup.ts index 3e5626416..1ece4decc 100644 --- a/packages/datagrid/src/cellgroup.ts +++ b/packages/datagrid/src/cellgroup.ts @@ -264,7 +264,7 @@ export namespace CellGroup { * same region if they intersect. * @param dataModel the data model of the grid. * @param group the target cell group. - * @param region the region wer're of the cell group. + * @param region the region of the cell group. * @returns a new cell group after merging has happened. */ export function joinCellGroupWithMergedCellGroups( From 706c1b6b7d4ad9379ee2dc04e1e60eb5bbcc59f5 Mon Sep 17 00:00:00 2001 From: Itay Dafna Date: Fri, 16 Jul 2021 10:21:06 -0700 Subject: [PATCH 5/9] Fix rendering issue with blit logic Signed-off-by: Itay Dafna --- packages/datagrid/src/datagrid.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/datagrid/src/datagrid.ts b/packages/datagrid/src/datagrid.ts index a62abbbe7..b62219a28 100644 --- a/packages/datagrid/src/datagrid.ts +++ b/packages/datagrid/src/datagrid.ts @@ -4413,6 +4413,12 @@ class DataGrid extends Widget { return; } + // Determine if the cell intersects with a merged group at row or column + let intersectingColumnGroups = CellGroup.getCellGroupsAtColumn(this._dataModel!, + rgn.region, rgn.column); + let intersectingRowGroups = CellGroup.getCellGroupsAtRow(this._dataModel!, + rgn.region, rgn.row); + // move the bounds of the region if edges of the region are part of a merge group. // after the move, new region contains entirety of the merge groups rgn = JSONExt.deepCopy(rgn); @@ -4580,7 +4586,13 @@ class DataGrid extends Widget { let y1 = Math.max(rgn.yMin, config.y); let y2 = Math.min(config.y + config.height - 1, rgn.yMax); - if (x2 > x1 && y2 > y1) { + if (intersectingColumnGroups.length !== 0 + || intersectingRowGroups.length !== 0) { + if (x2 > x1 && y2 > y1) { + this._blitContent(this._buffer, x1, y1, x2 - x1 + 1, y2 - y1 + 1, x1, y1); + } + } + else { this._blitContent(this._buffer, x1, y1, x2 - x1 + 1, y2 - y1 + 1, x1, y1); } From 23e2811dd1a0bf91b2ee21b196169402b0a24b84 Mon Sep 17 00:00:00 2001 From: Itay Dafna Date: Fri, 16 Jul 2021 10:31:30 -0700 Subject: [PATCH 6/9] Restore _scrollTo() docstring Signed-off-by: Itay Dafna --- packages/datagrid/src/datagrid.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/datagrid/src/datagrid.ts b/packages/datagrid/src/datagrid.ts index b62219a28..52bc56db8 100644 --- a/packages/datagrid/src/datagrid.ts +++ b/packages/datagrid/src/datagrid.ts @@ -3548,6 +3548,9 @@ class DataGrid extends Widget { this._syncScrollState(); } + /** + * Scroll immediately to the specified offset position. + */ private _scrollTo(x: number, y: number): void { // Render entire grid if scrolling merged cells grid const colGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'column-header'); From 55270f5d1c3b2671a48b33583597c2ad83841145 Mon Sep 17 00:00:00 2001 From: Itay Dafna Date: Fri, 16 Jul 2021 12:05:50 -0700 Subject: [PATCH 7/9] Add check for data model in _scrollTo Signed-off-by: Itay Dafna --- packages/datagrid/src/datagrid.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/datagrid/src/datagrid.ts b/packages/datagrid/src/datagrid.ts index 52bc56db8..c8b8d8aa9 100644 --- a/packages/datagrid/src/datagrid.ts +++ b/packages/datagrid/src/datagrid.ts @@ -3552,6 +3552,11 @@ class DataGrid extends Widget { * Scroll immediately to the specified offset position. */ private _scrollTo(x: number, y: number): void { + // Bail if no data model found. + if (!this.dataModel) { + return; + } + // Render entire grid if scrolling merged cells grid const colGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'column-header'); const rowHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'row-header'); From 46a495c92e76372d1664083e8bf1c3e7d466ba13 Mon Sep 17 00:00:00 2001 From: Itay Dafna Date: Fri, 16 Jul 2021 13:42:55 -0700 Subject: [PATCH 8/9] Refactor: 'paintEverything' as a private method Signed-off-by: Itay Dafna --- packages/datagrid/src/datagrid.ts | 71 +++++++++++-------------------- 1 file changed, 25 insertions(+), 46 deletions(-) diff --git a/packages/datagrid/src/datagrid.ts b/packages/datagrid/src/datagrid.ts index c8b8d8aa9..67fbded21 100644 --- a/packages/datagrid/src/datagrid.ts +++ b/packages/datagrid/src/datagrid.ts @@ -3110,15 +3110,7 @@ class DataGrid extends Widget { } // Render entire grid if scrolling merged cells grid - const colGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'column-header'); - const rowHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'row-header'); - const cornerHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'corner-header'); - const bodyGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'body'); - const paintEverything = ( - colGroups.length > 0 - || rowHeaderGroups.length > 0 - || cornerHeaderGroups.length > 0 - || bodyGroups.length > 0); + const paintEverything = Private.shouldPaintEverything(this._dataModel!); if (paintEverything) { this.paintContent(0, 0, vw, vh); @@ -3240,15 +3232,7 @@ class DataGrid extends Widget { } // Render entire grid if scrolling merged cells grid - const colGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'column-header'); - const rowHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'row-header'); - const cornerHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'corner-header'); - const bodyGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'body'); - const paintEverything = ( - colGroups.length > 0 - || rowHeaderGroups.length > 0 - || cornerHeaderGroups.length > 0 - || bodyGroups.length > 0); + const paintEverything = Private.shouldPaintEverything(this._dataModel!); if (paintEverything) { this.paintContent(0, 0, vw, vh); @@ -3370,15 +3354,7 @@ class DataGrid extends Widget { } // Render entire grid if scrolling merged cells grid - const colGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'column-header'); - const rowHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'row-header'); - const cornerHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'corner-header'); - const bodyGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'body'); - const paintEverything = ( - colGroups.length > 0 - || rowHeaderGroups.length > 0 - || cornerHeaderGroups.length > 0 - || bodyGroups.length > 0); + const paintEverything = Private.shouldPaintEverything(this._dataModel!); if (paintEverything) { this.paintContent(0, 0, vw, vh); @@ -3476,15 +3452,7 @@ class DataGrid extends Widget { } // Render entire grid if scrolling merged cells grid - const colGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'column-header'); - const rowHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'row-header'); - const cornerHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'corner-header'); - const bodyGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'body'); - const paintEverything = ( - colGroups.length > 0 - || rowHeaderGroups.length > 0 - || cornerHeaderGroups.length > 0 - || bodyGroups.length > 0); + const paintEverything = Private.shouldPaintEverything(this._dataModel!); if (paintEverything) { this.paintContent(0, 0, vw, vh); @@ -3556,17 +3524,9 @@ class DataGrid extends Widget { if (!this.dataModel) { return; } - + // Render entire grid if scrolling merged cells grid - const colGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'column-header'); - const rowHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'row-header'); - const cornerHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'corner-header'); - const bodyGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'body'); - const paintEverything = ( - colGroups.length > 0 - || rowHeaderGroups.length > 0 - || cornerHeaderGroups.length > 0 - || bodyGroups.length > 0); + const paintEverything = Private.shouldPaintEverything(this._dataModel!); // Floor and clamp the position to the allowable range. x = Math.max(0, Math.min(Math.floor(x), this.maxScrollX)); @@ -6144,6 +6104,25 @@ namespace Private { return canvas; } + /** + * A function to check whether the entire grid should be rendered + * when dealing with merged cell regions. + * @param dataModel grid's data model. + * @returns boolean. + */ + export + function shouldPaintEverything(dataModel: DataModel): boolean { + const colGroups = CellGroup.getCellGroupsAtRegion(dataModel!, 'column-header'); + const rowHeaderGroups = CellGroup.getCellGroupsAtRegion(dataModel!, 'row-header'); + const cornerHeaderGroups = CellGroup.getCellGroupsAtRegion(dataModel!, 'corner-header'); + const bodyGroups = CellGroup.getCellGroupsAtRegion(dataModel!, 'body'); + return ( + colGroups.length > 0 + || rowHeaderGroups.length > 0 + || cornerHeaderGroups.length > 0 + || bodyGroups.length > 0); + } + /** * An object which represents a region to be painted. */ From f99f5da7d235465cb0be2142487ac6c91969706a Mon Sep 17 00:00:00 2001 From: Itay Dafna Date: Fri, 16 Jul 2021 13:56:00 -0700 Subject: [PATCH 9/9] Refactor 'extendLines' to use same check as 'paintEverything' Signed-off-by: Itay Dafna --- packages/datagrid/src/datagrid.ts | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/packages/datagrid/src/datagrid.ts b/packages/datagrid/src/datagrid.ts index 67fbded21..74773b790 100644 --- a/packages/datagrid/src/datagrid.ts +++ b/packages/datagrid/src/datagrid.ts @@ -4662,17 +4662,7 @@ class DataGrid extends Widget { // Draw the line if it's in range of the dirty rect. if (pos >= rgn.yMin && pos <= rgn.yMax) { // Render entire grid if scrolling merged cells grid - const colGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'column-header'); - const rowHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'row-header'); - const cornerHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'corner-header'); - const bodyGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'body'); - const extendLines = ( - colGroups.length > 0 - || rowHeaderGroups.length > 0 - || cornerHeaderGroups.length > 0 - || bodyGroups.length > 0 - ); - + const extendLines = Private.shouldPaintEverything(this._dataModel!); if (extendLines) { for (const line of lines) { this._canvasGC.moveTo(line[0], pos + 0.5); @@ -4774,16 +4764,7 @@ class DataGrid extends Widget { // Draw the line if it's in range of the dirty rect. if (pos >= rgn.xMin && pos <= rgn.xMax) { // Render entire grid if scrolling merged cells grid - const colGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'column-header'); - const rowHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'row-header'); - const cornerHeaderGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'corner-header'); - const bodyGroups = CellGroup.getCellGroupsAtRegion(this.dataModel!, 'body'); - const extendLines = ( - colGroups.length > 0 - || rowHeaderGroups.length > 0 - || cornerHeaderGroups.length > 0 - || bodyGroups.length > 0 - ); + const extendLines = Private.shouldPaintEverything(this._dataModel!); if (extendLines) { for (const line of lines) { // this._canvasGC.strokeStyle = color;