canvas-datagrid 0.3.24 → 0.4.2

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.
@@ -331,6 +331,39 @@ export default function (self) {
331
331
  imgSrc,
332
332
  );
333
333
  };
334
+
335
+ /**
336
+ * Expand/Collapse CellTree.
337
+ * @memberof canvasDatagrid
338
+ * @name toggleCellCollapseTree
339
+ * @method
340
+ * @param {array} treeData The array of cellTree to expand or collapse.
341
+ */
342
+
343
+ self.toggleCellCollapseTree = function (treeData) {
344
+ for (let type in treeData) {
345
+ for (let t of treeData[type])
346
+ if (t.length > 0) self.toggleCollapseTree(t[0], t[1], type);
347
+ }
348
+ self.draw();
349
+ };
350
+
351
+ /**
352
+ * Expand/Collapse CellTree.
353
+ * @memberof canvasDatagrid
354
+ * @name expandCollapseCellTree
355
+ * @method
356
+ * @param {array} treeData The array of cellTree to expand or collapse.
357
+ */
358
+
359
+ self.expandCollapseCellTree = function (treeData) {
360
+ for (let type in treeData) {
361
+ for (let t of treeData[type])
362
+ if (t.length > 0) self.cellTreeExpandCollapse(t[0], t[1], type);
363
+ }
364
+ self.draw();
365
+ };
366
+
334
367
  /**
335
368
  * Scrolls the cell at cell x, row y into view if it is not already.
336
369
  * @memberof canvasDatagrid
@@ -342,18 +375,25 @@ export default function (self) {
342
375
  * @param {number} [offsetY=0] Percentage offset the cell should be from the top edge (not including headers). The default is 0, meaning the cell will appear at the top edge. Valid values are 0 through 1. 1 = Bottom, 0 = Top, 0.5 = Center.
343
376
  */
344
377
  self.scrollIntoView = function (x, y, offsetX, offsetY) {
345
- if (
346
- self.visibleCells.filter(function (cell) {
347
- return (
348
- (cell.rowIndex === y || y === undefined) &&
349
- (cell.columnIndex === x || x === undefined) &&
350
- cell.x > 0 &&
351
- cell.y > 0 &&
352
- cell.x + cell.width < self.width &&
353
- cell.y + cell.height < self.height
354
- );
355
- }).length === 0
356
- ) {
378
+ const matched = self.visibleCells.filter(function (cell) {
379
+ return (
380
+ (cell.rowIndex === y || y === undefined) &&
381
+ (cell.columnIndex === x || x === undefined) &&
382
+ cell.x > 0 &&
383
+ cell.y > 0 &&
384
+ cell.x + cell.width < self.width &&
385
+ cell.y + cell.height < self.height
386
+ );
387
+ });
388
+ if (matched.length === 1 && x !== undefined && y !== undefined) {
389
+ // goto specific cell and its part be hidden by header
390
+ if (
391
+ matched[0].x < self.getRowHeaderCellWidth() ||
392
+ matched[0].y < self.getColumnHeaderCellHeight()
393
+ )
394
+ matched.length = 0;
395
+ }
396
+ if (matched.length === 0) {
357
397
  self.gotoCell(x, y, offsetX, offsetY);
358
398
  }
359
399
  };
@@ -846,6 +886,244 @@ export default function (self) {
846
886
  }
847
887
  self.setStorageData();
848
888
  };
889
+
890
+ /**
891
+ * Add grouping
892
+ * @param {'columns'|'rows'} groupFor
893
+ * @param {number} from
894
+ * @param {number} to
895
+ */
896
+ function addGroup(groupFor, from, to) {
897
+ let newRow = false;
898
+ const allGroups =
899
+ groupFor === 'rows' ? self.groupedRows : self.groupedColumns;
900
+ for (let i = allGroups.length - 1; i >= 0; i--) {
901
+ const groups = allGroups[i];
902
+ const min = groups[0].from,
903
+ max = groups[groups.length - 1].to;
904
+ if (from <= min && to >= max) {
905
+ if (from === min && to === max && groups.length === 1) return; // nothings happened
906
+ // new group wrap this row
907
+ continue;
908
+ }
909
+ for (let gi = 0; gi < groups.length; gi++) {
910
+ const g = groups[gi];
911
+ if (from > g.to) continue;
912
+ if (from >= g.from) {
913
+ if (to > g.to) {
914
+ if (from === g.from) {
915
+ allGroups.splice(i, 0, [{ from, to, collapsed: false }]);
916
+ self.refresh();
917
+ return;
918
+ }
919
+ throw new Error(`Can't group these ${groupFor}`);
920
+ }
921
+ if (to === g.to) {
922
+ if (from === g.from) return; // nothings happened
923
+ }
924
+ newRow = true;
925
+ break;
926
+ }
927
+ if (to >= g.from) {
928
+ if (to < g.to) throw new Error(`Can't group these ${groupFor}`);
929
+ allGroups.splice(i, 0, [{ from, to, collapsed: false }]);
930
+ } else {
931
+ groups.splice(gi, 0, { from, to, collapsed: false });
932
+ }
933
+ self.refresh();
934
+ return;
935
+ }
936
+ if (newRow) continue;
937
+ groups.push({ from, to, collapsed: false });
938
+ self.refresh();
939
+ return;
940
+ }
941
+ if (newRow) allGroups.push([{ from, to, collapsed: false }]);
942
+ else allGroups.unshift([{ from, to, collapsed: false }]);
943
+ self.refresh();
944
+ }
945
+ /**
946
+ * Remove grouping
947
+ * @param {Array<Array<{from:number,to:number,collapsed:boolean}>>} allGroups
948
+ * @param {number} from
949
+ * @param {number} to
950
+ */
951
+ function removeGroup(allGroups, from, to) {
952
+ for (let i = 0; i < allGroups.length; i++) {
953
+ const groups = allGroups[i];
954
+ for (let gi = 0; gi < groups.length; gi++) {
955
+ const group = groups[gi];
956
+ if (group.from === from && group.to === to) {
957
+ if (groups.length <= 1) allGroups.splice(i, 1);
958
+ else groups.splice(gi, 1);
959
+ self.refresh();
960
+ return;
961
+ }
962
+ }
963
+ }
964
+ }
965
+ /**
966
+ * Grouping columns
967
+ * @memberof canvasDatagrid
968
+ * @name groupColumns
969
+ * @method
970
+ * @param {number|string} firstColumnName Name of the first column to be grouped.
971
+ * @param {number|string} lastColumnName Name of the last column to be grouped.
972
+ */
973
+ self.groupColumns = function (firstColumnName, lastColumnName) {
974
+ /** @type {Array<{name: string,columnIndex:number}>} */
975
+ const schema = self.getSchema();
976
+ let firstOne, lastOne;
977
+ for (let i = 0; i < schema.length; i++) {
978
+ const it = schema[i];
979
+ if (firstOne && lastOne) break;
980
+ if (it.name === firstColumnName) {
981
+ firstOne = it;
982
+ continue;
983
+ }
984
+ if (it.name === lastColumnName) {
985
+ lastOne = it;
986
+ continue;
987
+ }
988
+ }
989
+ if (!firstOne) throw new Error(`No such column name for first column`);
990
+ if (!lastOne) throw new Error(`No such column name for last column`);
991
+ if (lastOne.columnIndex > firstOne.columnIndex !== true)
992
+ throw new Error(`Can't group these columns`);
993
+
994
+ const from = firstOne.columnIndex;
995
+ const to = lastOne.columnIndex;
996
+ const ev = { group: { type: 'columns', from, to } };
997
+ try {
998
+ addGroup('columns', from, to);
999
+ } catch (error) {
1000
+ ev.error = error;
1001
+ }
1002
+ self.dispatchEvent('aftercreategroup', ev);
1003
+ };
1004
+ /**
1005
+ * Grouping columns
1006
+ * @memberof canvasDatagrid
1007
+ * @name groupRows
1008
+ * @method
1009
+ * @param {number} rowIndexFrom The row index which is the beginning of the group
1010
+ * @param {number} rowIndexTo The row index which is the end of the group
1011
+ */
1012
+ self.groupRows = function (rowIndexFrom, rowIndexTo) {
1013
+ if (!Number.isInteger(rowIndexFrom) || rowIndexFrom < 0)
1014
+ throw new Error(`No such row for the beginning of the group`);
1015
+
1016
+ const dataLength = self.viewData.length;
1017
+ if (
1018
+ !Number.isInteger(rowIndexFrom) ||
1019
+ rowIndexTo <= rowIndexFrom ||
1020
+ rowIndexTo >= dataLength
1021
+ )
1022
+ throw new Error(`No such row for the end of the group`);
1023
+ const ev = {
1024
+ group: {
1025
+ type: 'rows',
1026
+ from: rowIndexFrom,
1027
+ to: rowIndexTo,
1028
+ },
1029
+ };
1030
+ try {
1031
+ addGroup('rows', rowIndexFrom, rowIndexTo);
1032
+ } catch (error) {
1033
+ ev.error = error;
1034
+ }
1035
+ self.dispatchEvent('aftercreategroup', ev);
1036
+ };
1037
+ /**
1038
+ * Remove grouping columns
1039
+ * @memberof canvasDatagrid
1040
+ * @name removeGroupColumns
1041
+ * @method
1042
+ * @param {number|string} firstColumnName Name of the first column to be grouped.
1043
+ * @param {number|string} lastColumnName Name of the last column to be grouped.
1044
+ */
1045
+ self.removeGroupColumns = function (firstColumnName, lastColumnName) {
1046
+ /** @type {Array<{name:string,columnIndex:number}>} */
1047
+ const schema = self.getSchema();
1048
+ let firstOne, lastOne;
1049
+ for (let i = 0; i < schema.length; i++) {
1050
+ const it = schema[i];
1051
+ if (firstOne && lastOne) break;
1052
+ if (it.name === firstColumnName) {
1053
+ firstOne = it;
1054
+ continue;
1055
+ }
1056
+ if (it.name === lastColumnName) {
1057
+ lastOne = it;
1058
+ continue;
1059
+ }
1060
+ }
1061
+ if (!firstOne) throw new Error(`No such column name for first column`);
1062
+ if (!lastOne) throw new Error(`No such column name for last column`);
1063
+ const from = firstOne.columnIndex;
1064
+ const to = lastOne.columnIndex;
1065
+ removeGroup(self.groupedColumns, from, to);
1066
+ };
1067
+ /**
1068
+ * Remove grouping columns
1069
+ * @memberof canvasDatagrid
1070
+ * @name removeGroupRows
1071
+ * @method
1072
+ * @param {number} rowIndexFrom The row index which is the beginning of the group
1073
+ * @param {number} rowIndexTo The row index which is the end of the group
1074
+ */
1075
+ self.removeGroupRows = function (rowIndexFrom, rowIndexTo) {
1076
+ removeGroup(self.groupedRows, rowIndexFrom, rowIndexTo);
1077
+ };
1078
+ /**
1079
+ * Toggle(expand/collapsed) grouping columns
1080
+ * @memberof canvasDatagrid
1081
+ * @name toggleGroupColumns
1082
+ * @method
1083
+ * @param {number|string} firstColumnName Name of the first column to be grouped.
1084
+ * @param {number|string} lastColumnName Name of the last column to be grouped.
1085
+ */
1086
+ self.toggleGroupColumns = function (firstColumnName, lastColumnName) {
1087
+ /** @type {Array<{name:string,columnIndex:number}>} */
1088
+ const schema = self.getSchema();
1089
+ let firstOne, lastOne;
1090
+ for (let i = 0; i < schema.length; i++) {
1091
+ const it = schema[i];
1092
+ if (firstOne && lastOne) break;
1093
+ if (it.name === firstColumnName) {
1094
+ firstOne = it;
1095
+ continue;
1096
+ }
1097
+ if (it.name === lastColumnName) {
1098
+ lastOne = it;
1099
+ continue;
1100
+ }
1101
+ }
1102
+ if (!firstOne || !lastOne) return;
1103
+ const from = firstOne.columnIndex;
1104
+ const to = lastOne.columnIndex;
1105
+ if (self.toggleGroup({ type: 'c', from, to })) {
1106
+ self.disposeContextMenu();
1107
+ self.setStorageData();
1108
+ self.refresh();
1109
+ }
1110
+ };
1111
+ /**
1112
+ * Toggle(expand/collapsed) grouping rows
1113
+ * @memberof canvasDatagrid
1114
+ * @name toggleGroupRows
1115
+ * @method
1116
+ * @param {number} rowIndexFrom The row index which is the beginning of the group
1117
+ * @param {number} rowIndexTo The row index which is the end of the group
1118
+ */
1119
+ self.toggleGroupRows = function (rowIndexFrom, rowIndexTo) {
1120
+ if (self.toggleGroup({ type: 'r', from: rowIndexFrom, to: rowIndexTo })) {
1121
+ self.disposeContextMenu();
1122
+ self.setStorageData();
1123
+ self.refresh();
1124
+ }
1125
+ };
1126
+
849
1127
  self.isInGrid = function (e) {
850
1128
  if (e.x < 0 || e.x > self.width || e.y < 0 || e.y > self.height) {
851
1129
  return false;
@@ -924,6 +1202,9 @@ export default function (self) {
924
1202
  return;
925
1203
  }
926
1204
  // TODO:
1205
+ if (!self.data) {
1206
+ self.data = {};
1207
+ }
927
1208
  if (!self.data[rowIndex]) {
928
1209
  self.data[rowIndex] = {};
929
1210
  }
@@ -964,6 +1245,53 @@ export default function (self) {
964
1245
  });
965
1246
  });
966
1247
  };
1248
+ /**
1249
+ * Get the column group info given column belongs to
1250
+ * @memberof canvasDatagrid
1251
+ * @name getGroupsColumnBelongsTo
1252
+ * @method
1253
+ * @param {number} columnIndex Column index.
1254
+ * @returns {Array<{from:number,to:number,collapsed:boolean}>}
1255
+ */
1256
+ self.getGroupsColumnBelongsTo = function (columnIndex) {
1257
+ if (!self.attributes.allowGroupingColumns) return [];
1258
+ const result = [];
1259
+ for (let i = 0; i < self.groupedColumns.length; i++) {
1260
+ const groups = self.groupedColumns[i];
1261
+ for (let j = 0; j < groups.length; j++) {
1262
+ const group = groups[j];
1263
+ if (columnIndex >= group.from && columnIndex <= group.to) {
1264
+ result.push(group);
1265
+ break;
1266
+ }
1267
+ }
1268
+ }
1269
+ return result;
1270
+ };
1271
+ /**
1272
+ * Get the row group info given row belongs to
1273
+ * @memberof canvasDatagrid
1274
+ * @name getGroupsRowBelongsTo
1275
+ * @method
1276
+ * @param {number} rowIndex Row index.
1277
+ * @returns {Array<{from:number,to:number,collapsed:boolean}>}
1278
+ */
1279
+ self.getGroupsRowBelongsTo = function (rowIndex) {
1280
+ if (!self.attributes.allowGroupingRows) return [];
1281
+ const result = [];
1282
+ for (let i = 0; i < self.groupedRows.length; i++) {
1283
+ const groups = self.groupedRows[i];
1284
+ for (let j = 0; j < groups.length; j++) {
1285
+ const group = groups[j];
1286
+ if (rowIndex >= group.from && rowIndex <= group.to) {
1287
+ result.push(group);
1288
+ break;
1289
+ }
1290
+ }
1291
+ }
1292
+ return result;
1293
+ };
1294
+
967
1295
  /**
968
1296
  * Checks if a given column is visible.
969
1297
  * @memberof canvasDatagrid
@@ -1008,6 +1336,44 @@ export default function (self) {
1008
1336
  return c.columnIndex === x && c.rowIndex === y;
1009
1337
  })[0];
1010
1338
  };
1339
+ /**
1340
+ * Get a column group at grid pixel coordinate x and y.
1341
+ * @memberof canvasDatagrid
1342
+ * @name getColumnGroupAt
1343
+ * @method
1344
+ * @param {number} x Number of pixels from the left.
1345
+ * @param {number} y Number of pixels from the top.
1346
+ */
1347
+ self.getColumnGroupAt = function (x, y) {
1348
+ const groups = self.groupedColumns.length;
1349
+ if (groups <= 0) return;
1350
+ const yZero = self.getColumnGroupAreaHeight();
1351
+ if (y >= yZero) return;
1352
+ for (let i = 0; i < self.visibleGroups.length; i++) {
1353
+ const g = self.visibleGroups[i];
1354
+ if (g.type !== 'c') continue;
1355
+ if (x >= g.x && y >= g.y && x <= g.x2 && y <= g.y2) return g;
1356
+ }
1357
+ };
1358
+ /**
1359
+ * Get a row group at grid pixel coordinate x and y.
1360
+ * @memberof canvasDatagrid
1361
+ * @name getRowGroupAt
1362
+ * @method
1363
+ * @param {number} x Number of pixels from the left.
1364
+ * @param {number} y Number of pixels from the top.
1365
+ */
1366
+ self.getRowGroupAt = function (x, y) {
1367
+ const groups = self.groupedRows.length;
1368
+ if (groups <= 0) return;
1369
+ const xZero = self.getRowGroupAreaWidth();
1370
+ if (x >= xZero) return;
1371
+ for (let i = 0; i < self.visibleGroups.length; i++) {
1372
+ const g = self.visibleGroups[i];
1373
+ if (g.type !== 'r') continue;
1374
+ if (x >= g.x && y >= g.y && x <= g.x2 && y <= g.y2) return g;
1375
+ }
1376
+ };
1011
1377
  /**
1012
1378
  * Gets the cell at grid pixel coordinate x and y. Author's note. This function ties drawing and events together. This is a very complex function and is core to the component.
1013
1379
  * @memberof canvasDatagrid
@@ -1049,6 +1415,8 @@ export default function (self) {
1049
1415
  if (!self.visibleCells) {
1050
1416
  return;
1051
1417
  }
1418
+ x -= self.getRowGroupAreaWidth();
1419
+ y -= self.getColumnGroupAreaHeight();
1052
1420
  var border,
1053
1421
  tsz = useTouchScrollZones ? self.attributes.touchScrollZone : 0,
1054
1422
  moveMode = self.attributes.borderDragBehavior === 'move',
@@ -1197,8 +1565,20 @@ export default function (self) {
1197
1565
  }
1198
1566
  }
1199
1567
  if (cell.style === 'columnHeaderCell') {
1200
- cell.context = 'cell';
1201
- cell.dragContext = 'column-reorder';
1568
+ if (
1569
+ cell.x +
1570
+ cell.width -
1571
+ self.attributes.columnGrabZoneSize -
1572
+ self.style.cellBorderWidth >
1573
+ x ||
1574
+ !self.attributes.allowRowReordering
1575
+ ) {
1576
+ cell.dragContext = 'cell';
1577
+ cell.context = 'cell';
1578
+ } else {
1579
+ cell.context = self.cursorGrab;
1580
+ cell.dragContext = 'column-reorder';
1581
+ }
1202
1582
  return cell;
1203
1583
  }
1204
1584
  if (cell.style === 'rowHeaderCell') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canvas-datagrid",
3
- "version": "0.3.24",
3
+ "version": "0.4.2",
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",