canvas-datagrid 0.4.2 → 0.4.5

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
@@ -110,8 +110,9 @@ export default function (self) {
110
110
  }
111
111
  /**
112
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
113
114
  */
114
- function strokeLines(coords) {
115
+ function drawLines(coords, fill) {
115
116
  if (coords.length < 4) return;
116
117
  self.ctx.beginPath();
117
118
  self.ctx.moveTo(
@@ -123,7 +124,8 @@ export default function (self) {
123
124
  const y = coords[i + 1] + self.canvasOffsetTop;
124
125
  self.ctx.lineTo(x, y);
125
126
  }
126
- self.ctx.stroke();
127
+ if (fill) self.ctx.fill();
128
+ else self.ctx.stroke();
127
129
  }
128
130
  /**
129
131
  * @param {number} x based-X (left-top)
@@ -136,8 +138,67 @@ export default function (self) {
136
138
  strokeRect(x, y, width, width);
137
139
  const cx = x + width * 0.5;
138
140
  const cy = y + width * 0.5;
139
- strokeLines([x + width * 0.2, cy, x + width * 0.78, cy]);
140
- if (collapsed) strokeLines([cx, y + width * 0.22, cx, y + width * 0.8]);
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);
141
202
  }
142
203
  function drawOrderByArrow(x, y) {
143
204
  var mt = self.style.columnHeaderOrderByArrowMarginTop * self.scale,
@@ -719,7 +780,15 @@ export default function (self) {
719
780
  columnGroupsRectInfo = {},
720
781
  collapsedColumnGroups = self.getCollapsedColumnGroups(),
721
782
  collapsedRowGroups = self.getCollapsedRowGroups(),
722
- cellHeight = self.style.cellHeight;
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);
723
792
  drawCount += 1;
724
793
  p = performance.now();
725
794
  self.visibleRowHeights = [];
@@ -874,13 +943,17 @@ export default function (self) {
874
943
  selectionHandles.push([cell, 'tr']);
875
944
  cell.selectionHandle = 'tr';
876
945
  }
877
- if (
878
- cell.selectionBorderTop &&
879
- cell.selectionBorderLeft &&
880
- self.mobile
881
- ) {
882
- selectionHandles.push([cell, 'tl']);
883
- cell.selectionHandle = 'tl';
946
+ if (cell.selectionBorderTop && cell.selectionBorderLeft) {
947
+ if (self.mobile) {
948
+ selectionHandles.push([cell, 'tl']);
949
+ cell.selectionHandle = 'tl';
950
+ }
951
+ if (self.fillOverlay.handle) {
952
+ self.fillOverlay.snapTo = {
953
+ x: cell.x,
954
+ y: cell.y,
955
+ };
956
+ }
884
957
  }
885
958
  if (
886
959
  cell.selectionBorderBottom &&
@@ -897,6 +970,22 @@ export default function (self) {
897
970
  ) {
898
971
  selectionHandles.push([cell, 'br']);
899
972
  cell.selectionHandle = 'br';
973
+
974
+ if (self.fillOverlay.handle) {
975
+ self.fillOverlay.handle.x = cell.x + cell.width;
976
+ self.fillOverlay.handle.y = cell.y + cell.height;
977
+ }
978
+ }
979
+
980
+ if (self.fillOverlay.handle) {
981
+ // Some corners may not be displaying, so we get at least
982
+ // one correct axis in order to display a fill overlay.
983
+ if (self.fillOverlay.snapTo.x === -1 && cell.selectionBorderLeft) {
984
+ self.fillOverlay.snapTo.x = cell.x;
985
+ }
986
+ if (self.fillOverlay.snapTo.y === -1 && cell.selectionBorderTop) {
987
+ self.fillOverlay.snapTo.y = cell.y;
988
+ }
900
989
  }
901
990
  }
902
991
  }
@@ -995,8 +1084,10 @@ export default function (self) {
995
1084
  isGrid = header.type === 'canvas-datagrid',
996
1085
  activeHeader =
997
1086
  (self.orders.rows[self.activeCell.rowIndex] === rowOrderIndex ||
1087
+ self.selectedRows.indexOf(rowOrderIndex) >= 0 ||
998
1088
  self.orders.columns[self.activeCell.columnIndex] ===
999
- headerIndex) &&
1089
+ headerIndex ||
1090
+ self.selectedColumns.indexOf(headerIndex) >= 0) &&
1000
1091
  (columnOrderIndex === -1 || rowOrderIndex === -1)
1001
1092
  ? isRowHeader
1002
1093
  ? 'activeRowHeaderCell'
@@ -1369,6 +1460,19 @@ export default function (self) {
1369
1460
  group.to === cell.boundRowIndex,
1370
1461
  ) >= 0;
1371
1462
  }
1463
+ // We don't treat the row index difference from hidden rows as the row gap.
1464
+ if (hasRowGap && self.hiddenRowRanges.length > 0) {
1465
+ for (let i = 0; i < self.hiddenRowRanges.length; i++) {
1466
+ const [beginRowIndex, endRowIndex] = self.hiddenRowRanges[i];
1467
+ if (
1468
+ cell.boundRowIndex === endRowIndex + 1 &&
1469
+ previousRowNumber === beginRowIndex - 1
1470
+ ) {
1471
+ hasRowGap = false;
1472
+ break;
1473
+ }
1474
+ }
1475
+ }
1372
1476
 
1373
1477
  if (hasRowGap) {
1374
1478
  const barHeight = self.style.rowHeaderCellRowNumberGapHeight;
@@ -1384,9 +1488,141 @@ export default function (self) {
1384
1488
  }
1385
1489
  }
1386
1490
 
1491
+ //#region draw unhide indicator for column headers
1492
+ if (isColumnHeader && self.attributes.showUnhideColumnsIndicator) {
1493
+ const hovered = self.hovers.unhideIndicator;
1494
+ const size = self.style.unhideIndicatorSize;
1495
+ const cellX = x;
1496
+ const topY = cell.y + Math.max(0.5 * (cell.height - size), 0);
1497
+
1498
+ const isActive = (orderIndex) =>
1499
+ hovered &&
1500
+ (hovered.dir === 'l' || hovered.dir === 'r') &&
1501
+ orderIndex >= hovered.orderIndex0 &&
1502
+ orderIndex <= hovered.orderIndex1;
1503
+ const isHiddenColumn = (columnIndex) =>
1504
+ columnIndex >= 0 &&
1505
+ schema[columnIndex] &&
1506
+ schema[columnIndex].hidden;
1507
+
1508
+ let orderIndex0, orderIndex1;
1509
+ const drawIndicator = (leftX, dir, active) => {
1510
+ self.visibleUnhideIndicators.push({
1511
+ x: leftX - 1,
1512
+ y: topY - 1,
1513
+ x2: leftX + size + 2,
1514
+ y2: topY + size + 2,
1515
+ orderIndex0,
1516
+ orderIndex1,
1517
+ dir,
1518
+ });
1519
+ if (!active) {
1520
+ const line = cell.text && cell.text.lines && cell.text.lines[0];
1521
+ if (line) {
1522
+ const iconsWidth = orderByArrowSize + treeArrowSize;
1523
+ const lineX0 = iconsWidth > 0 ? iconsWidth : line.x;
1524
+ const lineX1 = line.x + line.width;
1525
+ if (leftX + size >= lineX0 && leftX <= lineX1) return;
1526
+ }
1527
+ }
1528
+ drawUnhideIndicator(leftX, topY, size, dir, active);
1529
+ }; // end of drawIndicator
1530
+
1531
+ let orderIndexPtr = columnOrderIndex - 1;
1532
+ const prevColumnIndex = self.orders.columns[orderIndexPtr];
1533
+ if (isHiddenColumn(prevColumnIndex)) {
1534
+ const active = isActive(prevColumnIndex);
1535
+ orderIndex0 = orderIndexPtr;
1536
+ orderIndex1 = orderIndexPtr;
1537
+ while (--orderIndexPtr >= 0) {
1538
+ if (isHiddenColumn(self.orders.columns[orderIndexPtr]))
1539
+ orderIndex0 = orderIndexPtr;
1540
+ else break;
1541
+ }
1542
+ drawIndicator(cellX, 'r', active);
1543
+ }
1544
+
1545
+ orderIndexPtr = columnOrderIndex + 1;
1546
+ const nextColumnIndex = self.orders.columns[orderIndexPtr];
1547
+ if (isHiddenColumn(nextColumnIndex)) {
1548
+ const active = isActive(nextColumnIndex);
1549
+ orderIndex0 = orderIndexPtr;
1550
+ orderIndex1 = orderIndexPtr;
1551
+ while (++orderIndexPtr < self.orders.columns.length) {
1552
+ if (isHiddenColumn(self.orders.columns[orderIndexPtr]))
1553
+ orderIndex1 = orderIndexPtr;
1554
+ else break;
1555
+ }
1556
+ const indicatorX = x + cell.width - size;
1557
+ drawIndicator(indicatorX, 'l', active);
1558
+ }
1559
+ }
1560
+ //#endregion draw unhide indicator for column headers
1561
+
1562
+ //#region draw unhide indicator for row headers
1563
+ if (
1564
+ isRowHeader &&
1565
+ self.attributes.showUnhideRowsIndicator &&
1566
+ self.hiddenRowRanges.length > 0
1567
+ ) {
1568
+ // Leo's comment:
1569
+ // from the first row to the last row, `rowIndex` is from 0 to the count of rows
1570
+ // but `boundRowIndex` can be disordered if there are any ordered columns or filtered columns
1571
+ // Like this statement:
1572
+ // console.log(rowIndex, cell.boundRowIndex, cell.formattedValue);
1573
+ // can output the result like this:
1574
+ // 0 1 '2'
1575
+ // 1 3 '4'
1576
+ const hovered = self.hovers.unhideIndicator;
1577
+ const size = self.style.unhideIndicatorSize;
1578
+ const leftX = cell.x + cell.width - size - 2;
1579
+ const cellY = y;
1580
+ const topIndicators = {};
1581
+ const bottomIndicators = {};
1582
+ self.hiddenRowRanges.forEach((it) => {
1583
+ topIndicators[it[0] - 1] = it;
1584
+ bottomIndicators[it[1] + 1] = it;
1585
+ });
1586
+
1587
+ const rowIndex = cell.rowIndex + currentRowIndexOffset;
1588
+ const isActive = () =>
1589
+ hovered &&
1590
+ (hovered.dir === 't' || hovered.dir === 'b') &&
1591
+ rowIndex >= hovered.orderIndex0 - 1 &&
1592
+ rowIndex <= hovered.orderIndex1 + 1;
1593
+
1594
+ let orderIndex0, orderIndex1;
1595
+ const drawIndicator = (topY, dir, active) => {
1596
+ self.visibleUnhideIndicators.push({
1597
+ x: leftX - 1,
1598
+ y: topY - 1,
1599
+ x2: leftX + size + 2,
1600
+ y2: topY + size + 2,
1601
+ orderIndex0,
1602
+ orderIndex1,
1603
+ dir,
1604
+ });
1605
+ drawUnhideIndicator(leftX, topY, size, dir, active);
1606
+ }; // end of drawIndicator
1607
+
1608
+ let matched = topIndicators[rowIndex];
1609
+ if (matched) {
1610
+ const indicatorY = cellY + cell.height - size;
1611
+ [orderIndex0, orderIndex1] = matched;
1612
+ drawIndicator(indicatorY, 't', isActive());
1613
+ }
1614
+ matched = bottomIndicators[rowIndex];
1615
+ if (matched) {
1616
+ const indicatorY = cellY;
1617
+ [orderIndex0, orderIndex1] = matched;
1618
+ drawIndicator(indicatorY, 'b', isActive());
1619
+ }
1620
+ }
1621
+ //#endregion draw unhide indicator for row headers
1622
+
1387
1623
  x += cell.width + (bc ? 0 : self.style.cellBorderWidth);
1388
1624
  return cell.width;
1389
- };
1625
+ }; // end of drawEach
1390
1626
  }
1391
1627
  function drawFilterButton(cell, ev) {
1392
1628
  var posX = cell.x + cell.width - self.style.filterButtonWidth - 1;
@@ -1424,17 +1660,20 @@ export default function (self) {
1424
1660
  // as it is in the unfiltered data, instead of simply the viewed
1425
1661
  // row index + 1. If rowIndex > viewData.length, it's a new row
1426
1662
  // added to the end, and we want to render that new row's number
1427
- const filteredRowNumber =
1428
- self.viewData && rowIndex < self.viewData.length
1429
- ? self.getBoundRowIndexFromViewRowIndex(rowIndex) + 1
1430
- : self.originalData
1663
+ let filteredRowNumber;
1664
+ if (self.viewData && rowIndex < self.viewData.length)
1665
+ filteredRowNumber =
1666
+ self.getBoundRowIndexFromViewRowIndex(rowIndex) + 1;
1667
+ else
1668
+ filteredRowNumber = self.originalData
1431
1669
  ? self.originalData.length + 1
1432
1670
  : rowOrderIndex + 1;
1433
1671
 
1434
- const rowHeaderValue =
1672
+ let rowHeaderValue =
1435
1673
  self.hasActiveFilters() || self.hasCollapsedRowGroup()
1436
1674
  ? filteredRowNumber
1437
1675
  : rowIndex + 1;
1676
+ rowHeaderValue += currentRowIndexOffset;
1438
1677
 
1439
1678
  const rowHeaderCell = { rowHeaderCell: rowHeaderValue };
1440
1679
  const headerDescription = {
@@ -1451,6 +1690,14 @@ export default function (self) {
1451
1690
  -1,
1452
1691
  -1,
1453
1692
  );
1693
+
1694
+ if (
1695
+ rowIndexOffsetByHiddenRows[0] &&
1696
+ rowHeaderValue >= rowIndexOffsetByHiddenRows[0].from
1697
+ ) {
1698
+ const { plus } = rowIndexOffsetByHiddenRows.shift();
1699
+ currentRowIndexOffset += plus;
1700
+ }
1454
1701
  }
1455
1702
  }
1456
1703
  function drawHeaders() {
@@ -1593,7 +1840,7 @@ export default function (self) {
1593
1840
  }
1594
1841
  }
1595
1842
  //draw frozen columns
1596
- x = 0;
1843
+ x = 1;
1597
1844
  if (self.attributes.showRowHeaders) {
1598
1845
  x += rowHeaderCellWidth;
1599
1846
  }
@@ -1675,12 +1922,20 @@ export default function (self) {
1675
1922
  schema = self.getSchema();
1676
1923
  self.visibleCells = [];
1677
1924
  self.visibleGroups = [];
1925
+ self.visibleUnhideIndicators = [];
1678
1926
  self.canvasOffsetTop = self.isChildGrid ? self.parentNode.offsetTop : 0.5;
1679
1927
  self.canvasOffsetLeft = self.isChildGrid
1680
1928
  ? self.parentNode.offsetLeft
1681
1929
  : -0.5;
1682
1930
  h = self.height;
1683
1931
  w = self.width;
1932
+
1933
+ // patch for first row being hidden
1934
+ const firstRowIndexOffset = rowIndexOffsetByHiddenRows[0];
1935
+ if (firstRowIndexOffset && firstRowIndexOffset.from === 0) {
1936
+ currentRowIndexOffset = firstRowIndexOffset.plus;
1937
+ rowIndexOffsetByHiddenRows.shift();
1938
+ }
1684
1939
  }
1685
1940
  function drawBackground() {
1686
1941
  radiusRect(0, 0, w, h, 0);
@@ -1876,7 +2131,7 @@ export default function (self) {
1876
2131
  leftX -= toggleHandlePadding + 1;
1877
2132
  if (containsEnd) rightX += toggleHandleSize;
1878
2133
  }
1879
- strokeLines(lineCoords);
2134
+ drawLines(lineCoords);
1880
2135
  ctx.restore();
1881
2136
  pushToVisibleGroups(leftX, rightX);
1882
2137
  }
@@ -2054,7 +2309,7 @@ export default function (self) {
2054
2309
  // add more clickable area into `visibleGroups`
2055
2310
  if (containsEnd) bottomY += toggleHandleSize;
2056
2311
  }
2057
- strokeLines(lineCoords);
2312
+ drawLines(lineCoords);
2058
2313
  ctx.restore();
2059
2314
  pushToVisibleGroups(topY, bottomY);
2060
2315
  }
@@ -2078,10 +2333,8 @@ export default function (self) {
2078
2333
  if (self.attributes.allowFreezingRows) {
2079
2334
  // HACK great, another stupid magic number.
2080
2335
  // Background will appear as a 0.5px artifact behind the row freeze bar without this hack
2081
- y +=
2082
- self.style.frozenMarkerBorderWidth +
2083
- self.style.frozenMarkerWidth -
2084
- 0.4999999999;
2336
+ if (y > columnHeaderCellHeight) y += self.style.frozenMarkerWidth;
2337
+ y += self.style.frozenMarkerBorderWidth - 0.4999999999;
2085
2338
  }
2086
2339
  self.lastFrozenRowPixel = y;
2087
2340
  }
@@ -2208,6 +2461,7 @@ export default function (self) {
2208
2461
  self.ctx.lineWidth = self.style.reorderMarkerIndexBorderWidth;
2209
2462
  self.ctx.strokeStyle = self.style.reorderMarkerIndexBorderColor;
2210
2463
  if (
2464
+ self.selectedRows.indexOf(self.reorderTarget.sortRowIndex) === -1 &&
2211
2465
  self.currentCell.rowIndex !== self.reorderObject.rowIndex &&
2212
2466
  self.currentCell.rowIndex > -1 &&
2213
2467
  self.currentCell.rowIndex < l
@@ -2221,10 +2475,12 @@ export default function (self) {
2221
2475
  }
2222
2476
  } else if (self.dragMode === 'column-reorder' && self.reorderObject) {
2223
2477
  var selectedColumns = self.selections[0];
2224
- for (var k = 1; k < selectedColumns.length; k++) {
2225
- b.width += self.getColumnWidth(
2226
- self.orders.columns[selectedColumns[k]],
2227
- );
2478
+ if (selectedColumns) {
2479
+ for (var k = 1; k < selectedColumns.length; k++) {
2480
+ b.width += self.getColumnWidth(
2481
+ self.orders.columns[selectedColumns[k]],
2482
+ );
2483
+ }
2228
2484
  }
2229
2485
  b.height = h;
2230
2486
  b.y = 0;
@@ -2237,8 +2493,11 @@ export default function (self) {
2237
2493
  self.ctx.lineWidth = self.style.reorderMarkerIndexBorderWidth;
2238
2494
  self.ctx.strokeStyle = self.style.reorderMarkerIndexBorderColor;
2239
2495
  if (
2496
+ self.selectedColumns.indexOf(self.reorderTarget.sortColumnIndex) ===
2497
+ -1 &&
2240
2498
  self.currentCell.sortColumnIndex !==
2241
2499
  self.reorderObject.sortColumnIndex &&
2500
+ self.reorderTarget.columnIndex !== self.reorderObject.columnIndex &&
2242
2501
  self.currentCell.sortColumnIndex > -1 &&
2243
2502
  self.currentCell.sortColumnIndex < schema.length
2244
2503
  ) {
@@ -2257,10 +2516,12 @@ export default function (self) {
2257
2516
  strokeRect(0, 0, self.width, self.height);
2258
2517
  }
2259
2518
  function drawSelectionBorders() {
2260
- self.ctx.lineWidth = self.style.selectionOverlayBorderWidth;
2261
- self.ctx.strokeStyle = self.style.selectionOverlayBorderColor;
2262
2519
  function dsb(c) {
2263
- addBorderLine(c[0], c[1]);
2520
+ if (!self.fillOverlay.handle) {
2521
+ self.ctx.lineWidth = self.style.selectionOverlayBorderWidth;
2522
+ self.ctx.strokeStyle = self.style.selectionOverlayBorderColor;
2523
+ addBorderLine(c[0], c[1]);
2524
+ }
2264
2525
  }
2265
2526
  selectionBorders
2266
2527
  .filter(function (c) {
@@ -2303,9 +2564,14 @@ export default function (self) {
2303
2564
  })
2304
2565
  .forEach(dsb);
2305
2566
  self.ctx.restore();
2567
+
2568
+ drawFillOverlay();
2306
2569
  }
2307
2570
  function drawSelectionHandles() {
2308
- if (self.mobile || self.attributes.allowMovingSelection) {
2571
+ if (
2572
+ (self.mobile || self.attributes.allowMovingSelection) &&
2573
+ self.attributes.editable
2574
+ ) {
2309
2575
  self.ctx.lineWidth = self.style.selectionHandleBorderWidth;
2310
2576
  self.ctx.strokeStyle = self.style.selectionHandleBorderColor;
2311
2577
  self.ctx.fillStyle = self.style.selectionHandleColor;
@@ -2326,6 +2592,62 @@ export default function (self) {
2326
2592
  });
2327
2593
  }
2328
2594
  }
2595
+ function drawFillOverlay() {
2596
+ if (!self.fillOverlay.handle || !self.fillOverlay.snapTo) {
2597
+ return;
2598
+ }
2599
+
2600
+ self.ctx.save();
2601
+
2602
+ const overlay = self.fillOverlay;
2603
+ const handle = overlay.handle;
2604
+ const toX = overlay.snapTo.x;
2605
+ const toY = overlay.snapTo.y;
2606
+
2607
+ // The cell that the cursor is moving over. This may be unavailable
2608
+ // when the cursor is outside the grid or is pointing to something else.
2609
+ //
2610
+ // When unavailable, we use the actual position of the cursor to draw
2611
+ // the overlay.
2612
+ const snap = overlay.snap;
2613
+
2614
+ // Calculate the X, Y coordinates of the cursor with snap positions and
2615
+ // the direction of the movement in mind.
2616
+ //
2617
+ // When the movement is horizontal, we get the Y coordinate from the handle,
2618
+ // and vice-versa.
2619
+ const cursorX =
2620
+ overlay.direction === 'x'
2621
+ ? snap
2622
+ ? snap.x + (overlay.x < toX ? 0 : snap.width)
2623
+ : overlay.x
2624
+ : handle.x;
2625
+ const cursorY =
2626
+ overlay.direction === undefined || overlay.direction === 'y'
2627
+ ? snap
2628
+ ? snap.y + (overlay.y < toY ? 0 : snap.height)
2629
+ : overlay.y
2630
+ : handle.y;
2631
+
2632
+ // The final coordinates of the rect. We use 'minX' and 'minY' to avoid
2633
+ // drawing on the frozen area.
2634
+ const x = Math.max(Math.min(toX, cursorX), overlay.minX);
2635
+ const y = Math.max(Math.min(toY, cursorY), overlay.minY);
2636
+
2637
+ // Width and height of the rect are the difference between the
2638
+ // coordinates of both the rect and the cursor. The user may be pointing
2639
+ // behind and/or upwards of the rect, so we need to take that into
2640
+ // account.
2641
+ const width = Math.max(toX, cursorX) - x;
2642
+ const height = Math.max(toY, cursorY) - y;
2643
+
2644
+ self.ctx.strokeStyle = self.style.fillOverlayBorderColor;
2645
+ self.ctx.lineWidth = self.style.fillOverlayBorderWidth;
2646
+ self.ctx.setLineDash([3, 3]);
2647
+ strokeRect(x, y, width, height);
2648
+ self.ctx.setLineDash([]);
2649
+ self.ctx.restore();
2650
+ }
2329
2651
  function drawActiveCell() {
2330
2652
  if (!aCell) {
2331
2653
  return;
@@ -2359,81 +2681,172 @@ export default function (self) {
2359
2681
  self.ctx.restore();
2360
2682
  }
2361
2683
  function drawFrozenMarkers() {
2362
- if (self.dragStartObject !== undefined) return;
2363
2684
  var my = self.lastFrozenRowPixel - self.style.frozenMarkerWidth,
2364
- mx = self.lastFrozenColumnPixel - self.style.frozenMarkerBorderWidth,
2685
+ mx = self.lastFrozenColumnPixel - self.style.frozenMarkerWidth,
2365
2686
  xHover =
2366
2687
  self.currentCell && self.currentCell.style === 'frozen-row-marker',
2367
2688
  yHover =
2368
2689
  self.currentCell && self.currentCell.style === 'frozen-column-marker';
2690
+ let rowHeaderCellWidth = self.getRowHeaderCellWidth();
2369
2691
  self.ctx.lineWidth = self.style.frozenMarkerBorderWidth;
2370
2692
  if (self.attributes.allowFreezingColumns) {
2371
- self.ctx.fillStyle = yHover
2372
- ? self.style.frozenMarkerHoverColor
2373
- : self.style.frozenMarkerColor;
2374
- self.ctx.strokeStyle = yHover
2375
- ? self.style.frozenMarkerHoverBorderColor
2376
- : self.style.frozenMarkerBorderColor;
2377
- fillRect(mx, 0, self.style.frozenMarkerWidth, self.height);
2378
- strokeRect(mx, 0, self.style.frozenMarkerWidth, self.height);
2379
- self.visibleCells.unshift({
2380
- x: mx,
2381
- y: 0,
2382
- height: self.height,
2383
- width:
2384
- self.style.frozenMarkerWidth + self.style.frozenMarkerBorderWidth,
2385
- style: 'frozen-column-marker',
2386
- });
2693
+ if (
2694
+ !self.freezeMarkerPosition ||
2695
+ (self.freezeMarkerPosition && self.dragMode === 'frozen-row-marker')
2696
+ ) {
2697
+ if (mx > self.style.rowHeaderCellWidth) {
2698
+ self.ctx.fillStyle = self.style.frozenMarkerColor;
2699
+ self.ctx.strokeStyle = self.style.frozenMarkerBorderColor;
2700
+ fillRect(mx, 0, self.style.frozenMarkerWidth, self.height);
2701
+ strokeRect(mx, 0, self.style.frozenMarkerWidth, self.height);
2702
+ }
2703
+ self.ctx.fillStyle = yHover
2704
+ ? self.style.frozenMarkerHoverColor
2705
+ : self.style.frozenMarkerHeaderColor;
2706
+ self.ctx.strokeStyle = yHover
2707
+ ? self.style.frozenMarkerHoverBorderColor
2708
+ : self.style.frozenMarkerHeaderColor;
2709
+ fillRect(
2710
+ mx,
2711
+ 0,
2712
+ self.style.frozenMarkerWidth,
2713
+ self.style.columnHeaderCellHeight,
2714
+ );
2715
+ strokeRect(
2716
+ mx,
2717
+ 0,
2718
+ self.style.frozenMarkerWidth,
2719
+ self.style.columnHeaderCellHeight,
2720
+ );
2721
+ }
2722
+
2723
+ if (
2724
+ !self.dragStartObject ||
2725
+ (self.dragStartObject &&
2726
+ self.dragStartObject.style !== 'rowHeaderCell')
2727
+ ) {
2728
+ self.visibleCells.unshift({
2729
+ x: mx,
2730
+ y: 0,
2731
+ height: self.height,
2732
+ width: self.style.frozenMarkerWidth, // + self.style.frozenMarkerBorderWidth,
2733
+ style: 'frozen-column-marker',
2734
+ });
2735
+ }
2387
2736
  }
2388
2737
  if (self.attributes.allowFreezingRows) {
2389
- self.ctx.fillStyle = xHover
2390
- ? self.style.frozenMarkerHoverColor
2391
- : self.style.frozenMarkerColor;
2392
- self.ctx.strokeStyle = xHover
2393
- ? self.style.frozenMarkerHoverBorderColor
2394
- : self.style.frozenMarkerBorderColor;
2395
- fillRect(0, my, self.width, self.style.frozenMarkerWidth);
2396
- strokeRect(0, my, self.width, self.style.frozenMarkerWidth);
2397
- const height =
2738
+ if (
2739
+ !self.freezeMarkerPosition ||
2740
+ (self.freezeMarkerPosition &&
2741
+ self.dragMode === 'frozen-column-marker')
2742
+ ) {
2743
+ if (my > rowHeaderCellWidth) {
2744
+ self.ctx.fillStyle = self.style.frozenMarkerColor;
2745
+ self.ctx.strokeStyle = self.style.frozenMarkerBorderColor;
2746
+ fillRect(0, my, self.width, self.style.frozenMarkerWidth);
2747
+ strokeRect(0, my, self.width, self.style.frozenMarkerWidth);
2748
+ }
2749
+ self.ctx.fillStyle = xHover
2750
+ ? self.style.frozenMarkerHoverColor
2751
+ : self.style.frozenMarkerHeaderColor;
2752
+ self.ctx.strokeStyle = xHover
2753
+ ? self.style.frozenMarkerHoverBorderColor
2754
+ : self.style.frozenMarkerHeaderColor;
2755
+ fillRect(0, my, rowHeaderCellWidth, self.style.frozenMarkerWidth);
2756
+ strokeRect(0, my, rowHeaderCellWidth, self.style.frozenMarkerWidth);
2757
+ }
2758
+ var height =
2398
2759
  self.style.frozenMarkerWidth + self.style.frozenMarkerBorderWidth;
2399
- self.visibleCells.unshift({
2400
- x: 0,
2401
- y: my,
2402
- height,
2403
- width: self.width,
2404
- style: 'frozen-row-marker',
2405
- });
2760
+ if (
2761
+ !self.dragStartObject ||
2762
+ (self.dragStartObject &&
2763
+ self.dragStartObject.style !== 'columnHeaderCell')
2764
+ ) {
2765
+ self.visibleCells.unshift({
2766
+ x: 0,
2767
+ y: my,
2768
+ height: height,
2769
+ width: self.width,
2770
+ style: 'frozen-row-marker',
2771
+ });
2772
+ }
2406
2773
  rowGroupsFrozenInfo = { y: my, h: height };
2407
2774
  }
2408
2775
  if (self.freezeMarkerPosition) {
2409
2776
  self.ctx.fillStyle = self.style.frozenMarkerActiveColor;
2410
2777
  self.ctx.strokeStyle = self.style.frozenMarkerActiveBorderColor;
2411
2778
  if (self.dragMode === 'frozen-column-marker') {
2779
+ let posX = self.freezeMarkerPosition.x;
2780
+ let nearCell = self.getCellAt(posX, 0);
2781
+ if (self.freezeMarkerPosition.isGrab) posX = mx;
2782
+ if (posX > rowHeaderCellWidth) {
2783
+ let x =
2784
+ nearCell.x -
2785
+ self.style.frozenMarkerWidth -
2786
+ self.style.frozenMarkerBorderWidth;
2787
+ if (posX > x + nearCell.width / 2) x = x + nearCell.width;
2788
+ self.ctx.fillStyle = self.style.frozenMarkerColor;
2789
+ self.ctx.strokeStyle = self.style.frozenMarkerBorderColor;
2790
+ fillRect(x, 0, self.style.frozenMarkerWidth, self.height);
2791
+ strokeRect(x, 0, self.style.frozenMarkerWidth, self.height);
2792
+ self.ctx.fillStyle = self.style.frozenMarkerHeaderColor;
2793
+ self.ctx.strokeStyle = self.style.frozenMarkerHeaderColor;
2794
+ fillRect(
2795
+ x,
2796
+ 0,
2797
+ self.style.frozenMarkerWidth,
2798
+ self.style.columnHeaderCellHeight,
2799
+ );
2800
+ strokeRect(
2801
+ x,
2802
+ 0,
2803
+ self.style.frozenMarkerWidth,
2804
+ self.style.columnHeaderCellHeight,
2805
+ );
2806
+ }
2807
+ self.ctx.fillStyle = self.style.frozenMarkerActiveHeaderColor;
2808
+ self.ctx.strokeStyle = self.style.frozenMarkerActiveBorderColor;
2412
2809
  fillRect(
2413
- self.freezeMarkerPosition.x,
2810
+ posX,
2414
2811
  0,
2415
2812
  self.style.frozenMarkerWidth,
2416
- self.height,
2813
+ self.style.columnHeaderCellHeight,
2417
2814
  );
2418
2815
  strokeRect(
2419
- self.freezeMarkerPosition.x,
2816
+ posX,
2420
2817
  0,
2421
2818
  self.style.frozenMarkerWidth,
2422
- self.height,
2819
+ self.style.columnHeaderCellHeight,
2423
2820
  );
2821
+ self.ctx.fillStyle = self.style.frozenMarkerActiveColor;
2822
+ fillRect(posX, 0, self.style.frozenMarkerWidth, self.height);
2823
+ strokeRect(posX, 0, self.style.frozenMarkerWidth, self.height);
2424
2824
  } else {
2425
- fillRect(
2426
- 0,
2427
- self.freezeMarkerPosition.y,
2428
- self.width,
2429
- self.style.frozenMarkerWidth,
2430
- );
2431
- strokeRect(
2432
- 0,
2433
- self.freezeMarkerPosition.y,
2434
- self.width,
2435
- self.style.frozenMarkerWidth,
2436
- );
2825
+ let posY = self.freezeMarkerPosition.y;
2826
+ let nearCell = self.getCellAt(0, posY);
2827
+ if (self.freezeMarkerPosition.isGrab) posY = my;
2828
+ if (posY > self.style.columnHeaderCellHeight) {
2829
+ let y =
2830
+ nearCell.y -
2831
+ self.style.frozenMarkerWidth -
2832
+ self.style.frozenMarkerBorderWidth;
2833
+ if (posY > y + nearCell.height / 2) y = y + nearCell.height;
2834
+ self.ctx.fillStyle = self.style.frozenMarkerColor;
2835
+ self.ctx.strokeStyle = self.style.frozenMarkerBorderColor;
2836
+ fillRect(0, y, self.width, self.style.frozenMarkerWidth);
2837
+ strokeRect(0, y, self.width, self.style.frozenMarkerWidth);
2838
+ self.ctx.fillStyle = self.style.frozenMarkerHeaderColor;
2839
+ self.ctx.strokeStyle = self.style.frozenMarkerHeaderColor;
2840
+ fillRect(0, y, rowHeaderCellWidth, self.style.frozenMarkerWidth);
2841
+ strokeRect(0, y, rowHeaderCellWidth, self.style.frozenMarkerWidth);
2842
+ }
2843
+ self.ctx.fillStyle = self.style.frozenMarkerActiveHeaderColor;
2844
+ self.ctx.strokeStyle = self.style.frozenMarkerActiveBorderColor;
2845
+ fillRect(0, posY, rowHeaderCellWidth, self.style.frozenMarkerWidth);
2846
+ strokeRect(0, posY, rowHeaderCellWidth, self.style.frozenMarkerWidth);
2847
+ self.ctx.fillStyle = self.style.frozenMarkerActiveColor;
2848
+ fillRect(0, posY, self.width, self.style.frozenMarkerWidth);
2849
+ strokeRect(0, posY, self.width, self.style.frozenMarkerWidth);
2437
2850
  }
2438
2851
  }
2439
2852
  }