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/dist/types.d.ts CHANGED
@@ -66,6 +66,8 @@
66
66
  * @param [args.autoScrollMargin = 5] - Number of pixels of mouse movement to trigger auto scroll.
67
67
  * @param [args.allowFreezingRows = false] - When true, the UI provides a drag-able cutter to freeze rows.
68
68
  * @param [args.allowFreezingColumns = false] - When true, the UI provides a drag-able cutter to freeze columns.
69
+ * @param [args.allowShrinkingSelection = false] - When true, this allows users to shrink the selection by dragging and dropping the handle inwards, similar to Excel. (Not supported yet.)
70
+ * @param [args.clearCellsWhenShrinkingSelection = false] - When true, this allows the clearing of the previously selected cells after the handle is moved inwards. (Not supported yet.)
69
71
  * @param [args.filterFrozenRows = true] - When false, rows on and above {@link canvasDatagrid#property:frozenRow}` will be ignored by filters when {@link canvasDatagrid#param:allowFreezingRows} is true.
70
72
  * @param [args.sortFrozenRows = true] - When false, rows on and above {@link canvasDatagrid#property:frozenRow}` will be ignored by sorters when {@link canvasDatagrid#param:allowSorting} is true.
71
73
  * @param [args.allowColumnReordering = true] - When true columns can be reordered.
@@ -128,7 +130,7 @@
128
130
  * @param [args.copyText = Copy] - The text that appears on the context menu when copy is available.
129
131
  * @param [args.columnHeaderClickBehavior = sort] - Can be any of sort, select, none. When sort is selected, left clicking a column header will result in sorting ascending, then sorting descending if already sorted by this column. If select is selected then clicking a column header will result in the column becoming selected. Holding control/command or shift will select multiple columns in this mode.
130
132
  * @param [args.scrollPointerLock = false] - When true, clicking on the scroll box to scroll will cause the mouse cursor to disappear to prevent it from exiting the area observable to the grid.
131
- * @param [args.selectionHandleBehavior = 'none'] - When set to a value other than none a handle will appear in the lower right corner of the desktop version of the grid. It does nothing but will be used in a future version of the grid.
133
+ * @param [args.selectionHandleBehavior = 'none'] - When set to a value other than none, a handle will appear in the lower right corner of the desktop version of the grid.
132
134
  * @param [args.columnSelectorVisibleText = '  &nbsp '] - When a column is hidden, this is the value to the left of the title in the column selector content menu.
133
135
  * @param [args.columnSelectorHiddenText = '\u2713'] - When a column is visible, this is the value to the left of the title in the column selector content menu.
134
136
  * @param [args.columnSelectorText = 'Add/remove columns'] - The text of the column selector context menu.
@@ -143,6 +145,7 @@
143
145
  * @param [args.touchZoomMin = 0.5] - The minimum zoom scale.
144
146
  * @param [args.touchZoomMax = 1.75] - The maximum zoom scale.
145
147
  * @param [args.maxPixelRatio = 1.5] - The maximum pixel ratio for high DPI displays. High DPI displays can cause sluggish performance, this caps resolution the grid is rendered at. Standard resolution (e.g.: 1920x1080) have a pixel ratio of 1:1 while higher resolution displays can be higher (e.g.: Retina display 2:1). Higher numbers are sharper (higher resolution) up to the max of your display (usually 2), lower numbers are lower resolution, down to 1. It might be fun to set a value lower than 1, I've never done it.
148
+ * @param [args.fillCellCallback] - The callback function that is called when a cell is filled.
146
149
  * @param [args.style = {}] - Sets selected values in style.
147
150
  * @param [args.filters = {}] - Sets selected values in filters. See {@link canvasDatagrid.filters}.
148
151
  * @param [args.sorters = {}] - Sets selected values in sorters. See {@link canvasDatagrid.sorters}.
@@ -169,6 +172,8 @@ declare class canvasDatagrid {
169
172
  autoScrollMargin?: number;
170
173
  allowFreezingRows?: boolean;
171
174
  allowFreezingColumns?: boolean;
175
+ allowShrinkingSelection?: boolean;
176
+ clearCellsWhenShrinkingSelection?: boolean;
172
177
  filterFrozenRows?: boolean;
173
178
  sortFrozenRows?: boolean;
174
179
  allowColumnReordering?: boolean;
@@ -246,6 +251,7 @@ declare class canvasDatagrid {
246
251
  touchZoomMin?: number;
247
252
  touchZoomMax?: number;
248
253
  maxPixelRatio?: number;
254
+ fillCellCallback?: any;
249
255
  style?: canvasDatagrid.style;
250
256
  filters?: canvasDatagrid.filter;
251
257
  sorters?: canvasDatagrid.sorter;
@@ -463,16 +469,16 @@ declare class canvasDatagrid {
463
469
  * @param dontDraw - Suppress the draw method after the selection change.
464
470
  */
465
471
  static selectAll(dontDraw: boolean): void;
466
- /**
467
- * Returns true if indices of columns next to the selected columnIndex is selected on every row.
468
- * @param columnIndex - The column index to check.
469
- */
470
- static isMultiColumnsSelected(columnIndex: number): void;
471
472
  /**
472
473
  * Returns true if the selected columnIndex is selected on every row.
473
474
  * @param columnIndex - The column index to check.
474
475
  */
475
476
  static isColumnSelected(columnIndex: number): void;
477
+ /**
478
+ * Returns true if the selected rowIndex is selected on every column.
479
+ * @param rowIndex - The row index to check.
480
+ */
481
+ static isRowSelected(rowIndex: number): void;
476
482
  /**
477
483
  * Runs the defined method on each selected cell.
478
484
  * @param fn - The function to execute. The signature of the function is: (data, rowIndex, columnName).
@@ -516,6 +522,30 @@ declare class canvasDatagrid {
516
522
  * @returns header with the selected name, or undefined.
517
523
  */
518
524
  static getHeaderByName(name: string): header;
525
+ /**
526
+ * Hide column/columns
527
+ * @param beginColumnOrderIndex - The begin column order index
528
+ * @param [endColumnOrderIndex] - The end column order index
529
+ */
530
+ static hideColumns(beginColumnOrderIndex: number, endColumnOrderIndex?: number): void;
531
+ /**
532
+ * Unihde column/columns
533
+ * @param beginColumnOrderIndex - The begin column order index
534
+ * @param [endColumnOrderIndex] - The end column order index
535
+ */
536
+ static unhideColumns(beginColumnOrderIndex: number, endColumnOrderIndex?: number): void;
537
+ /**
538
+ * Hide rows
539
+ * @param beginRowIndex - The begin row index
540
+ * @param endRowIndex - The end row index
541
+ */
542
+ static hideRows(beginRowIndex: number, endRowIndex: number): void;
543
+ /**
544
+ * Unhide rows
545
+ * @param beginRowIndex - The begin row index
546
+ * @param endRowIndex - The end row index
547
+ */
548
+ static unhideRows(beginRowIndex: number, endRowIndex: number): void;
519
549
  /**
520
550
  * Resizes a column to fit the longest value in the column. Call without a value to resize all columns.
521
551
  * Warning, can be slow on very large record sets (1m records ~3-5 seconds on an i7).
@@ -620,6 +650,12 @@ declare class canvasDatagrid {
620
650
  * @returns cell at the selected location.
621
651
  */
622
652
  static getVisibleCellByIndex(x: number, y: number): cell;
653
+ /**
654
+ * Get an unhide indicator at grid pixel coordinate x and y.
655
+ * @param x - Number of pixels from the left.
656
+ * @param y - Number of pixels from the top.
657
+ */
658
+ static getUnhideIndicator(x: number, y: number): void;
623
659
  /**
624
660
  * Get a column group at grid pixel coordinate x and y.
625
661
  * @param x - Number of pixels from the left.
@@ -1256,6 +1292,8 @@ declare namespace canvasDatagrid {
1256
1292
  * @property [editCellColor = black] - Style of editCellColor.
1257
1293
  * @property [editCellBackgroundColor = white] - Style of editCellBackgroundColor.
1258
1294
  * @property [editCellZIndex = 10000] - Style of editCellZIndex.
1295
+ * @property [fillOverlayBorderColor = rgba(127, 127, 127, 1)] - Style of fillOverlayBorderColor.
1296
+ * @property [fillOverlayBorderWidth = 2] - Style of fillOverlayBorderWidth.
1259
1297
  * @property [gridBackgroundColor = rgba(240, 240, 240, 1)] - Style of gridBackgroundColor.
1260
1298
  * @property [gridBorderColor = rgba(202, 202, 202, 1)] - Style of gridBorderColor.
1261
1299
  * @property [gridBorderWidth = 1] - Style of gridBorderWidth.
@@ -1774,6 +1812,14 @@ declare namespace canvasDatagrid {
1774
1812
  * Style of editCellZIndex.
1775
1813
  */
1776
1814
  editCellZIndex?: number;
1815
+ /**
1816
+ * Style of fillOverlayBorderColor.
1817
+ */
1818
+ fillOverlayBorderColor?: string;
1819
+ /**
1820
+ * Style of fillOverlayBorderWidth.
1821
+ */
1822
+ fillOverlayBorderWidth?: number;
1777
1823
  /**
1778
1824
  * Style of gridBackgroundColor.
1779
1825
  */
@@ -2186,3 +2232,10 @@ declare namespace canvasDatagrid {
2186
2232
  }
2187
2233
  }
2188
2234
 
2235
+ /**
2236
+ * Merge a new hidden row range into existed ranges array
2237
+ * @param hiddenRowRanges - tuples: Array<[bgeinRowIndex, endRowIndex]>
2238
+ * @param newRange - tuple: [beginRowIndex, endRowIndex]
2239
+ */
2240
+ declare function mergeHiddenRowRanges(hiddenRowRanges: any[], newRange: number[]): boolean;
2241
+
@@ -538,8 +538,114 @@ export default function (self) {
538
538
  });
539
539
  }
540
540
  }
541
+
542
+ /**
543
+ * Return a tuple if the user selected contiguous columns, otherwise `null`.
544
+ * Info: Because the user may reorder the columns,
545
+ * the schemaIndex of the first item may be greater than the schemaIndex of the second item,
546
+ * but the columnIndex of the firs item must less than the columnIndex of the second item.
547
+ * @param {any[]} schema from `self.getSchema()`
548
+ * @returns {any[]} column schemas tuple (each schema has an additional field `schemaIndex`)
549
+ */
550
+ function getSelectedContiguousColumns(ev, schema) {
551
+ const memoKey = '__contiguousColumns';
552
+ if (Array.isArray(ev[memoKey]) || ev[memoKey] === null) return ev[memoKey];
553
+ ev[memoKey] = null;
554
+
555
+ if (!Array.isArray(self.selections) || self.selections.length === 0) return;
556
+ const selection = self.selections[0];
557
+ if (!selection || selection.length === 0) return;
558
+ for (let rowIndex = 0; rowIndex < self.viewData.length; rowIndex++) {
559
+ const row = self.viewData[rowIndex];
560
+ if (!row) continue;
561
+ const compare = self.selections[rowIndex];
562
+ if (!compare) return;
563
+ if (compare.length !== selection.length) return;
564
+ for (let i = 0; i < selection.length; i++)
565
+ if (selection[i] !== compare[i]) return;
566
+ }
567
+ selection.sort((a, b) => a - b);
568
+
569
+ /** @type {number[][]} */
570
+ const ranges = [];
571
+ let begin = selection[0];
572
+ let end = selection[0];
573
+ for (let i = 1; i < selection.length; i++) {
574
+ const orderIndex = selection[i];
575
+ if (orderIndex === end + 1) {
576
+ end = orderIndex;
577
+ continue;
578
+ }
579
+ ranges.push([begin, end]);
580
+ begin = orderIndex;
581
+ end = orderIndex;
582
+ }
583
+ ranges.push([begin, end]);
584
+
585
+ const currentOrderIndex = ev.cell.columnIndex;
586
+ const matchedRange = ranges.find(
587
+ (range) =>
588
+ currentOrderIndex >= range[0] &&
589
+ currentOrderIndex <= range[1] &&
590
+ range[0] !== range[1],
591
+ );
592
+ if (!matchedRange) return;
593
+
594
+ /** @type {number[]} orders[index] => columnIndex */
595
+ const orders = self.orders.columns;
596
+ if (!Array.isArray(orders)) return;
597
+
598
+ const matchedSchema = matchedRange.map((orderIndex) => {
599
+ const schemaIndex = orders[orderIndex];
600
+ const thisSchema = schema[schemaIndex];
601
+ return Object.assign({}, thisSchema, { orderIndex });
602
+ });
603
+ if (matchedSchema.findIndex((it) => !it) >= 0) return;
604
+ return (ev[memoKey] = matchedSchema);
605
+ }
606
+ /**
607
+ * @param {boolean} [allowOnlyOneRow]
608
+ * @returns {number[]} a rowIndex tuple. It can contains one row index or two row indexes.
609
+ */
610
+ function getSelectedContiguousRows(allowOnlyOneRow) {
611
+ let range = [];
612
+ let prev = -2;
613
+ let ok = true;
614
+ self.selections.forEach(function (row, index) {
615
+ if (!ok) return;
616
+ if (prev < -1) {
617
+ prev = index;
618
+ range[0] = index;
619
+ return;
620
+ }
621
+ if (index !== prev + 1 || !row || row.length === 0) {
622
+ ok = false;
623
+ return;
624
+ }
625
+ prev = index;
626
+ range[1] = index;
627
+ });
628
+ if (ok) {
629
+ if (range.length === 1) return allowOnlyOneRow ? range : null;
630
+ return range;
631
+ }
632
+ }
541
633
  function addDefaultContextMenuItem(e) {
542
- var isNormalCell =
634
+ const schema = self.getSchema();
635
+ /**
636
+ * A map between columnIndex and column data
637
+ * @type {Map<string,any>}
638
+ */
639
+ let columns;
640
+ const getColumnsMap = () => {
641
+ if (!columns)
642
+ columns = new Map(schema.map((_col) => [_col.columnIndex, _col]));
643
+ return columns;
644
+ };
645
+ const isSorting =
646
+ self.orderings.columns && self.orderings.columns.length > 0;
647
+
648
+ const isNormalCell =
543
649
  !(
544
650
  e.cell.isBackground ||
545
651
  e.cell.isColumnHeaderCellCap ||
@@ -614,20 +720,30 @@ export default function (self) {
614
720
  const columnOrderIndex = e.cell.columnIndex;
615
721
  const columnIndex = self.orders.columns[columnOrderIndex];
616
722
 
723
+ const contiguousColumns = getSelectedContiguousColumns(e, schema);
724
+ let title = '';
725
+ if (contiguousColumns) {
726
+ title = contiguousColumns
727
+ .map((col) => col.title || col.name)
728
+ .join('-');
729
+ } else {
730
+ const column = schema[columnIndex];
731
+ if (column) title = column.title || column.name;
732
+ }
617
733
  e.items.push({
618
- title: self.attributes.hideColumnText.replace(
619
- /%s/gi,
620
- e.cell.header.title || e.cell.header.name,
621
- ),
734
+ title: self.attributes.hideColumnText.replace(/%s/gi, title),
622
735
  click: function (ev) {
623
- self.getSchema()[columnIndex].hidden = true;
624
736
  ev.preventDefault();
625
737
  self.stopPropagation(ev);
626
738
  self.disposeContextMenu();
627
- self.setStorageData();
628
- setTimeout(function () {
629
- self.resize(true);
630
- }, 10);
739
+ if (contiguousColumns) {
740
+ self.hideColumns(
741
+ contiguousColumns[0].orderIndex,
742
+ contiguousColumns[1].orderIndex,
743
+ );
744
+ } else {
745
+ self.hideColumns(columnOrderIndex);
746
+ }
631
747
  },
632
748
  });
633
749
  }
@@ -689,6 +805,51 @@ export default function (self) {
689
805
  },
690
806
  });
691
807
  }
808
+
809
+ //#region hide rows
810
+ const canHideRows = !isSorting && e.cell.isRowHeader && e.cell.header;
811
+ if (canHideRows) {
812
+ const range = getSelectedContiguousRows(true);
813
+ if (range) {
814
+ const boundRowIndexes = range.map((viewRowIndex) =>
815
+ self.getBoundRowIndexFromViewRowIndex(viewRowIndex),
816
+ );
817
+ let title;
818
+ if (boundRowIndexes.length === 1) {
819
+ if (typeof boundRowIndexes[0] === 'number')
820
+ title = boundRowIndexes[0] + 1;
821
+ else title = range[0] + 1;
822
+
823
+ title = self.attributes.showHideRow.replace('%s', title);
824
+ // hide one row
825
+ e.items.push({
826
+ title,
827
+ click: function (ev) {
828
+ ev.preventDefault();
829
+ self.hideRows(boundRowIndexes[0], boundRowIndexes[0]);
830
+ },
831
+ });
832
+ } else if (boundRowIndexes[0] <= boundRowIndexes[1]) {
833
+ title = boundRowIndexes
834
+ .map((it, index) => {
835
+ if (typeof it === 'number') return it + 1;
836
+ return range[index] + 1;
837
+ })
838
+ .join('-');
839
+ title = self.attributes.showHideRows.replace('%s', title);
840
+ // hide rows
841
+ e.items.push({
842
+ title,
843
+ click: function (ev) {
844
+ ev.preventDefault();
845
+ self.hideRows(boundRowIndexes[0], boundRowIndexes[1]);
846
+ },
847
+ });
848
+ }
849
+ }
850
+ }
851
+ //#endregion hide rows
852
+
692
853
  //#region group/ungroup columns
693
854
  const groupAreaHeight = self.getColumnGroupAreaHeight();
694
855
  const groupAreaWidth = self.getRowGroupAreaWidth();
@@ -760,28 +921,13 @@ export default function (self) {
760
921
  const canUngroupColumns =
761
922
  self.attributes.allowGroupingColumns && e.cell.isColumnHeader;
762
923
  const canGroupByRows =
763
- self.attributes.allowGroupingRows && e.cell.isRowHeader && e.cell.header;
924
+ !isSorting &&
925
+ self.attributes.allowGroupingRows &&
926
+ e.cell.isRowHeader &&
927
+ e.cell.header;
764
928
  const canUngroupRows =
765
929
  self.attributes.allowGroupingRows && e.cell.isRowHeader;
766
930
 
767
- /**
768
- * The value for storing the return value from `self.getSchema()`
769
- * @type {any[]}
770
- */
771
- let schema;
772
- /**
773
- * A map between columnIndex and column data
774
- * @type {Map<string,any>}
775
- */
776
- let columns;
777
- const getColumnsMap = () => {
778
- if (!columns) {
779
- if (!schema) schema = self.getSchema();
780
- columns = new Map(schema.map((_col) => [_col.columnIndex, _col]));
781
- }
782
- return columns;
783
- };
784
-
785
931
  if (canGroupByColumns) {
786
932
  /** @type {number[]} */
787
933
  const groupIndexes = [];
@@ -863,23 +1009,7 @@ export default function (self) {
863
1009
  }
864
1010
  }
865
1011
  if (canGroupByRows) {
866
- let range = [];
867
- let prev = -2;
868
- let ok = true;
869
- self.selections.forEach(function (row, index) {
870
- if (!ok) return;
871
- if (prev < -1) {
872
- prev = index;
873
- range[0] = index;
874
- return;
875
- }
876
- if (index !== prev + 1 || !row || row.length === 0) {
877
- ok = false;
878
- return;
879
- }
880
- prev = index;
881
- range[1] = index;
882
- });
1012
+ const range = getSelectedContiguousRows(false) || [];
883
1013
  const rangeTitle = range
884
1014
  .map((rowIndex) => {
885
1015
  const index = self.getBoundRowIndexFromViewRowIndex(rowIndex);
@@ -888,7 +1018,6 @@ export default function (self) {
888
1018
  })
889
1019
  .join('-');
890
1020
  if (
891
- ok &&
892
1021
  range.length === 2 &&
893
1022
  self.isNewGroupRangeValid(self.groupedRows, range[0], range[1])
894
1023
  ) {
@@ -999,7 +1128,7 @@ export default function (self) {
999
1128
  function createDisposeEvent() {
1000
1129
  requestAnimationFrame(function () {
1001
1130
  document.addEventListener('click', self.disposeContextMenu);
1002
- document.removeEventListener('mouseup', createDisposeEvent);
1131
+ window.removeEventListener('mouseup', createDisposeEvent);
1003
1132
  });
1004
1133
  }
1005
1134
  var contextPosition,
@@ -1047,7 +1176,7 @@ export default function (self) {
1047
1176
  }
1048
1177
  self.contextMenu = createContextMenu(ev, contextPosition, items);
1049
1178
  if (e.type == 'mousedown') {
1050
- document.addEventListener('mouseup', createDisposeEvent);
1179
+ window.addEventListener('mouseup', createDisposeEvent);
1051
1180
  } else {
1052
1181
  createDisposeEvent();
1053
1182
  }
package/lib/defaults.js CHANGED
@@ -25,9 +25,11 @@ export default function (self) {
25
25
  ['autoResizeRows', false],
26
26
  ['autoScrollOnMousemove', false],
27
27
  ['autoScrollMargin', 5],
28
+ ['allowShrinkingSelection', false],
28
29
  ['blanksText', '(Blanks)'],
29
30
  ['borderDragBehavior', 'none'],
30
31
  ['borderResizeZone', 10],
32
+ ['clearCellsWhenShrinkingSelection', false],
31
33
  ['clearSettingsOptionText', 'Clear saved settings'],
32
34
  ['columnHeaderClickBehavior', 'sort'],
33
35
  ['columnSelectorHiddenText', '&nbsp;&nbsp;&nbsp;'],
@@ -45,6 +47,10 @@ export default function (self) {
45
47
  ['filterFrozenRows', true],
46
48
  ['globalRowResize', false],
47
49
  ['hideColumnText', 'Hide %s'],
50
+ ['showUnhideColumnsIndicator', false],
51
+ ['showUnhideRowsIndicator', false],
52
+ ['showHideRow', 'Hide row %s'],
53
+ ['showHideRows', 'Hide rows %s'],
48
54
  ['hoverMode', 'cell'],
49
55
  ['keepFocusOnMouseOut', false],
50
56
  ['maxAutoCompleteItems', 200],
@@ -291,14 +297,16 @@ export default function (self) {
291
297
  ['filterButtonHoverBackgroundColor', 'rgba(235, 235, 235, 1)'],
292
298
  ['filterButtonMenuOffsetTop', 10],
293
299
  ['filterButtonWidth', 20],
294
- ['frozenMarkerHoverColor', 'rgba(236, 243, 255, 1)'],
295
- ['frozenMarkerHoverBorderColor', 'rgba(110, 168, 255, 1)'],
296
- ['frozenMarkerActiveColor', 'rgba(236, 243, 255, 1)'],
297
- ['frozenMarkerActiveBorderColor', 'rgba(110, 168, 255, 1)'],
298
- ['frozenMarkerColor', 'rgba(222, 222, 222, 1)'],
299
- ['frozenMarkerBorderColor', 'rgba(168, 168, 168, 1)'],
300
+ ['frozenMarkerHoverColor', 'rgba(165, 198, 254, 1)'],
301
+ ['frozenMarkerHoverBorderColor', 'rgba(165, 198, 254, 1)'],
302
+ ['frozenMarkerActiveColor', 'rgba(165, 198, 254, 0.2)'],
303
+ ['frozenMarkerActiveBorderColor', 'rgba(165, 198, 254, 0.5)'],
304
+ ['frozenMarkerActiveHeaderColor', 'rgba(165, 198, 254, 1)'],
305
+ ['frozenMarkerColor', 'rgba(221, 221, 221, 1)'],
306
+ ['frozenMarkerBorderColor', 'rgba(221, 221, 221, 1)'],
300
307
  ['frozenMarkerBorderWidth', 1],
301
- ['frozenMarkerWidth', 2],
308
+ ['frozenMarkerHeaderColor', 'rgba(188, 188, 188, 1)'],
309
+ ['frozenMarkerWidth', 4],
302
310
  ['groupingAreaBackgroundColor', 'rgba(240, 240, 240, 1)'],
303
311
  ['gridBackgroundColor', 'rgba(240, 240, 240, 1)'],
304
312
  ['gridBorderCollapse', 'collapse'],
@@ -365,6 +373,8 @@ export default function (self) {
365
373
  ['selectionHandleColor', 'rgba(66, 133, 244, 1)'],
366
374
  ['selectionHandleSize', 8],
367
375
  ['selectionHandleType', 'square'],
376
+ ['fillOverlayBorderColor', 'rgba(127, 127, 127, 1)'],
377
+ ['fillOverlayBorderWidth', 2],
368
378
  ['selectionOverlayBorderColor', 'rgba(66, 133, 244, 1)'],
369
379
  ['selectionOverlayBorderWidth', 1],
370
380
  ['treeArrowBorderColor', 'rgba(195, 199, 202, 1)'],
@@ -377,6 +387,10 @@ export default function (self) {
377
387
  ['treeArrowMarginTop', 6],
378
388
  ['treeArrowWidth', 13],
379
389
  ['treeGridHeight', 250],
390
+ ['unhideIndicatorColor', 'rgba(0, 0, 0, 1)'],
391
+ ['unhideIndicatorBackgroundColor', 'rgba(255, 255, 255, 1)'],
392
+ ['unhideIndicatorBorderColor', 'rgba(174, 193, 232, 1)'],
393
+ ['unhideIndicatorSize', 16],
380
394
  ['width', 'auto'],
381
395
  ],
382
396
  };
package/lib/docs.js CHANGED
@@ -29,6 +29,8 @@
29
29
  * @param {number} [args.autoScrollMargin=5] - Number of pixels of mouse movement to trigger auto scroll.
30
30
  * @param {boolean} [args.allowFreezingRows=false] - When true, the UI provides a drag-able cutter to freeze rows.
31
31
  * @param {boolean} [args.allowFreezingColumns=false] - When true, the UI provides a drag-able cutter to freeze columns.
32
+ * @param {boolean} [args.allowShrinkingSelection=false] - When true, this allows users to shrink the selection by dragging and dropping the handle inwards, similar to Excel. (Not supported yet.)
33
+ * @param {boolean} [args.clearCellsWhenShrinkingSelection=false] - When true, this allows the clearing of the previously selected cells after the handle is moved inwards. (Not supported yet.)
32
34
  * @param {boolean} [args.filterFrozenRows=true] - When false, rows on and above {@link canvasDatagrid#property:frozenRow}` will be ignored by filters when {@link canvasDatagrid#param:allowFreezingRows} is true.
33
35
  * @param {boolean} [args.sortFrozenRows=true] - When false, rows on and above {@link canvasDatagrid#property:frozenRow}` will be ignored by sorters when {@link canvasDatagrid#param:allowSorting} is true.
34
36
  * @param {boolean} [args.allowColumnReordering=true] - When true columns can be reordered.
@@ -91,7 +93,7 @@
91
93
  * @param {string} [args.copyText=Copy] - The text that appears on the context menu when copy is available.
92
94
  * @param {string} [args.columnHeaderClickBehavior=sort] - Can be any of sort, select, none. When sort is selected, left clicking a column header will result in sorting ascending, then sorting descending if already sorted by this column. If select is selected then clicking a column header will result in the column becoming selected. Holding control/command or shift will select multiple columns in this mode.
93
95
  * @param {boolean} [args.scrollPointerLock=false] - When true, clicking on the scroll box to scroll will cause the mouse cursor to disappear to prevent it from exiting the area observable to the grid.
94
- * @param {string} [args.selectionHandleBehavior='none'] - When set to a value other than none a handle will appear in the lower right corner of the desktop version of the grid. It does nothing but will be used in a future version of the grid.
96
+ * @param {string} [args.selectionHandleBehavior='none'] - When set to a value other than none, a handle will appear in the lower right corner of the desktop version of the grid.
95
97
  * @param {string} [args.columnSelectorVisibleText='&nbsp;&nbsp;&nbsp&nbsp;'] - When a column is hidden, this is the value to the left of the title in the column selector content menu.
96
98
  * @param {string} [args.columnSelectorHiddenText='\u2713'] - When a column is visible, this is the value to the left of the title in the column selector content menu.
97
99
  * @param {string} [args.columnSelectorText='Add/remove columns'] - The text of the column selector context menu.
@@ -106,6 +108,7 @@
106
108
  * @param {number} [args.touchZoomMin=0.5] - The minimum zoom scale.
107
109
  * @param {number} [args.touchZoomMax=1.75] - The maximum zoom scale.
108
110
  * @param {number} [args.maxPixelRatio=1.5] - The maximum pixel ratio for high DPI displays. High DPI displays can cause sluggish performance, this caps resolution the grid is rendered at. Standard resolution (e.g.: 1920x1080) have a pixel ratio of 1:1 while higher resolution displays can be higher (e.g.: Retina display 2:1). Higher numbers are sharper (higher resolution) up to the max of your display (usually 2), lower numbers are lower resolution, down to 1. It might be fun to set a value lower than 1, I've never done it.
111
+ * @param {object} [args.fillCellCallback] - The callback function that is called when a cell is filled.
109
112
  * @param {canvasDatagrid.style} [args.style={}] - Sets selected values in style.
110
113
  * @param {canvasDatagrid.filter} [args.filters={}] - Sets selected values in filters. See {@link canvasDatagrid.filters}.
111
114
  * @param {canvasDatagrid.sorter} [args.sorters={}] - Sets selected values in sorters. See {@link canvasDatagrid.sorters}.
@@ -256,6 +259,32 @@
256
259
  * @property {object} text.width - The width of the text, including truncation and ellipsis.
257
260
  * @property {object} text.value - The value of the text, including truncation and ellipsis.
258
261
  */
262
+ /**
263
+ * The additional function to invoke when a cell is filled. The return value of this
264
+ * function sets the new data of the cell.
265
+ * @function
266
+ * @name canvasDataGrid.fillCellCallback
267
+ * @param {object} args - Arguments that are passed to the function.
268
+ * @param {array} args.rows - Data that is being filled into all the cells, including this one.
269
+ * @param {string} args.direction - Direction of the fill operation, which can be 'horizontal' for x axis, 'vertical' for y axis, or 'both' when it goes both ways, e.g., when pasting unevenly.
270
+ * @param {object} args.newRowData - New row data that is going to replace 'existingRowData'. The result of this function will be kept in this object.
271
+ * @param {object} args.existingRowData - Existing data of the row. This will be replaced with 'newRowData'.
272
+ * @param {number} args.rowIndex - Index of the row on the grid.
273
+ * @param {number} args.rowOffset - Position/offset of 'cells' in 'rows'. Starts with '0'.
274
+ * @param {array} args.cells - New data for all the cells, including this one, for the current row. This is the same as accessing 'rows' using 'rowOffset'.
275
+ * @param {boolean} args.reversed - Whether the fill operation is applied in the reverse order, meaning if horizontal, we are going from right to left, and if vertical, we are going from bottom to top.
276
+ * @param {boolean} args.isFillingRow - Whether the current row is being filled. If the 'direction' is 'vertical', this will always be true, or sometimes true if the 'direction' is 'both'.
277
+ * @param {number} args.fillingRowPosition - Increase in position since the first filling of the rows. This will be '-1' if 'isFillingRow' is false. Starts with '0'.
278
+ * @param {number} args.fillingRowLength - Total length that 'fillingRowPosition' will go. This will be '-1' if 'isFillingRow' is false.
279
+ * @param {object} args.column - Column that this cell is on.
280
+ * @param {number} args.columnIndex - The index of the column on the grid.
281
+ * @param {string} args.newCellData - Data from 'cells' to be set for this cell. You can modify this and return the result to set the new data for this cell.
282
+ * @param {string} args.existingCellData - Existing data on this cell that is about to be replaced with the data you will return.
283
+ * @param {number} args.columnOffset - Position/offset of the 'newCellData' in 'cells'. Starts with '0'.
284
+ * @param {boolean} args.isFillingColumn - Whether the current column is being filled. If the 'direction' is 'horizontal', this will always be true, or sometimes true if the 'direction' is 'both'.
285
+ * @param {number} args.fillingColumnPosition - Increase in position since the first filling of the columns. This will be '-1' if 'isFillingColumn' is false. Starts with '0'.
286
+ * @param {number} args.fillingColumnLength - Total length that 'fillingColumnPosition' will go. This will be '-1' if 'isFillingColumn' is false.
287
+ */
259
288
  /**
260
289
  * Styles for the canvas data grid. Standard CSS styles still apply but are not listed here.
261
290
  * @class
@@ -364,6 +393,8 @@
364
393
  * @property {string} [editCellColor=black] - Style of editCellColor.
365
394
  * @property {string} [editCellBackgroundColor=white] - Style of editCellBackgroundColor.
366
395
  * @property {number} [editCellZIndex=10000] - Style of editCellZIndex.
396
+ * @property {string} [fillOverlayBorderColor=rgba(127, 127, 127, 1)] - Style of fillOverlayBorderColor.
397
+ * @property {number} [fillOverlayBorderWidth=2] - Style of fillOverlayBorderWidth.
367
398
  * @property {string} [gridBackgroundColor=rgba(240, 240, 240, 1)] - Style of gridBackgroundColor.
368
399
  * @property {string} [gridBorderColor=rgba(202, 202, 202, 1)] - Style of gridBorderColor.
369
400
  * @property {number} [gridBorderWidth=1] - Style of gridBorderWidth.
@@ -973,6 +1004,22 @@
973
1004
  * @param {object} e.ctx Canvas context.
974
1005
  * @param {canvasDatagrid.cell} e.cell The cell being moved out of.
975
1006
  */
1007
+ /**
1008
+ * Fires column(s) are being hidden
1009
+ * @event
1010
+ * @name canvasDatagrid#columnhide
1011
+ * @param {object} e Event object.
1012
+ * @param {object} e.ctx Canvas context.
1013
+ * @param {columnIndex} e.columnIndex Index of column being hidden.
1014
+ */
1015
+ /**
1016
+ * Fires column(s) are being unhidden
1017
+ * @event
1018
+ * @name canvasDatagrid#columnunhide
1019
+ * @param {object} e Event object.
1020
+ * @param {object} e.ctx Canvas context.
1021
+ * @param {columnIndex} e.columnIndex Index of column being unhidden.
1022
+ */
976
1023
  /**
977
1024
  * Fires when the mouse enters a row.
978
1025
  * @event
package/lib/dom.js CHANGED
@@ -370,6 +370,19 @@ export default function (self) {
370
370
  var shouldClearCellValue = cellValueIsEmpty || inEnterMode;
371
371
 
372
372
  self.input.value = shouldClearCellValue ? '' : cell.value;
373
+ let width = Math.round(
374
+ self.input.value.length *
375
+ parseInt(self.style.editCellFontSize, 10) *
376
+ 0.7 *
377
+ self.scale,
378
+ );
379
+ if (width + self.style.cellPaddingLeft < cell.width) {
380
+ width = cell.width - self.style.cellPaddingLeft;
381
+ } else if (width > self.width - cell.x - self.style.scrollBarWidth) {
382
+ width = self.width - cell.x - self.style.scrollBarWidth;
383
+ self.input.style.height = 'auto';
384
+ }
385
+ self.input.style.width = width + 'px';
373
386
  self.input.focus();
374
387
  self.input.addEventListener('click', self.stopPropagation);
375
388
  self.input.addEventListener('dblclick', self.stopPropagation);
@@ -450,6 +463,20 @@ export default function (self) {
450
463
  }
451
464
  self.scrollIntoView(nx, ny);
452
465
  self.beginEditAt(nx, ny, e);
466
+ } else {
467
+ let width = Math.round(
468
+ self.input.value.length *
469
+ parseInt(self.style.editCellFontSize, 10) *
470
+ 0.7 *
471
+ self.scale,
472
+ );
473
+ if (width + self.style.cellPaddingLeft < cell.width) {
474
+ width = cell.width - self.style.cellPaddingLeft;
475
+ } else if (width > self.width - cell.x - self.style.scrollBarWidth) {
476
+ width = self.width - cell.x - self.style.scrollBarWidth;
477
+ self.input.style.height = 'auto';
478
+ }
479
+ self.input.style.width = width + 'px';
453
480
  }
454
481
  });
455
482
 
@@ -773,11 +800,11 @@ export default function (self) {
773
800
  });
774
801
  self.eventParent.addEventListener('scroll', self.resize, false);
775
802
  self.eventParent.addEventListener('touchstart', self.touchstart, false);
776
- self.eventParent.addEventListener('mouseup', self.mouseup, false);
777
803
  self.eventParent.addEventListener('mousedown', self.mousedown, false);
778
804
  self.eventParent.addEventListener('dblclick', self.dblclick, false);
779
805
  self.eventParent.addEventListener('click', self.click, false);
780
- document.body.addEventListener('mousemove', self.mousemove);
806
+ window.addEventListener('mouseup', self.mouseup, false);
807
+ window.addEventListener('mousemove', self.mousemove);
781
808
  self[self.isChildGrid ? 'parentGrid' : 'eventParent'].addEventListener(
782
809
  'wheel',
783
810
  self.scrollWheel,