canvas-datagrid 0.3.15 → 0.3.19

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/dist/types.d.ts CHANGED
@@ -416,6 +416,11 @@ declare class canvasDatagrid {
416
416
  * @param dontDraw - Suppress the draw method after the selection change.
417
417
  */
418
418
  static selectAll(dontDraw: boolean): void;
419
+ /**
420
+ * Returns true if indices of columns next to the selected columnIndex is selected on every row.
421
+ * @param columnIndex - The column index to check.
422
+ */
423
+ static isMultiColumnsSelected(columnIndex: number): void;
419
424
  /**
420
425
  * Returns true if the selected columnIndex is selected on every row.
421
426
  * @param columnIndex - The column index to check.
package/lib/draw.js CHANGED
@@ -601,15 +601,29 @@ export default function (self) {
601
601
  m = self.style.scrollBarBoxMargin * 2;
602
602
  self.ctx.strokeStyle = self.style.scrollBarBorderColor;
603
603
  self.ctx.lineWidth = self.style.scrollBarBorderWidth;
604
- en.horizontalBox.x =
605
- rowHeaderCellWidth +
606
- self.style.scrollBarBoxMargin +
607
- (en.horizontalBar.width - self.scrollBox.scrollBoxWidth) *
608
- (self.scrollBox.scrollLeft / self.scrollBox.scrollWidth);
604
+ if (self.frozenColumn > 0) {
605
+ en.horizontalBox.x =
606
+ rowHeaderCellWidth +
607
+ self.style.scrollBarBoxMargin +
608
+ self.scrollCache.x[self.frozenColumn - 1] +
609
+ (en.horizontalBar.width -
610
+ self.scrollCache.x[self.frozenColumn - 1] -
611
+ self.scrollBox.scrollBoxWidth) *
612
+ (self.scrollBox.scrollLeft / self.scrollBox.scrollWidth);
613
+ } else {
614
+ en.horizontalBox.x =
615
+ rowHeaderCellWidth +
616
+ self.style.scrollBarBoxMargin +
617
+ (en.horizontalBar.width - self.scrollBox.scrollBoxWidth) *
618
+ (self.scrollBox.scrollLeft / self.scrollBox.scrollWidth);
619
+ }
609
620
  en.verticalBox.y =
610
621
  columnHeaderCellHeight +
611
622
  self.style.scrollBarBoxMargin +
612
- (en.verticalBar.height - self.scrollBox.scrollBoxHeight) *
623
+ self.scrollCache.y[self.frozenRow] +
624
+ (en.verticalBar.height -
625
+ self.scrollBox.scrollBoxHeight -
626
+ self.scrollCache.y[self.frozenRow]) *
613
627
  (self.scrollBox.scrollTop / self.scrollBox.scrollHeight);
614
628
  if (self.scrollBox.horizontalBarVisible) {
615
629
  self.ctx.fillStyle = self.style.scrollBarBackgroundColor;
@@ -1102,11 +1116,17 @@ export default function (self) {
1102
1116
 
1103
1117
  // Gaps may occur in row numbers between consecutively rendered rows
1104
1118
  // when we are filtering. We draw attention to this by drawing a thick
1105
- // border overlapping the two consecutive row headers.
1119
+ // border overlapping the two consecutive row headers. If sorting, visible
1120
+ // row numbers stay the same (i.e. they don't correspond to the underlying
1121
+ // data's row number), so we do not show row gaps in that case.
1122
+ const isSorting =
1123
+ self.orderings.columns && self.orderings.columns.length > 0;
1124
+
1106
1125
  if (
1107
1126
  isRowHeader &&
1108
1127
  self.attributes.showRowNumbers &&
1109
- self.attributes.showRowNumberGaps
1128
+ self.attributes.showRowNumberGaps &&
1129
+ isSorting === false
1110
1130
  ) {
1111
1131
  const previousRowNumber = self.getBoundRowIndexFromViewRowIndex(
1112
1132
  rowOrderIndex - 1,
@@ -1514,6 +1534,10 @@ export default function (self) {
1514
1534
  self.ctx.lineWidth = self.style.reorderMarkerBorderWidth;
1515
1535
  self.ctx.strokeStyle = self.style.reorderMarkerBorderColor;
1516
1536
  if (self.dragMode === 'row-reorder') {
1537
+ for (var k = 0; k < self.selections.length; k++) {
1538
+ if (!self.selections[k] || k == self.reorderObject.rowIndex) continue;
1539
+ b.height += self.getRowHeight(k);
1540
+ }
1517
1541
  b.width = w;
1518
1542
  b.x = 0;
1519
1543
  m.width = w;
@@ -1536,6 +1560,12 @@ export default function (self) {
1536
1560
  );
1537
1561
  }
1538
1562
  } else if (self.dragMode === 'column-reorder' && self.reorderObject) {
1563
+ var selectedColumns = self.selections[0];
1564
+ for (var k = 1; k < selectedColumns.length; k++) {
1565
+ b.width += self.getColumnWidth(
1566
+ self.orders.columns[selectedColumns[k]],
1567
+ );
1568
+ }
1539
1569
  b.height = h;
1540
1570
  b.y = 0;
1541
1571
  m.height = h;
@@ -254,7 +254,13 @@ export default function (self) {
254
254
  setScrollBoxSize();
255
255
  self.scrollBox.scrollWidth = dataWidth - self.scrollBox.width;
256
256
  self.scrollBox.scrollHeight = dataHeight - self.scrollBox.height;
257
- self.scrollBox.widthBoxRatio = self.scrollBox.width / dataWidth;
257
+ if (self.frozenColumn > 0) {
258
+ self.scrollBox.widthBoxRatio =
259
+ (self.scrollBox.width - self.scrollCache.x[self.frozenColumn - 1]) /
260
+ dataWidth;
261
+ } else {
262
+ self.scrollBox.widthBoxRatio = self.scrollBox.width / dataWidth;
263
+ }
258
264
  self.scrollBox.scrollBoxWidth =
259
265
  self.scrollBox.width * self.scrollBox.widthBoxRatio -
260
266
  self.style.scrollBarWidth -
@@ -266,7 +272,10 @@ export default function (self) {
266
272
  // the dragged mouse.
267
273
  // https://github.com/TonyGermaneri/canvas-datagrid/issues/97
268
274
  self.scrollBox.heightBoxRatio =
269
- (self.scrollBox.height - columnHeaderCellHeight) / dataHeight;
275
+ (self.scrollBox.height -
276
+ columnHeaderCellHeight -
277
+ self.scrollCache.y[self.frozenRow]) /
278
+ dataHeight;
270
279
  self.scrollBox.scrollBoxHeight =
271
280
  self.scrollBox.height * self.scrollBox.heightBoxRatio -
272
281
  self.style.scrollBarWidth -
@@ -296,12 +305,13 @@ export default function (self) {
296
305
  self.style.scrollBarWidth -
297
306
  self.style.scrollBarBorderWidth -
298
307
  d;
299
- v.y += columnHeaderCellHeight;
308
+ v.y += columnHeaderCellHeight + self.scrollCache.y[self.frozenRow];
300
309
  v.width = self.style.scrollBarWidth + self.style.scrollBarBorderWidth + d;
301
310
  v.height =
302
311
  self.height - columnHeaderCellHeight - self.style.scrollBarWidth - d - m;
303
312
  // vertical box
304
313
  vb.x = v.x + self.style.scrollBarBoxMargin;
314
+ vb.y += self.scrollCache.y[self.frozenRow];
305
315
  vb.width = self.style.scrollBarBoxWidth;
306
316
  vb.height = self.scrollBox.scrollBoxHeight;
307
317
  // corner
@@ -546,6 +556,8 @@ export default function (self) {
546
556
  }
547
557
  } else if (dragBounds.top !== -1) {
548
558
  self.selectArea(sBounds, true);
559
+ if (sBounds.left == -1 && sBounds.top !== sBounds.bottom)
560
+ self.isMultiRowsSelected = true;
549
561
  }
550
562
  }
551
563
 
@@ -641,11 +653,6 @@ export default function (self) {
641
653
  checkSelectionChange();
642
654
  return;
643
655
  }
644
- if (self.attributes.columnHeaderClickBehavior === 'select') {
645
- self.selectColumn(i.header.index, ctrl, e.shiftKey);
646
- self.draw();
647
- return;
648
- }
649
656
  }
650
657
  self.selections[i.rowIndex] = self.selections[i.rowIndex] || [];
651
658
  if (
@@ -868,6 +875,14 @@ export default function (self) {
868
875
  if (!self.attributes.allowRowReordering && rowReorder) {
869
876
  return;
870
877
  }
878
+ if ((e.ctrlKey || e.metaKey || e.shiftKey) && self.reorderObject) {
879
+ if (
880
+ self.dragMode === 'column-reorder' &&
881
+ !self.isMultiColumnsSelected(self.draggingItem.header.index)
882
+ ) {
883
+ self.selectColumn(self.draggingItem.header.index, false, false);
884
+ }
885
+ }
871
886
  if (
872
887
  self.dispatchEvent('reordering', {
873
888
  NativeEvent: e,
@@ -883,6 +898,11 @@ export default function (self) {
883
898
  Math.abs(y) > self.attributes.reorderDeadZone
884
899
  ) {
885
900
  self.reorderObject = self.draggingItem;
901
+ if (self.isMultiRowsSelected)
902
+ self.reorderObject = self.getVisibleCellByIndex(
903
+ -1,
904
+ self.activeCell.rowIndex,
905
+ );
886
906
  self.reorderTarget = self.currentCell;
887
907
  self.reorderObject.dragOffset = {
888
908
  x: x,
@@ -899,7 +919,7 @@ export default function (self) {
899
919
  self.stopDragReorder = function (e) {
900
920
  var oIndex,
901
921
  tIndex,
902
- odata,
922
+ odata = [],
903
923
  cr = {
904
924
  'row-reorder': self.orders.rows,
905
925
  'column-reorder': self.orders.columns,
@@ -931,14 +951,40 @@ export default function (self) {
931
951
  oIndex = cr[self.dragMode].indexOf(self.reorderObject[i]);
932
952
  tIndex = cr[self.dragMode].indexOf(self.reorderTarget[i]);
933
953
  if (self.dragMode === 'column-reorder') {
934
- cr[self.dragMode].splice(oIndex, 1);
935
- cr[self.dragMode].splice(tIndex, 0, self.reorderObject[i]);
954
+ var sortColumnIndices = [];
955
+ var seletedColumnIndices = [];
956
+ if (self.selections[0]) {
957
+ self.selections[0].forEach(function (value) {
958
+ sortColumnIndices.push(self.orders.columns[value]);
959
+ });
960
+ }
961
+ var deleteCount = sortColumnIndices.length;
962
+ cr[self.dragMode].splice(oIndex, deleteCount);
963
+ if (tIndex > oIndex) tIndex = tIndex - (deleteCount - 1);
964
+ for (var i = 0; i < sortColumnIndices.length; i++) {
965
+ seletedColumnIndices.push(tIndex + i);
966
+ cr[self.dragMode].splice(tIndex + i, 0, sortColumnIndices[i]);
967
+ }
936
968
  self.orders.columns = cr[self.dragMode];
969
+ self.viewData.forEach(function (row, rowIndex) {
970
+ self.selections[rowIndex] = seletedColumnIndices;
971
+ });
937
972
  } else {
938
- // self.orders.rows = cr[self.dragMode];
939
- odata = self.viewData[oIndex];
940
- self.viewData[oIndex] = self.viewData[tIndex];
941
- self.viewData[tIndex] = odata;
973
+ var selectedRows = [];
974
+ self.selections.forEach(function (row, rowIndex) {
975
+ if (row) {
976
+ selectedRows.push(row);
977
+ odata.push(self.viewData[rowIndex]);
978
+ }
979
+ });
980
+ self.viewData.splice(oIndex, odata.length);
981
+ self.selections = [];
982
+ if (tIndex > oIndex) tIndex = tIndex - (odata.length - 1);
983
+ self.activeCell.rowIndex = tIndex;
984
+ for (var i = 0; i < odata.length; i++) {
985
+ self.viewData.splice(tIndex + i, 0, odata[i]);
986
+ self.selections[tIndex + i] = selectedRows[i];
987
+ }
942
988
  }
943
989
  self.resize();
944
990
  self.setStorageData();
@@ -1000,7 +1046,12 @@ export default function (self) {
1000
1046
  ) {
1001
1047
  return;
1002
1048
  }
1003
- var pos = self.getLayerPos(e);
1049
+ var pos = self.getLayerPos(e),
1050
+ bm = self.style.gridBorderCollapse === 'collapse' ? 1 : 2,
1051
+ columnHeaderCellBorder = self.style.columnHeaderCellBorderWidth * bm,
1052
+ columnHeaderCellHeight = self.getColumnHeaderCellHeight(),
1053
+ rowHeaderCellWidth = self.getRowHeaderCellWidth();
1054
+
1004
1055
  self.ignoreNextClick = true;
1005
1056
  self.freezeMarkerPosition = pos;
1006
1057
  if (
@@ -1010,6 +1061,28 @@ export default function (self) {
1010
1061
  ) {
1011
1062
  self.scrollBox.scrollTop = 0;
1012
1063
  self.frozenRow = self.currentCell.rowIndex + 1;
1064
+ self.scrollBox.bar.v.y =
1065
+ columnHeaderCellHeight +
1066
+ columnHeaderCellBorder +
1067
+ self.scrollCache.y[self.frozenRow];
1068
+ self.scrollBox.box.v.y =
1069
+ columnHeaderCellHeight +
1070
+ columnHeaderCellBorder +
1071
+ self.scrollCache.y[self.frozenRow];
1072
+ var dataHeight = self.scrollCache.y[self.scrollCache.y.length - 1];
1073
+ self.scrollBox.heightBoxRatio =
1074
+ (self.scrollBox.height -
1075
+ columnHeaderCellHeight -
1076
+ self.scrollCache.y[self.frozenRow]) /
1077
+ dataHeight;
1078
+ self.scrollBox.scrollBoxHeight =
1079
+ self.scrollBox.height * self.scrollBox.heightBoxRatio -
1080
+ self.style.scrollBarWidth;
1081
+ self.scrollBox.scrollBoxHeight = Math.max(
1082
+ self.scrollBox.scrollBoxHeight,
1083
+ self.style.scrollBarBoxMinSize,
1084
+ );
1085
+ self.scrollBox.box.v.height = self.scrollBox.scrollBoxHeight;
1013
1086
  }
1014
1087
  if (
1015
1088
  self.currentCell &&
@@ -1018,6 +1091,22 @@ export default function (self) {
1018
1091
  ) {
1019
1092
  self.scrollBox.scrollLeft = 0;
1020
1093
  self.frozenColumn = self.currentCell.columnIndex + 1;
1094
+ self.scrollBox.bar.h.x =
1095
+ rowHeaderCellWidth + self.scrollCache.x[self.frozenColumn - 1];
1096
+ self.scrollBox.box.h.x =
1097
+ rowHeaderCellWidth + self.scrollCache.x[self.frozenColumn - 1];
1098
+ var dataWidth = self.scrollCache.x[self.scrollCache.x.length - 1];
1099
+ self.scrollBox.widthBoxRatio =
1100
+ (self.scrollBox.width - self.scrollCache.x[self.frozenColumn - 1]) /
1101
+ dataWidth;
1102
+ self.scrollBox.scrollBoxWidth =
1103
+ self.scrollBox.width * self.scrollBox.widthBoxRatio -
1104
+ self.style.scrollBarWidth;
1105
+ self.scrollBox.scrollBoxWidth = Math.max(
1106
+ self.scrollBox.scrollBoxWidth,
1107
+ self.style.scrollBarBoxMinSize,
1108
+ );
1109
+ self.scrollBox.box.h.width = self.scrollBox.scrollBoxWidth;
1021
1110
  }
1022
1111
  if (
1023
1112
  Math.abs(pos.x) > self.attributes.reorderDeadZone ||
@@ -1084,7 +1173,8 @@ export default function (self) {
1084
1173
  !freeze &&
1085
1174
  !resize
1086
1175
  ) {
1087
- self.selections = [];
1176
+ if (!(self.dragMode == 'row-reorder' && self.isMultiRowsSelected))
1177
+ self.selections = [];
1088
1178
  }
1089
1179
  if (self.dragStartObject.isGrid) {
1090
1180
  return;
@@ -1175,10 +1265,11 @@ export default function (self) {
1175
1265
  self.draggingItem = self.dragStartObject;
1176
1266
  if (
1177
1267
  self.dragMode === 'column-reorder' &&
1178
- self.attributes.columnHeaderClickBehavior === 'select'
1268
+ !self.isMultiColumnsSelected(self.currentCell.header.index)
1179
1269
  ) {
1180
1270
  self.selectColumn(self.currentCell.header.index, ctrl, e.shiftKey);
1181
- self.draw();
1271
+ } else if (self.dragMode === 'row-reorder' && !self.isMultiRowsSelected) {
1272
+ self.selectRow(self.dragStartObject.rowIndex, ctrl, null);
1182
1273
  }
1183
1274
  document.body.addEventListener('mousemove', self.dragReorder, false);
1184
1275
  document.body.addEventListener('mouseup', self.stopDragReorder, false);
@@ -1187,14 +1278,9 @@ export default function (self) {
1187
1278
  };
1188
1279
  self.mouseup = function (e) {
1189
1280
  clearTimeout(self.scrollTimer);
1190
- var ctrl = e.ctrlKey || e.metaKey;
1191
1281
  self.cellBoundaryCrossed = true;
1192
1282
  self.rowBoundaryCrossed = true;
1193
1283
  self.columnBoundaryCrossed = true;
1194
- if (self.draggingItem) {
1195
- self.selectColumn(self.currentCell.header.index, ctrl, e.shiftKey);
1196
- self.draw();
1197
- }
1198
1284
  self.selecting = undefined;
1199
1285
  self.draggingItem = undefined;
1200
1286
  self.dragStartObject = undefined;
@@ -1740,6 +1826,7 @@ export default function (self) {
1740
1826
  firstRowKeys,
1741
1827
  isNeat = true; // Selected like [[0, 1], [0, 1]] of [[0, 3]] is neat; Selected like [[0, 1], [1, 2]] is untidy
1742
1828
  function htmlSafe(v) {
1829
+ if (typeof v === 'number') return v;
1743
1830
  return v.replace(/</g, '&lt;').replace(/>/g, '&gt;');
1744
1831
  }
1745
1832
  s.forEach(function (column, columnIndex) {
@@ -1753,8 +1840,8 @@ export default function (self) {
1753
1840
  if (!firstRowKeys) firstRowKeys = Object.keys(row);
1754
1841
  if (isNeat && rowKeys.length !== firstRowKeys.length) isNeat = false;
1755
1842
  sSorted.forEach(function (column, columnIndex) {
1756
- if (rowKeys.indexOf(column.name) < 0) {
1757
- if (firstRowKeys.indexOf(column.name) < 0) {
1843
+ if (rowKeys.indexOf(String(column.name)) < 0) {
1844
+ if (firstRowKeys.indexOf(String(column.name)) < 0) {
1758
1845
  return;
1759
1846
  } else if (isNeat) {
1760
1847
  isNeat = false;
@@ -379,6 +379,37 @@ export default function (self) {
379
379
  }
380
380
  self.draw();
381
381
  };
382
+ /**
383
+ * Returns true if indices of columns next to the selected columnIndex is selected on every row.
384
+ * @memberof canvasDatagrid
385
+ * @name isMultiColumnsSelected
386
+ * @method
387
+ * @param {number} columnIndex The column index to check.
388
+ */
389
+ self.isMultiColumnsSelected = function (columnIndex) {
390
+ var multiColIsSelected = true;
391
+ self.viewData.forEach(function (row, rowIndex) {
392
+ var columnIndices = self.selections[rowIndex];
393
+ if (
394
+ !columnIndices ||
395
+ columnIndices.length <= 1 ||
396
+ columnIndices.indexOf(columnIndex) === -1
397
+ ) {
398
+ multiColIsSelected = false;
399
+ } else if (columnIndices.length > 1) {
400
+ if (columnIndices[0] != columnIndex) multiColIsSelected = false;
401
+ else {
402
+ for (var i = 0; i < columnIndices.length - 1; i++) {
403
+ if (columnIndices[i] + 1 != columnIndices[i + 1]) {
404
+ multiColIsSelected = false;
405
+ break;
406
+ }
407
+ }
408
+ }
409
+ }
410
+ });
411
+ return multiColIsSelected;
412
+ };
382
413
  /**
383
414
  * Returns true if the selected columnIndex is selected on every row.
384
415
  * @memberof canvasDatagrid
@@ -391,8 +422,7 @@ export default function (self) {
391
422
  self.viewData.forEach(function (row, rowIndex) {
392
423
  if (
393
424
  !self.selections[rowIndex] ||
394
- self.selections[rowIndex].indexOf(self.orders.columns[columnIndex]) ===
395
- -1
425
+ self.selections[rowIndex].indexOf(columnIndex) === -1
396
426
  ) {
397
427
  colIsSelected = false;
398
428
  }
@@ -504,6 +534,7 @@ export default function (self) {
504
534
  st,
505
535
  en,
506
536
  s = self.getVisibleSchema();
537
+ self.isMultiRowsSelected = false;
507
538
  function de() {
508
539
  if (supressEvent) {
509
540
  return;
@@ -1367,22 +1398,18 @@ export default function (self) {
1367
1398
  self.sorters.string = function (columnName, direction) {
1368
1399
  var asc = direction === 'asc';
1369
1400
  return function (a, b) {
1370
- if (a[columnName] === undefined || a[columnName] === null) {
1371
- return 1;
1372
- }
1373
- if (b[columnName] === undefined || b[columnName] === null) {
1374
- return 0;
1375
- }
1401
+ const aValue = a[columnName] || '';
1402
+ const bValue = b[columnName] || '';
1376
1403
  if (asc) {
1377
- if (!a[columnName].localeCompare) {
1404
+ if (!aValue.localeCompare) {
1378
1405
  return 1;
1379
1406
  }
1380
- return a[columnName].localeCompare(b[columnName]);
1407
+ return aValue.localeCompare(bValue);
1381
1408
  }
1382
- if (!b[columnName].localeCompare) {
1409
+ if (!bValue.localeCompare) {
1383
1410
  return 1;
1384
1411
  }
1385
- return b[columnName].localeCompare(a[columnName]);
1412
+ return bValue.localeCompare(aValue);
1386
1413
  };
1387
1414
  };
1388
1415
  self.sorters.number = function (columnName, direction) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canvas-datagrid",
3
- "version": "0.3.15",
3
+ "version": "0.3.19",
4
4
  "description": "Canvas based data grid web component. Capable of displaying millions of contiguous hierarchical rows and columns without paging or loading, on a single canvas element.",
5
5
  "main": "./dist/canvas-datagrid.js",
6
6
  "module": "./dist/canvas-datagrid.module.js",