canvas-datagrid 0.3.25 → 0.4.3

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/lib/draw.js CHANGED
@@ -108,6 +108,98 @@ export default function (self) {
108
108
  '</svg>\n',
109
109
  );
110
110
  }
111
+ /**
112
+ * @param {number[]} coords [x0,y0, x1,y1, x2,y2, ...]
113
+ * @param {boolean} [fill] fill the area that construct by these lines but not stroke
114
+ */
115
+ function drawLines(coords, fill) {
116
+ if (coords.length < 4) return;
117
+ self.ctx.beginPath();
118
+ self.ctx.moveTo(
119
+ coords[0] + self.canvasOffsetLeft,
120
+ coords[1] + self.canvasOffsetTop,
121
+ );
122
+ for (let i = 2; i < coords.length; i += 2) {
123
+ const x = coords[i] + self.canvasOffsetLeft;
124
+ const y = coords[i + 1] + self.canvasOffsetTop;
125
+ self.ctx.lineTo(x, y);
126
+ }
127
+ if (fill) self.ctx.fill();
128
+ else self.ctx.stroke();
129
+ }
130
+ /**
131
+ * @param {number} x based-X (left-top)
132
+ * @param {number} y based-Y (left-top)
133
+ * @param {number} width
134
+ * @param {boolean} collapsed true: '+'; false: '-'
135
+ */
136
+ function drawGroupHandle(x, y, width, collapsed) {
137
+ fillRect(x, y, width, width);
138
+ strokeRect(x, y, width, width);
139
+ const cx = x + width * 0.5;
140
+ const cy = y + width * 0.5;
141
+ drawLines([x + width * 0.2, cy, x + width * 0.78, cy]);
142
+ if (collapsed) drawLines([cx, y + width * 0.22, cx, y + width * 0.8]);
143
+ }
144
+ /**
145
+ * @param {number} x
146
+ * @param {number} y
147
+ * @param {number} size
148
+ * @param {string} dir Direction of the triangle, one of the 't','b','l' and 'r'
149
+ * @param {boolean} [active]
150
+ */
151
+ function drawUnhideIndicator(x, y, size, dir, active) {
152
+ const minPadding = size * 0.2;
153
+ const maxPadding = size * 0.3;
154
+ /** The long edge width of the triangle */
155
+ const longEdge = size - 2 * minPadding;
156
+ /** The median width of the triangle */
157
+ const median = size - 2 * maxPadding;
158
+ const halfLongEdge = longEdge * 0.5;
159
+ let x0, y0;
160
+ let coords, borderCoords;
161
+ switch (dir) {
162
+ case 'r':
163
+ x0 = x + maxPadding;
164
+ y0 = y + minPadding;
165
+ borderCoords = [x, y, x + size, y, x + size, y + size, x, y + size];
166
+ coords = [x0, y0, x0, y0 + longEdge, x0 + median, y0 + halfLongEdge];
167
+ break;
168
+ case 'l':
169
+ x0 = x + size - maxPadding;
170
+ y0 = y + minPadding;
171
+ borderCoords = [x + size, y, x, y, x, y + size, x + size, y + size];
172
+ coords = [x0, y0, x0, y0 + longEdge, x0 - median, y0 + halfLongEdge];
173
+ break;
174
+ case 't':
175
+ x0 = x + minPadding;
176
+ y0 = y + size - maxPadding;
177
+ borderCoords = [x, y + size, x, y, x + size, y, x + size, y + size];
178
+ coords = [x0, y0, x0 + longEdge, y0, x0 + halfLongEdge, y0 - median];
179
+ break;
180
+ case 'b':
181
+ x0 = x + minPadding;
182
+ y0 = y + maxPadding;
183
+ borderCoords = [x, y, x, y + size, x + size, y + size, x + size, y];
184
+ coords = [x0, y0, x0 + longEdge, y0, x0 + halfLongEdge, y0 + median];
185
+ break;
186
+ }
187
+
188
+ if (active) {
189
+ self.ctx.strokeStyle = self.style.unhideIndicatorBorderColor;
190
+ self.ctx.lineWidth = 2;
191
+ drawLines(borderCoords);
192
+
193
+ self.ctx.fillStyle = self.style.unhideIndicatorBackgroundColor;
194
+ let offset = dir === 'r' || dir === 'b' ? 1 : 0;
195
+ if (dir === 'l' || dir === 'r')
196
+ fillRect(x - offset, y, size + offset, size);
197
+ else fillRect(x, y - offset, size, size + offset);
198
+ }
199
+
200
+ self.ctx.fillStyle = self.style.unhideIndicatorColor;
201
+ drawLines(coords, true);
202
+ }
111
203
  function drawOrderByArrow(x, y) {
112
204
  var mt = self.style.columnHeaderOrderByArrowMarginTop * self.scale,
113
205
  ml = self.style.columnHeaderOrderByArrowMarginLeft * self.scale,
@@ -164,6 +256,54 @@ export default function (self) {
164
256
  self.ctx.fill();
165
257
  return ml + aw + mr;
166
258
  }
259
+ function drawCellTreeIcon(cell, tree, rowTree) {
260
+ const parentCount = rowTree ? tree.parentCount : 0;
261
+ const iconSize = self.style.cellTreeIconWidth * self.scale,
262
+ marginTop = self.style.cellTreeIconMarginTop * self.scale,
263
+ marginRight = self.style.cellTreeIconMarginRight * self.scale,
264
+ marginLeft =
265
+ self.style.cellTreeIconMarginLeft * self.scale +
266
+ parentCount * (iconSize + cell.paddingLeft);
267
+
268
+ let x = cell.x + cell.paddingLeft + self.canvasOffsetLeft + marginLeft,
269
+ y = cell.y + self.canvasOffsetTop + marginTop;
270
+
271
+ if (tree.icon) {
272
+ self.ctx.beginPath();
273
+ const oldFillStyle = self.ctx.fillStyle;
274
+ const oldStrokeStyle = self.ctx.strokeStyle;
275
+
276
+ if (cell.hovered && self.hovers.onCellTreeIcon) {
277
+ self.ctx.fillStyle = self.style.cellTreeIconHoverFillColor;
278
+ } else {
279
+ self.ctx.fillStyle = self.style.cellTreeIconFillColor;
280
+ }
281
+
282
+ self.ctx.fillRect(x, y, iconSize, iconSize);
283
+ self.ctx.strokeStyle = self.style.cellTreeIconBorderColor;
284
+ self.ctx.rect(x, y, iconSize, iconSize);
285
+ self.ctx.stroke();
286
+
287
+ self.ctx.beginPath();
288
+ if (tree.expand) {
289
+ self.ctx.moveTo(x + 3, y + iconSize * 0.5);
290
+ self.ctx.lineTo(x + iconSize - 3, y + iconSize * 0.5);
291
+ } else {
292
+ self.ctx.moveTo(x + 2, y + iconSize * 0.5);
293
+ self.ctx.lineTo(x + iconSize - 2, y + iconSize * 0.5);
294
+ self.ctx.moveTo(x + iconSize * 0.5, y + 2);
295
+ self.ctx.lineTo(x + iconSize * 0.5, y + iconSize - 2);
296
+ }
297
+ self.ctx.lineWidth = self.style.cellTreeIconLineWidth;
298
+ self.ctx.strokeStyle = self.style.cellTreeIconLineColor;
299
+ self.ctx.stroke();
300
+
301
+ self.ctx.strokeStyle = oldStrokeStyle;
302
+ self.ctx.fillStyle = oldFillStyle;
303
+ }
304
+
305
+ return marginLeft + iconSize + marginRight;
306
+ }
167
307
  function drawFilterButtonArrow(x, y) {
168
308
  var mt =
169
309
  ((self.style.filterButtonHeight - self.style.filterButtonArrowHeight) /
@@ -460,7 +600,7 @@ export default function (self) {
460
600
  height: cell.calculatedLineHeight * lines.length,
461
601
  };
462
602
  }
463
- function drawText(cell) {
603
+ function drawText(cell, treeCellPadding = 0) {
464
604
  var ll = cell.text.lines.length,
465
605
  h = cell.fontHeight * cell.lineHeight,
466
606
  x,
@@ -476,12 +616,18 @@ export default function (self) {
476
616
  0.5,
477
617
  0,
478
618
  ) + h,
479
- hPos = cell.paddingLeft + cell.treeArrowWidth + cell.orderByArrowWidth;
619
+ hPos =
620
+ cell.paddingLeft +
621
+ treeCellPadding +
622
+ cell.treeArrowWidth +
623
+ cell.orderByArrowWidth;
480
624
  if (cell.horizontalAlignment === 'right') {
481
- hPos = cell.paddingLeft + cell.paddedWidth - line.width;
625
+ hPos =
626
+ cell.paddingLeft + treeCellPadding + cell.paddedWidth - line.width;
482
627
  } else if (cell.horizontalAlignment === 'center') {
483
628
  hPos =
484
629
  cell.paddingLeft +
630
+ treeCellPadding +
485
631
  (cell.paddedWidth + cell.paddingRight) / 2 -
486
632
  line.width / 2;
487
633
  }
@@ -538,6 +684,7 @@ export default function (self) {
538
684
  s = self.getSchema(),
539
685
  x = 0,
540
686
  n = Math.min(self.frozenColumn, s.length),
687
+ collapsedGroups = self.getCollapsedColumnGroups(),
541
688
  column;
542
689
  hiddenFrozenColumnCount = 0;
543
690
  while (x < n) {
@@ -545,7 +692,15 @@ export default function (self) {
545
692
  if (column.hidden) {
546
693
  hiddenFrozenColumnCount += 1;
547
694
  } else {
548
- w += self.getColumnWidth(x);
695
+ const isCollapsed =
696
+ collapsedGroups.findIndex(
697
+ (group) => x >= group.from && x <= group.to,
698
+ ) >= 0;
699
+ if (isCollapsed) {
700
+ hiddenFrozenColumnCount += 1;
701
+ } else {
702
+ w += self.getColumnWidth(x);
703
+ }
549
704
  }
550
705
  x += 1;
551
706
  }
@@ -615,7 +770,25 @@ export default function (self) {
615
770
  u = self.currentCell || {},
616
771
  columnHeaderCellHeight = self.getColumnHeaderCellHeight(),
617
772
  rowHeaderCellWidth = self.getRowHeaderCellWidth(),
618
- cellHeight = self.style.cellHeight;
773
+ rowGroupsAreaWidth = self.getRowGroupAreaWidth(),
774
+ columnGroupsAreaHeight = self.getColumnGroupAreaHeight(),
775
+ /** key: boundRowIndex, value: `{y,h}` */
776
+ rowGroupsRectInfo = {},
777
+ /** value: `{y,h}` */
778
+ rowGroupsFrozenInfo = {},
779
+ /** key: columnIndex, value: `{x,w}` */
780
+ columnGroupsRectInfo = {},
781
+ collapsedColumnGroups = self.getCollapsedColumnGroups(),
782
+ collapsedRowGroups = self.getCollapsedRowGroups(),
783
+ cellHeight = self.style.cellHeight,
784
+ currentRowIndexOffset = 0,
785
+ /** @type {Array<{from:number,plus:number}>} */
786
+ rowIndexOffsetByHiddenRows = self.hiddenRowRanges
787
+ .map((range) => ({
788
+ from: range[0],
789
+ plus: range[1] - range[0] + 1,
790
+ }))
791
+ .sort((a, b) => a.from - b.from);
619
792
  drawCount += 1;
620
793
  p = performance.now();
621
794
  self.visibleRowHeights = [];
@@ -623,6 +796,31 @@ export default function (self) {
623
796
  if (viewData.length > self.orders.rows.length) {
624
797
  self.createRowOrders();
625
798
  }
799
+ function saveRowGroupsRectInfo(cell) {
800
+ let index = cell.boundRowIndex;
801
+ if (index >= -1 === false)
802
+ if (cell.rowIndex === -1) index = -1;
803
+ else return;
804
+ if (rowGroupsRectInfo[index]) return;
805
+ rowGroupsRectInfo[index] = { y: cell.y, h: cell.height };
806
+ }
807
+ function saveColumnGroupsRectInfo(cell) {
808
+ const index = cell.columnIndex;
809
+ if (columnGroupsRectInfo[index]) return;
810
+ columnGroupsRectInfo[index] = { x: cell.x, w: cell.width };
811
+ }
812
+ /**
813
+ * @param {number} columnIndex
814
+ * @returns {boolean}
815
+ */
816
+ function isColumnCollapsedByGroup(columnIndex) {
817
+ return (
818
+ collapsedColumnGroups.findIndex(
819
+ (group) => columnIndex >= group.from && columnIndex <= group.to,
820
+ ) >= 0
821
+ );
822
+ }
823
+
626
824
  function drawScrollBars() {
627
825
  var drawCorner,
628
826
  en = self.scrollBox.entities,
@@ -976,6 +1174,15 @@ export default function (self) {
976
1174
  activeHeader: activeHeader,
977
1175
  value:
978
1176
  isHeader && !isRowHeader ? header.title || header.name : rawValue,
1177
+ isRowTree:
1178
+ rowOrderIndex >= 0 &&
1179
+ columnOrderIndex == self.cellTree.rowTreeColIndex &&
1180
+ self.cellTree.rows.length > 0 &&
1181
+ self.cellTree.rows[rowOrderIndex].icon,
1182
+ isColumnTree:
1183
+ columnOrderIndex >= 0 &&
1184
+ self.cellTree.columns[rowOrderIndex] &&
1185
+ self.cellTree.columns[rowOrderIndex][columnOrderIndex].icon,
979
1186
  };
980
1187
  cell.calculatedLineHeight =
981
1188
  cell.fontHeight * cell.lineHeight + cell.lineSpacing;
@@ -987,6 +1194,8 @@ export default function (self) {
987
1194
  ? self.sizes.columns.cornerCell
988
1195
  : self.sizes.columns[headerIndex];
989
1196
  self.visibleCells.unshift(cell);
1197
+ saveRowGroupsRectInfo(cell);
1198
+ saveColumnGroupsRectInfo(cell);
990
1199
  if (self.dispatchEvent('beforerendercell', ev)) {
991
1200
  return;
992
1201
  }
@@ -1129,7 +1338,53 @@ export default function (self) {
1129
1338
  if (cell.innerHTML || header.type === 'html') {
1130
1339
  drawHtml(cell);
1131
1340
  } else {
1132
- drawText(cell);
1341
+ let treeCellPadding = 0,
1342
+ isDrawText = true;
1343
+ if (
1344
+ cell.columnIndex == self.cellTree.rowTreeColIndex &&
1345
+ !cell.isColumnHeader &&
1346
+ self.cellTree.rows.length > 0 &&
1347
+ Object.keys(self.cellTree.rows[cell.rowIndex]).length > 1
1348
+ )
1349
+ treeCellPadding = drawCellTreeIcon(
1350
+ cell,
1351
+ self.cellTree.rows[cell.rowIndex],
1352
+ true,
1353
+ );
1354
+
1355
+ if (
1356
+ !cell.isRowHeader &&
1357
+ cell.rowIndex > 0 &&
1358
+ self.cellTree.columns[cell.rowIndex - 1] &&
1359
+ self.cellTree.columns[cell.rowIndex - 1][cell.columnIndex]
1360
+ .icon
1361
+ ) {
1362
+ for (let r = cell.rowIndex - 1; r >= 0; r--) {
1363
+ if (!self.cellTree.columns[r]) break;
1364
+ if (!self.cellTree.columns[r][cell.columnIndex].icon) break;
1365
+ if (!self.cellTree.columns[r][cell.columnIndex].expand) {
1366
+ isDrawText = false;
1367
+ break;
1368
+ }
1369
+ }
1370
+ }
1371
+ if (
1372
+ isDrawText &&
1373
+ !cell.isRowHeader &&
1374
+ self.cellTree.columns[cell.rowIndex] &&
1375
+ self.cellTree.columns[cell.rowIndex][cell.columnIndex].icon
1376
+ ) {
1377
+ if (
1378
+ self.viewData.length > 0 &&
1379
+ self.viewData[cell.rowIndex][cell.columnIndex].length > 0
1380
+ )
1381
+ treeCellPadding = drawCellTreeIcon(
1382
+ cell,
1383
+ self.cellTree.columns[cell.rowIndex][cell.columnIndex],
1384
+ false,
1385
+ );
1386
+ }
1387
+ if (isDrawText) drawText(cell, treeCellPadding);
1133
1388
  }
1134
1389
 
1135
1390
  if (wrap && cell.text && cell.text.height > rowHeight) {
@@ -1171,10 +1426,31 @@ export default function (self) {
1171
1426
  const previousRowNumber = self.getBoundRowIndexFromViewRowIndex(
1172
1427
  rowOrderIndex - 1,
1173
1428
  );
1174
- const hasRowGap =
1429
+ let hasRowGap =
1175
1430
  previousRowNumber !== undefined &&
1176
1431
  cell.boundRowIndex > 0 &&
1177
1432
  cell.boundRowIndex - previousRowNumber > 1;
1433
+ if (hasRowGap && collapsedRowGroups.length > 0) {
1434
+ hasRowGap =
1435
+ collapsedRowGroups.find(
1436
+ (group) =>
1437
+ group.from === previousRowNumber &&
1438
+ group.to === cell.boundRowIndex,
1439
+ ) >= 0;
1440
+ }
1441
+ // We don't treat the row index difference from hidden rows as the row gap.
1442
+ if (hasRowGap && self.hiddenRowRanges.length > 0) {
1443
+ for (let i = 0; i < self.hiddenRowRanges.length; i++) {
1444
+ const [beginRowIndex, endRowIndex] = self.hiddenRowRanges[i];
1445
+ if (
1446
+ cell.boundRowIndex === endRowIndex + 1 &&
1447
+ previousRowNumber === beginRowIndex - 1
1448
+ ) {
1449
+ hasRowGap = false;
1450
+ break;
1451
+ }
1452
+ }
1453
+ }
1178
1454
 
1179
1455
  if (hasRowGap) {
1180
1456
  const barHeight = self.style.rowHeaderCellRowNumberGapHeight;
@@ -1190,9 +1466,141 @@ export default function (self) {
1190
1466
  }
1191
1467
  }
1192
1468
 
1469
+ //#region draw unhide indicator for column headers
1470
+ if (isColumnHeader && self.attributes.showUnhideColumnsIndicator) {
1471
+ const hovered = self.hovers.unhideIndicator;
1472
+ const size = self.style.unhideIndicatorSize;
1473
+ const cellX = x;
1474
+ const topY = cell.y + Math.max(0.5 * (cell.height - size), 0);
1475
+
1476
+ const isActive = (orderIndex) =>
1477
+ hovered &&
1478
+ (hovered.dir === 'l' || hovered.dir === 'r') &&
1479
+ orderIndex >= hovered.orderIndex0 &&
1480
+ orderIndex <= hovered.orderIndex1;
1481
+ const isHiddenColumn = (columnIndex) =>
1482
+ columnIndex >= 0 &&
1483
+ schema[columnIndex] &&
1484
+ schema[columnIndex].hidden;
1485
+
1486
+ let orderIndex0, orderIndex1;
1487
+ const drawIndicator = (leftX, dir, active) => {
1488
+ self.visibleUnhideIndicators.push({
1489
+ x: leftX - 1,
1490
+ y: topY - 1,
1491
+ x2: leftX + size + 2,
1492
+ y2: topY + size + 2,
1493
+ orderIndex0,
1494
+ orderIndex1,
1495
+ dir,
1496
+ });
1497
+ if (!active) {
1498
+ const line = cell.text && cell.text.lines && cell.text.lines[0];
1499
+ if (line) {
1500
+ const iconsWidth = orderByArrowSize + treeArrowSize;
1501
+ const lineX0 = iconsWidth > 0 ? iconsWidth : line.x;
1502
+ const lineX1 = line.x + line.width;
1503
+ if (leftX + size >= lineX0 && leftX <= lineX1) return;
1504
+ }
1505
+ }
1506
+ drawUnhideIndicator(leftX, topY, size, dir, active);
1507
+ }; // end of drawIndicator
1508
+
1509
+ let orderIndexPtr = columnOrderIndex - 1;
1510
+ const prevColumnIndex = self.orders.columns[orderIndexPtr];
1511
+ if (isHiddenColumn(prevColumnIndex)) {
1512
+ const active = isActive(prevColumnIndex);
1513
+ orderIndex0 = orderIndexPtr;
1514
+ orderIndex1 = orderIndexPtr;
1515
+ while (--orderIndexPtr >= 0) {
1516
+ if (isHiddenColumn(self.orders.columns[orderIndexPtr]))
1517
+ orderIndex0 = orderIndexPtr;
1518
+ else break;
1519
+ }
1520
+ drawIndicator(cellX, 'r', active);
1521
+ }
1522
+
1523
+ orderIndexPtr = columnOrderIndex + 1;
1524
+ const nextColumnIndex = self.orders.columns[orderIndexPtr];
1525
+ if (isHiddenColumn(nextColumnIndex)) {
1526
+ const active = isActive(nextColumnIndex);
1527
+ orderIndex0 = orderIndexPtr;
1528
+ orderIndex1 = orderIndexPtr;
1529
+ while (++orderIndexPtr < self.orders.columns.length) {
1530
+ if (isHiddenColumn(self.orders.columns[orderIndexPtr]))
1531
+ orderIndex1 = orderIndexPtr;
1532
+ else break;
1533
+ }
1534
+ const indicatorX = x + cell.width - size;
1535
+ drawIndicator(indicatorX, 'l', active);
1536
+ }
1537
+ }
1538
+ //#endregion draw unhide indicator for column headers
1539
+
1540
+ //#region draw unhide indicator for row headers
1541
+ if (
1542
+ isRowHeader &&
1543
+ self.attributes.showUnhideRowsIndicator &&
1544
+ self.hiddenRowRanges.length > 0
1545
+ ) {
1546
+ // Leo's comment:
1547
+ // from the first row to the last row, `rowIndex` is from 0 to the count of rows
1548
+ // but `boundRowIndex` can be disordered if there are any ordered columns or filtered columns
1549
+ // Like this statement:
1550
+ // console.log(rowIndex, cell.boundRowIndex, cell.formattedValue);
1551
+ // can output the result like this:
1552
+ // 0 1 '2'
1553
+ // 1 3 '4'
1554
+ const hovered = self.hovers.unhideIndicator;
1555
+ const size = self.style.unhideIndicatorSize;
1556
+ const leftX = cell.x + cell.width - size - 2;
1557
+ const cellY = y;
1558
+ const topIndicators = {};
1559
+ const bottomIndicators = {};
1560
+ self.hiddenRowRanges.forEach((it) => {
1561
+ topIndicators[it[0] - 1] = it;
1562
+ bottomIndicators[it[1] + 1] = it;
1563
+ });
1564
+
1565
+ const rowIndex = cell.rowIndex + currentRowIndexOffset;
1566
+ const isActive = () =>
1567
+ hovered &&
1568
+ (hovered.dir === 't' || hovered.dir === 'b') &&
1569
+ rowIndex >= hovered.orderIndex0 - 1 &&
1570
+ rowIndex <= hovered.orderIndex1 + 1;
1571
+
1572
+ let orderIndex0, orderIndex1;
1573
+ const drawIndicator = (topY, dir, active) => {
1574
+ self.visibleUnhideIndicators.push({
1575
+ x: leftX - 1,
1576
+ y: topY - 1,
1577
+ x2: leftX + size + 2,
1578
+ y2: topY + size + 2,
1579
+ orderIndex0,
1580
+ orderIndex1,
1581
+ dir,
1582
+ });
1583
+ drawUnhideIndicator(leftX, topY, size, dir, active);
1584
+ }; // end of drawIndicator
1585
+
1586
+ let matched = topIndicators[rowIndex];
1587
+ if (matched) {
1588
+ const indicatorY = cellY + cell.height - size;
1589
+ [orderIndex0, orderIndex1] = matched;
1590
+ drawIndicator(indicatorY, 't', isActive());
1591
+ }
1592
+ matched = bottomIndicators[rowIndex];
1593
+ if (matched) {
1594
+ const indicatorY = cellY;
1595
+ [orderIndex0, orderIndex1] = matched;
1596
+ drawIndicator(indicatorY, 'b', isActive());
1597
+ }
1598
+ }
1599
+ //#endregion draw unhide indicator for row headers
1600
+
1193
1601
  x += cell.width + (bc ? 0 : self.style.cellBorderWidth);
1194
1602
  return cell.width;
1195
- };
1603
+ }; // end of drawEach
1196
1604
  }
1197
1605
  function drawFilterButton(cell, ev) {
1198
1606
  var posX = cell.x + cell.width - self.style.filterButtonWidth - 1;
@@ -1230,16 +1638,20 @@ export default function (self) {
1230
1638
  // as it is in the unfiltered data, instead of simply the viewed
1231
1639
  // row index + 1. If rowIndex > viewData.length, it's a new row
1232
1640
  // added to the end, and we want to render that new row's number
1233
- const filteredRowNumber =
1234
- self.viewData && rowIndex < self.viewData.length
1235
- ? self.getBoundRowIndexFromViewRowIndex(rowIndex) + 1
1236
- : self.originalData
1641
+ let filteredRowNumber;
1642
+ if (self.viewData && rowIndex < self.viewData.length)
1643
+ filteredRowNumber =
1644
+ self.getBoundRowIndexFromViewRowIndex(rowIndex) + 1;
1645
+ else
1646
+ filteredRowNumber = self.originalData
1237
1647
  ? self.originalData.length + 1
1238
1648
  : rowOrderIndex + 1;
1239
1649
 
1240
- const rowHeaderValue = self.hasActiveFilters()
1241
- ? filteredRowNumber
1242
- : rowIndex + 1;
1650
+ let rowHeaderValue =
1651
+ self.hasActiveFilters() || self.hasCollapsedRowGroup()
1652
+ ? filteredRowNumber
1653
+ : rowIndex + 1;
1654
+ rowHeaderValue += currentRowIndexOffset;
1243
1655
 
1244
1656
  const rowHeaderCell = { rowHeaderCell: rowHeaderValue };
1245
1657
  const headerDescription = {
@@ -1256,6 +1668,14 @@ export default function (self) {
1256
1668
  -1,
1257
1669
  -1,
1258
1670
  );
1671
+
1672
+ if (
1673
+ rowIndexOffsetByHiddenRows[0] &&
1674
+ rowHeaderValue >= rowIndexOffsetByHiddenRows[0].from
1675
+ ) {
1676
+ const { plus } = rowIndexOffsetByHiddenRows.shift();
1677
+ currentRowIndexOffset += plus;
1678
+ }
1259
1679
  }
1260
1680
  }
1261
1681
  function drawHeaders() {
@@ -1271,7 +1691,7 @@ export default function (self) {
1271
1691
  for (o = start; o < end; o += 1) {
1272
1692
  i = self.orders.columns[o];
1273
1693
  header = schema[i];
1274
- if (!header.hidden) {
1694
+ if (!header.hidden && !isColumnCollapsedByGroup(o)) {
1275
1695
  d = {
1276
1696
  title: header.title,
1277
1697
  name: header.name,
@@ -1383,12 +1803,14 @@ export default function (self) {
1383
1803
  columnOrderIndex < g;
1384
1804
  columnOrderIndex += 1
1385
1805
  ) {
1386
- headerIndex = self.orders.columns[columnOrderIndex];
1387
- x += drawCell(rowData, rowOrderIndex, rowIndex)(
1388
- schema[headerIndex],
1389
- headerIndex,
1390
- columnOrderIndex,
1391
- );
1806
+ if (!isColumnCollapsedByGroup(columnOrderIndex)) {
1807
+ headerIndex = self.orders.columns[columnOrderIndex];
1808
+ x += drawCell(rowData, rowOrderIndex, rowIndex)(
1809
+ schema[headerIndex],
1810
+ headerIndex,
1811
+ columnOrderIndex,
1812
+ );
1813
+ }
1392
1814
  if (x > self.width) {
1393
1815
  self.scrollIndexRight = columnOrderIndex;
1394
1816
  self.scrollPixelRight = x;
@@ -1405,12 +1827,14 @@ export default function (self) {
1405
1827
  columnOrderIndex < self.frozenColumn;
1406
1828
  columnOrderIndex += 1
1407
1829
  ) {
1408
- headerIndex = self.orders.columns[columnOrderIndex];
1409
- x += drawCell(rowData, rowOrderIndex, rowIndex)(
1410
- schema[headerIndex],
1411
- headerIndex,
1412
- columnOrderIndex,
1413
- );
1830
+ if (!isColumnCollapsedByGroup(columnOrderIndex)) {
1831
+ headerIndex = self.orders.columns[columnOrderIndex];
1832
+ x += drawCell(rowData, rowOrderIndex, rowIndex)(
1833
+ schema[headerIndex],
1834
+ headerIndex,
1835
+ columnOrderIndex,
1836
+ );
1837
+ }
1414
1838
  if (x > self.width) {
1415
1839
  break;
1416
1840
  }
@@ -1439,7 +1863,18 @@ export default function (self) {
1439
1863
  scrollTop: self.scrollBox.scrollTop,
1440
1864
  scrollLeft: self.scrollBox.scrollLeft,
1441
1865
  rowIndex: rowOrderIndex,
1866
+ columnGroupsAreaHeight: columnGroupsAreaHeight,
1867
+ rowGroupsAreaWidth: rowGroupsAreaWidth,
1442
1868
  };
1869
+ if (self.intf.parentNode) {
1870
+ const {
1871
+ columnGroupsAreaHeight,
1872
+ rowGroupsAreaWidth,
1873
+ } = self.intf.parentNode;
1874
+ treeGrid.parentNode.columnGroupsAreaHeight +=
1875
+ columnGroupsAreaHeight || 0;
1876
+ treeGrid.parentNode.rowGroupsAreaWidth += rowGroupsAreaWidth || 0;
1877
+ }
1443
1878
  self.visibleCells.unshift({
1444
1879
  rowIndex: rowOrderIndex,
1445
1880
  columnIndex: 0,
@@ -1464,12 +1899,21 @@ export default function (self) {
1464
1899
  self.visibleRows = [];
1465
1900
  schema = self.getSchema();
1466
1901
  self.visibleCells = [];
1902
+ self.visibleGroups = [];
1903
+ self.visibleUnhideIndicators = [];
1467
1904
  self.canvasOffsetTop = self.isChildGrid ? self.parentNode.offsetTop : 0.5;
1468
1905
  self.canvasOffsetLeft = self.isChildGrid
1469
1906
  ? self.parentNode.offsetLeft
1470
1907
  : -0.5;
1471
1908
  h = self.height;
1472
1909
  w = self.width;
1910
+
1911
+ // patch for first row being hidden
1912
+ const firstRowIndexOffset = rowIndexOffsetByHiddenRows[0];
1913
+ if (firstRowIndexOffset && firstRowIndexOffset.from === 0) {
1914
+ currentRowIndexOffset = firstRowIndexOffset.plus;
1915
+ rowIndexOffsetByHiddenRows.shift();
1916
+ }
1473
1917
  }
1474
1918
  function drawBackground() {
1475
1919
  radiusRect(0, 0, w, h, 0);
@@ -1477,6 +1921,379 @@ export default function (self) {
1477
1921
  self.ctx.fillStyle = self.style.gridBackgroundColor;
1478
1922
  fillRect(0, 0, w, h);
1479
1923
  }
1924
+ function initGroupArea() {
1925
+ self.ctx.translate(rowGroupsAreaWidth, columnGroupsAreaHeight);
1926
+ }
1927
+ function drawGroupArea() {
1928
+ const mx = rowGroupsAreaWidth;
1929
+ const my = columnGroupsAreaHeight;
1930
+ const frozenColumnsWidth = getFrozenColumnsWidth();
1931
+ const frozenRowsHeight =
1932
+ rowGroupsFrozenInfo.y + rowGroupsFrozenInfo.h - columnHeaderCellHeight;
1933
+ const onTheLeft = self.attributes.columnGroupIndicatorPosition === 'left';
1934
+ const onTheTop = self.attributes.rowGroupIndicatorPosition === 'top';
1935
+
1936
+ /** @type {CanvasRenderingContext2D} */
1937
+ const ctx = self.ctx;
1938
+ ctx.save();
1939
+ ctx.fillStyle = self.style.groupingAreaBackgroundColor;
1940
+ fillRect(0, -my, w, my);
1941
+ fillRect(-mx, -my, mx, h);
1942
+ ctx.restore();
1943
+
1944
+ //#region Columns Grouping
1945
+ /** it extends `self.groupedRows` */
1946
+ const groupedColumns = [];
1947
+ for (let row = 0; row < self.groupedColumns.length; row++) {
1948
+ const groups = self.groupedColumns[row];
1949
+ for (let j = 0; j < groups.length; j++) {
1950
+ groupedColumns.push(Object.assign({ row }, groups[j]));
1951
+ }
1952
+ }
1953
+ if (groupedColumns.length > 0) {
1954
+ const rowHeight = self.style.columnGroupRowHeight;
1955
+ const toggleHandleSize = rowHeight * 0.5;
1956
+ const toggleHandlePadding = (rowHeight - toggleHandleSize) * 0.5;
1957
+
1958
+ for (let i = 0; i < groupedColumns.length; i++) {
1959
+ const group = groupedColumns[i];
1960
+ const { row, collapsed } = group;
1961
+
1962
+ const topY = -my + row * rowHeight;
1963
+ const centerY = topY + rowHeight * 0.5;
1964
+ const bottomY = topY + rowHeight - toggleHandlePadding;
1965
+ const leftmostX =
1966
+ rowHeaderCellWidth - toggleHandleSize - toggleHandlePadding;
1967
+
1968
+ const drawGroupHandleAtX = (x) =>
1969
+ drawGroupHandle(
1970
+ x,
1971
+ topY + toggleHandlePadding,
1972
+ toggleHandleSize,
1973
+ group.collapsed,
1974
+ );
1975
+ const pushToVisibleGroups = (leftX, rightX) =>
1976
+ self.visibleGroups.push({
1977
+ type: 'c',
1978
+ collapsed,
1979
+ from: group.from,
1980
+ to: group.to,
1981
+ row,
1982
+ x: leftX + mx,
1983
+ y: topY + my,
1984
+ x2: rightX + mx,
1985
+ y2: bottomY + my,
1986
+ });
1987
+
1988
+ //#region check the relationship between this group and frozen columns
1989
+ const crossTheFrozen =
1990
+ group.from < self.frozenColumn && group.to >= self.frozenColumn;
1991
+ const notInFrozen = group.from >= self.frozenColumn;
1992
+ //#endregion
1993
+
1994
+ if (collapsed) {
1995
+ let leftX = leftmostX + toggleHandleSize;
1996
+ // This group is not sticking on the first column
1997
+ if (group.from > 0) {
1998
+ let colIndex = group.to + 1;
1999
+ let col = columnGroupsRectInfo[colIndex];
2000
+ if (!col) {
2001
+ colIndex = group.from - 1;
2002
+ col = columnGroupsRectInfo[colIndex];
2003
+ if (!col) continue; // don't draw this group indicator because it is invisible
2004
+ leftX = col.x + col.w - toggleHandleSize * 0.5;
2005
+ } else {
2006
+ leftX = col.x + toggleHandlePadding;
2007
+ }
2008
+ if (colIndex >= self.frozenColumn) {
2009
+ const compare =
2010
+ frozenColumnsWidth + rowHeaderCellWidth - toggleHandlePadding;
2011
+ // don't draw this group indicator because it is hidden by frozen columns
2012
+ if (leftX < compare) continue;
2013
+ }
2014
+ }
2015
+ const rightX = leftX + toggleHandleSize;
2016
+ ctx.save();
2017
+ ctx.strokeStyle = self.style.groupIndicatorColor;
2018
+ ctx.fillStyle = self.style.groupIndicatorBackgroundColor;
2019
+ drawGroupHandleAtX(leftX);
2020
+ ctx.restore();
2021
+ pushToVisibleGroups(leftX, rightX);
2022
+ } // end of collapsed group
2023
+
2024
+ /** @type {number} pointer for loop */
2025
+ let ptr;
2026
+ let left = columnGroupsRectInfo[group.from];
2027
+ let right = columnGroupsRectInfo[group.to];
2028
+
2029
+ let containsBegining = true;
2030
+ let containsEnd = true;
2031
+ ptr = group.from;
2032
+ while (!left && ptr < group.to) {
2033
+ left = columnGroupsRectInfo[++ptr];
2034
+ containsBegining = false;
2035
+ }
2036
+ ptr = group.to;
2037
+ while (!right && ptr > group.from) {
2038
+ right = columnGroupsRectInfo[--ptr];
2039
+ containsEnd = false;
2040
+ }
2041
+ if (!left || !right) continue;
2042
+ let rightX = right.x + right.w;
2043
+ let leftX = left.x;
2044
+ if (crossTheFrozen) {
2045
+ const rightCompare = columnGroupsRectInfo[self.frozenColumn - 1];
2046
+ if (rightCompare) {
2047
+ let compareX = rightCompare.x + rightCompare.w;
2048
+ if (!onTheLeft) compareX += toggleHandleSize;
2049
+ if (compareX >= rightX) {
2050
+ right = rightCompare;
2051
+ rightX = right.x + right.w;
2052
+ containsEnd = false;
2053
+ }
2054
+ }
2055
+ }
2056
+
2057
+ let minLeftX =
2058
+ rowHeaderCellWidth + (notInFrozen ? frozenColumnsWidth : 0);
2059
+ if (rightX + (onTheLeft ? 0 : toggleHandleSize) < minLeftX) continue;
2060
+
2061
+ rightX -= toggleHandlePadding;
2062
+ leftX += toggleHandlePadding;
2063
+
2064
+ ctx.save();
2065
+ ctx.strokeStyle = self.style.groupIndicatorColor;
2066
+ ctx.fillStyle = self.style.groupIndicatorBackgroundColor;
2067
+ const lineCoords = [];
2068
+
2069
+ if (onTheLeft) {
2070
+ // avoid lines from two groups be overlapping
2071
+ minLeftX += toggleHandlePadding * 2;
2072
+ if (leftX < minLeftX) leftX = minLeftX;
2073
+ if (group.from === 0) leftX -= toggleHandlePadding * 2;
2074
+ if (rightX >= leftX) {
2075
+ lineCoords.push(leftX, centerY, rightX, centerY);
2076
+ if (containsEnd) lineCoords.push(rightX, bottomY);
2077
+ } else {
2078
+ rightX = leftX;
2079
+ }
2080
+
2081
+ leftX -= toggleHandleSize;
2082
+ drawGroupHandleAtX(leftX);
2083
+ // add more clickable area into `visibleGroups`
2084
+ rightX += toggleHandlePadding - 1;
2085
+ } else {
2086
+ // handle on the right
2087
+ if (leftX < minLeftX) leftX = minLeftX;
2088
+ if (group.from === 0) leftX -= toggleHandlePadding * 2;
2089
+ if (containsEnd) {
2090
+ if (group.to === self.frozenColumn - 1) {
2091
+ rightX -= toggleHandleSize;
2092
+ } else {
2093
+ rightX += toggleHandlePadding * 2;
2094
+ }
2095
+ drawGroupHandleAtX(rightX);
2096
+ }
2097
+ if (leftX > rightX) {
2098
+ leftX = rightX;
2099
+ } else {
2100
+ if (group.from === 0) {
2101
+ containsBegining = true;
2102
+ leftX = leftmostX + toggleHandleSize;
2103
+ }
2104
+ if (containsBegining) lineCoords.push(leftX, bottomY);
2105
+ lineCoords.push(leftX, centerY, rightX, centerY);
2106
+ }
2107
+
2108
+ // add more clickable area into `visibleGroups`
2109
+ leftX -= toggleHandlePadding + 1;
2110
+ if (containsEnd) rightX += toggleHandleSize;
2111
+ }
2112
+ drawLines(lineCoords);
2113
+ ctx.restore();
2114
+ pushToVisibleGroups(leftX, rightX);
2115
+ }
2116
+ }
2117
+ //#endregion Columns Grouping
2118
+
2119
+ //#region Rows Grouping
2120
+ /** it extends `self.groupedRows` */
2121
+ const groupedRows = [];
2122
+ for (let col = 0; col < self.groupedRows.length; col++) {
2123
+ const groups = self.groupedRows[col];
2124
+ for (let j = 0; j < groups.length; j++) {
2125
+ groupedRows.push(Object.assign({ col }, groups[j]));
2126
+ }
2127
+ }
2128
+ if (groupedRows.length > 0) {
2129
+ const colWidth = self.style.rowGroupColumnWidth;
2130
+ const toggleHandleSize = colWidth * 0.5;
2131
+ const toggleHandlePadding = (colWidth - toggleHandleSize) * 0.5;
2132
+
2133
+ for (let i = 0; i < groupedRows.length; i++) {
2134
+ const group = groupedRows[i];
2135
+ const { col, collapsed } = group;
2136
+
2137
+ const leftX = -mx + col * colWidth;
2138
+ const centerX = leftX + colWidth * 0.5;
2139
+ const rightX = leftX + colWidth - toggleHandlePadding;
2140
+ const topmostY =
2141
+ columnHeaderCellHeight - toggleHandleSize - toggleHandlePadding;
2142
+
2143
+ const drawGroupHandleAtY = (y) =>
2144
+ drawGroupHandle(
2145
+ leftX + toggleHandlePadding,
2146
+ y,
2147
+ toggleHandleSize,
2148
+ group.collapsed,
2149
+ );
2150
+ const pushToVisibleGroups = (topY, bottomY) =>
2151
+ self.visibleGroups.push({
2152
+ type: 'r',
2153
+ collapsed,
2154
+ from: group.from,
2155
+ to: group.to,
2156
+ col,
2157
+ x: leftX + mx,
2158
+ y: topY + my,
2159
+ x2: rightX + mx,
2160
+ y2: bottomY + my,
2161
+ });
2162
+
2163
+ //#region check the relationship between this group and frozen columns
2164
+ const crossTheFrozen =
2165
+ group.from < self.frozenRow && group.to >= self.frozenRow;
2166
+ const notInFrozen = group.from >= self.frozenRow;
2167
+ //#endregion
2168
+
2169
+ if (collapsed) {
2170
+ let topY = topmostY + toggleHandleSize;
2171
+ // This group is not sticking on the first column
2172
+ if (group.from > 0) {
2173
+ let rowIndex = group.to + 1;
2174
+ let row = rowGroupsRectInfo[rowIndex];
2175
+ if (!row) {
2176
+ rowIndex = group.from - 1;
2177
+ row = rowGroupsRectInfo[rowIndex];
2178
+ if (!row) continue; // don't draw this group indicator because it is invisible
2179
+ topY = row.y + row.h - toggleHandleSize * 0.5;
2180
+ } else {
2181
+ topY = row.y;
2182
+ }
2183
+ if (rowIndex >= self.frozenRow) {
2184
+ const compare =
2185
+ frozenRowsHeight +
2186
+ columnHeaderCellHeight -
2187
+ toggleHandlePadding;
2188
+ // don't draw this group indicator because it is hidden by frozen columns
2189
+ if (topY < compare) continue;
2190
+ }
2191
+ }
2192
+ const bottomY = topY + toggleHandleSize;
2193
+ ctx.save();
2194
+ ctx.strokeStyle = self.style.groupIndicatorColor;
2195
+ ctx.fillStyle = self.style.groupIndicatorBackgroundColor;
2196
+ drawGroupHandleAtY(topY);
2197
+ ctx.restore();
2198
+ pushToVisibleGroups(topY, bottomY);
2199
+ } // end of collapsed group
2200
+
2201
+ /** @type {number} pointer for loop */
2202
+ let ptr;
2203
+ let top = rowGroupsRectInfo[group.from];
2204
+ let bottom = rowGroupsRectInfo[group.to];
2205
+
2206
+ let containsBegining = true;
2207
+ let containsEnd = true;
2208
+ ptr = group.from;
2209
+ while (!top && ptr < group.to) {
2210
+ top = rowGroupsRectInfo[++ptr];
2211
+ containsBegining = false;
2212
+ }
2213
+ ptr = group.to;
2214
+ while (!bottom && ptr > group.from) {
2215
+ bottom = rowGroupsRectInfo[--ptr];
2216
+ containsEnd = false;
2217
+ }
2218
+ if (!top || !bottom) continue;
2219
+ let bottomY = bottom.y + bottom.h;
2220
+ let topY = top.y;
2221
+ if (crossTheFrozen) {
2222
+ const bottomCompare = rowGroupsRectInfo[self.frozenRow - 1];
2223
+ if (bottomCompare) {
2224
+ let compareY = bottomCompare.y + bottomCompare.h;
2225
+ if (!onTheTop) compareY += toggleHandleSize;
2226
+ if (compareY >= bottomY) {
2227
+ bottom = bottomCompare;
2228
+ bottomY = bottom.y + bottom.h;
2229
+ containsEnd = false;
2230
+ }
2231
+ }
2232
+ }
2233
+
2234
+ let minTopY =
2235
+ columnHeaderCellHeight + (notInFrozen ? frozenRowsHeight : 0);
2236
+ if (bottomY + (onTheTop ? 0 : toggleHandleSize) < minTopY) continue;
2237
+
2238
+ bottomY -= toggleHandlePadding;
2239
+ topY += toggleHandlePadding;
2240
+
2241
+ ctx.save();
2242
+ ctx.strokeStyle = self.style.groupIndicatorColor;
2243
+ ctx.fillStyle = self.style.groupIndicatorBackgroundColor;
2244
+ const lineCoords = [];
2245
+
2246
+ if (onTheTop) {
2247
+ // avoid lines from two groups be overlapping
2248
+ minTopY += toggleHandlePadding * 2;
2249
+ if (topY < minTopY) topY = minTopY;
2250
+ if (group.from === 0) topY -= toggleHandlePadding * 2;
2251
+ if (bottomY >= topY) {
2252
+ lineCoords.push(centerX, topY, centerX, bottomY);
2253
+ if (containsEnd) lineCoords.push(rightX, bottomY);
2254
+ } else {
2255
+ bottomY = topY;
2256
+ }
2257
+
2258
+ topY -= toggleHandleSize;
2259
+ drawGroupHandleAtY(topY);
2260
+
2261
+ // add more clickable area into `visibleGroups`
2262
+ bottomY += toggleHandlePadding - 1;
2263
+ } else {
2264
+ // handle on the bottom
2265
+ if (topY < minTopY) topY = minTopY;
2266
+ if (group.from === 0) topY -= toggleHandlePadding * 2;
2267
+ if (containsEnd) {
2268
+ if (group.to === self.frozenRow - 1) {
2269
+ bottomY -= toggleHandleSize;
2270
+ } else {
2271
+ // bottomY += toggleHandlePadding * 2;
2272
+ }
2273
+ drawGroupHandleAtY(bottomY);
2274
+ }
2275
+ if (topY > bottomY) {
2276
+ topY = bottomY;
2277
+ } else {
2278
+ if (group.from === 0) {
2279
+ containsBegining = true;
2280
+ topY = topmostY + toggleHandleSize;
2281
+ }
2282
+ if (containsBegining) lineCoords.push(rightX, topY);
2283
+ lineCoords.push(centerX, topY, centerX, bottomY);
2284
+ // add more clickable area into `visibleGroups`
2285
+ topY -= toggleHandlePadding + 1;
2286
+ }
2287
+ // add more clickable area into `visibleGroups`
2288
+ if (containsEnd) bottomY += toggleHandleSize;
2289
+ }
2290
+ drawLines(lineCoords);
2291
+ ctx.restore();
2292
+ pushToVisibleGroups(topY, bottomY);
2293
+ }
2294
+ }
2295
+ //#endregion Rows Grouping
2296
+ }
1480
2297
  function drawFrozenRows() {
1481
2298
  var rowOrderIndex,
1482
2299
  ln = Math.min(viewData.length, self.frozenRow);
@@ -1535,6 +2352,12 @@ export default function (self) {
1535
2352
  rowOrderIndex = self.orders.rows[rowIndex];
1536
2353
  self.scrollIndexBottom = rowIndex;
1537
2354
  self.scrollPixelBottom = y;
2355
+ if (
2356
+ self.cellTree.rows.length > 0 &&
2357
+ Object.keys(self.cellTree.rows[rowOrderIndex]).length > 0 &&
2358
+ self.cellTree.rows[rowOrderIndex].hide
2359
+ )
2360
+ continue;
1538
2361
  if (!drawRow(rowOrderIndex, rowIndex)) {
1539
2362
  break;
1540
2363
  }
@@ -1550,12 +2373,14 @@ export default function (self) {
1550
2373
  columnOrderIndex < g;
1551
2374
  columnOrderIndex += 1
1552
2375
  ) {
1553
- headerIndex = self.orders.columns[columnOrderIndex];
1554
- x += drawCell(self.newRow, viewData.length, viewData.length)(
1555
- schema[headerIndex],
1556
- headerIndex,
1557
- columnOrderIndex,
1558
- );
2376
+ if (!isColumnCollapsedByGroup(columnOrderIndex)) {
2377
+ headerIndex = self.orders.columns[columnOrderIndex];
2378
+ x += drawCell(self.newRow, viewData.length, viewData.length)(
2379
+ schema[headerIndex],
2380
+ headerIndex,
2381
+ columnOrderIndex,
2382
+ );
2383
+ }
1559
2384
  if (x > self.width + self.scrollBox.scrollLeft) {
1560
2385
  break;
1561
2386
  }
@@ -1767,6 +2592,7 @@ export default function (self) {
1767
2592
  self.ctx.restore();
1768
2593
  }
1769
2594
  function drawFrozenMarkers() {
2595
+ if (self.dragStartObject !== undefined) return;
1770
2596
  var my = self.lastFrozenRowPixel - self.style.frozenMarkerWidth,
1771
2597
  mx = self.lastFrozenColumnPixel - self.style.frozenMarkerBorderWidth,
1772
2598
  xHover =
@@ -1801,14 +2627,16 @@ export default function (self) {
1801
2627
  : self.style.frozenMarkerBorderColor;
1802
2628
  fillRect(0, my, self.width, self.style.frozenMarkerWidth);
1803
2629
  strokeRect(0, my, self.width, self.style.frozenMarkerWidth);
2630
+ const height =
2631
+ self.style.frozenMarkerWidth + self.style.frozenMarkerBorderWidth;
1804
2632
  self.visibleCells.unshift({
1805
2633
  x: 0,
1806
2634
  y: my,
1807
- height:
1808
- self.style.frozenMarkerWidth + self.style.frozenMarkerBorderWidth,
2635
+ height,
1809
2636
  width: self.width,
1810
2637
  style: 'frozen-row-marker',
1811
2638
  });
2639
+ rowGroupsFrozenInfo = { y: my, h: height };
1812
2640
  }
1813
2641
  if (self.freezeMarkerPosition) {
1814
2642
  self.ctx.fillStyle = self.style.frozenMarkerActiveColor;
@@ -2047,6 +2875,7 @@ export default function (self) {
2047
2875
  self.ctx.save();
2048
2876
  initDraw();
2049
2877
  drawBackground();
2878
+ initGroupArea();
2050
2879
  drawFrozenRows();
2051
2880
  drawRows();
2052
2881
  drawActiveCell();
@@ -2061,6 +2890,7 @@ export default function (self) {
2061
2890
  if (checkScrollHeight) {
2062
2891
  self.resize(true);
2063
2892
  }
2893
+ drawGroupArea();
2064
2894
  drawDebug();
2065
2895
  drawPerfLines();
2066
2896
  if (self.dispatchEvent('afterdraw', {})) {