canvas-datagrid 0.26.0 → 0.27.1

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
@@ -20,7 +20,7 @@
20
20
  * @property sorters - Object that contains a list of sorting functions for sorting columns. See {@tutorial sorters}.
21
21
  * @property filters - Object that contains a list of filters for filtering data. The properties in this object match the `schema[].type` property. For example, if the schema for a given column was of the type `date` the grid would look for a filter called `filters.date` if a filter cannot be found for a given data type a warning will be logged and the string/RegExp filter will be used. See {@link canvasDatagrid.filters}.
22
22
  * @property hasActiveFilters - When true, grid data is being filtered.
23
- * @property data - This is how data is set in the grid. Data must be an array of objects that conform to a schema. Data values can be any primitive type. However if a cell value is another data array, an inner grid will be rendered into the cell. This "cell grid" is different than a "tree grid" (the sort you drill in with a row header arrow) and uses the `cellGridAttributes` attribute for properties and styling. See {@link canvasDatagrid.data}.
23
+ * @property data - This is how data is set in the grid. Data must be an array of objects that conform to a schema. Data values can be any primitive type. A column whose schema `type` is `canvas-datagrid` renders an inner grid into each of its cells, with the cell's value, itself an array of rows, as that grid's data. An array value on its own does not create an inner grid, the column type has to be set in the schema, otherwise the array is formatted as a string. This "cell grid" is different than a "tree grid" (the sort you drill in with a row header arrow) and uses the `cellGridAttributes` attribute for properties and styling. See {@link tutorial--Create-a-cell-grid}.
24
24
  * @property schema - Schema is optional. Schema is an array of {canvasDatagrid.header} objects. If no schema is provided one will be generated from the data, in that case all data will be assumed to be string data. See {@link canvasDatagrid.schema}.
25
25
  * @property scrollHeight - The total number of pixels that can be scrolled down.
26
26
  * @property scrollWidth - The total number of pixels that can be scrolled to the left.
@@ -52,7 +52,7 @@
52
52
  * @param [args.name] - Optional value that will allow the saving of column height, row width, etc. to the browser's local store. This name should be unique to this grid.
53
53
  * @param [args.tree = false] - When true, an arrow will be drawn on each row that when clicked raises the See {@link canvasDatagrid#event:expandtree} event for that row and creates an inner grid. See {@link tutorial--Allow-users-to-open-trees}.
54
54
  * @param [args.treeHorizontalScroll = false] - Reserved. Intended to make expanded child grids scroll horizontally with the parent columns; the option is accepted but not implemented yet (see issue #314), child grids always stay stationary.
55
- * @param [args.cellGridAttributes] - Attributes used for cell grids. These child grids are different than the tree grids. See the {@link canvasDatagrid.data} property for more information about cell grids.
55
+ * @param [args.cellGridAttributes] - Attributes used for cell grids, the inner grids drawn in the cells of a column whose schema `type` is `canvas-datagrid`. These child grids are different than the tree grids. See the {@link canvasDatagrid.data} property for more information about cell grids and {@link tutorial--Create-a-cell-grid}.
56
56
  * @param [args.treeGridAttributes] - Attributes used for tree grids. These child grids are different than the cell grids. See the {@link canvasDatagrid.data} property for more information about tree grids.
57
57
  * @param [args.showNewRow = true] - When true, a row will appear at the bottom of the data set. schema[].defaultValue will define a default value for each cell. defaultValue can be a string or a function. When a function is used, the arguments header and index will be passed to the function. The value returned by the function will be the value in the new cell. See {@link canvasDatagrid.header.defaultValue}
58
58
  * @param [args.saveAppearance = true] - When true, and the attribute name is set, column and row sizes will be saved to the browser's localStore.
@@ -149,7 +149,7 @@
149
149
  * @param [args.touchZoomMin = 0.5] - The minimum zoom scale.
150
150
  * @param [args.touchZoomMax = 1.75] - The maximum zoom scale.
151
151
  * @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.
152
- * @param [args.maxCanvasSize = 16384] - Largest width or height, in CSS pixels, an auto-sized grid (`style.width`/`style.height` set to `auto`) may grow to. Browsers cannot paint larger canvases. Past this size the grid stops growing and shows a scroll bar for the rest of the data.
152
+ * @param [args.maxCanvasSize = 16384] - Largest width or height, in CSS pixels, an auto-sized grid (`style.width`/`style.height` left at `auto`) may grow to. Browsers cannot paint larger canvases. Past this size the grid stops growing and shows a scroll bar for the rest of the data.
153
153
  * @param [args.fillCellCallback] - The callback function that is called when a cell is filled.
154
154
  * @param [args.style = {}] - Sets selected values in style.
155
155
  * @param [args.filters = {}] - Sets selected values in filters. See {@link canvasDatagrid.filters}.
@@ -812,7 +812,7 @@ declare class canvasDatagrid {
812
812
  */
813
813
  hasActiveFilters: boolean;
814
814
  /**
815
- * This is how data is set in the grid. Data must be an array of objects that conform to a schema. Data values can be any primitive type. However if a cell value is another data array, an inner grid will be rendered into the cell. This "cell grid" is different than a "tree grid" (the sort you drill in with a row header arrow) and uses the `cellGridAttributes` attribute for properties and styling. See {@link canvasDatagrid.data}.
815
+ * This is how data is set in the grid. Data must be an array of objects that conform to a schema. Data values can be any primitive type. A column whose schema `type` is `canvas-datagrid` renders an inner grid into each of its cells, with the cell's value, itself an array of rows, as that grid's data. An array value on its own does not create an inner grid, the column type has to be set in the schema, otherwise the array is formatted as a string. This "cell grid" is different than a "tree grid" (the sort you drill in with a row header arrow) and uses the `cellGridAttributes` attribute for properties and styling. See {@link tutorial--Create-a-cell-grid}.
816
816
  */
817
817
  data: canvasDatagrid.data;
818
818
  /**
@@ -950,7 +950,7 @@ declare namespace canvasDatagrid {
950
950
  /**
951
951
  * A header that describes the data in a column. The term header and column are used interchangeably in this documentation. The {@link canvasDatagrid.schema} is an array of {@link canvasDatagrid.header}.
952
952
  * @property name - The name of the header. This must match the property name of an object in the {@link canvasDatagrid.data} array. This is the only required property of a {@link canvasDatagrid.header}. This value will appear at the top of the column unless {@link canvasDatagrid.header.title} is defined.
953
- * @property type - The data type of this header. This value should match properties in {@link canvasDatagrid.formatters}, {@link canvasDatagrid.filters}, {@link canvasDatagrid.sorters} to take full advantage of formatting, sorting and filtering when not defining these properties within this header.
953
+ * @property type - The data type of this header. This value should match properties in {@link canvasDatagrid.formatters}, {@link canvasDatagrid.filters}, {@link canvasDatagrid.sorters} to take full advantage of formatting, sorting and filtering when not defining these properties within this header. The type `canvas-datagrid` is special: each cell in the column renders an inner grid, a "cell grid", with the cell's value (an array of rows) as its data. See {@link tutorial--Create-a-cell-grid}.
954
954
  * @property title - The value that is actually displayed to the user at the top of the column. If no value is present, {@link canvasDatagrid.header.name} will be used instead.
955
955
  * @property width - The mutable width of this column in pixels. The user can override this value if {@link canvasDatagrid.attributes.allowColumnResizing} is set to `true`.
956
956
  * @property hidden - When true, the column will not be included in the visible schema. This means selection, copy, and drawing functions will not display this column or values from this column.
@@ -965,7 +965,7 @@ declare namespace canvasDatagrid {
965
965
  */
966
966
  name: string;
967
967
  /**
968
- * The data type of this header. This value should match properties in {@link canvasDatagrid.formatters}, {@link canvasDatagrid.filters}, {@link canvasDatagrid.sorters} to take full advantage of formatting, sorting and filtering when not defining these properties within this header.
968
+ * The data type of this header. This value should match properties in {@link canvasDatagrid.formatters}, {@link canvasDatagrid.filters}, {@link canvasDatagrid.sorters} to take full advantage of formatting, sorting and filtering when not defining these properties within this header. The type `canvas-datagrid` is special: each cell in the column renders an inner grid, a "cell grid", with the cell's value (an array of rows) as its data. See {@link tutorial--Create-a-cell-grid}.
969
969
  */
970
970
  type: string;
971
971
  /**
@@ -1343,7 +1343,7 @@ declare namespace canvasDatagrid {
1343
1343
  * @property [columnHeaderOrderByArrowWidth = 13] - Style of columnHeaderOrderByArrowWidth.
1344
1344
  * @property [rowHeaderCellWidth = 57] - Style of rowHeaderCellWidth.
1345
1345
  * @property [minColumnWidth = 45] - Style of minColumnWidth.
1346
- * @property [height = auto] - Style of height.
1346
+ * @property [height = auto] - Height of the grid as a CSS value (`300px`, `100%`). With the default `auto` the grid fills its parent element when the parent has a height of its own; otherwise it grows to fit its rows, but never past the viewport height, and scrolls for the rest.
1347
1347
  * @property [minHeight = 24] - Style of minHeight.
1348
1348
  * @property [minRowHeight = 24] - Style of minRowHeight.
1349
1349
  * @property [name = default] - Style of name.
@@ -1413,7 +1413,7 @@ declare namespace canvasDatagrid {
1413
1413
  * @property [frozenMarkerWidth = 1] - Style of frozenMarkerWidth.
1414
1414
  * @property [overflowY = auto] - When set to hidden, vertical scroll bar will be hidden. When set to auto vertical scroll bar will appear when data overflows the height. When set to scroll the vertical scrollbar will always be visible.
1415
1415
  * @property [overflowX = auto] - When set to hidden, horizontal scroll bar will be hidden. When set to auto horizontal scroll bar will appear when data overflows the width. When set to scroll the horizontal scrollbar will always be visible.
1416
- * @property [width = auto] - Style of width.
1416
+ * @property [width = auto] - Width of the grid as a CSS value (`800px`, `100%`). With the default `auto` the grid fills its parent element when the parent has a width of its own; otherwise it grows to fit its columns, but never past the viewport width, and scrolls for the rest.
1417
1417
  *
1418
1418
  * ['', 'normal'],
1419
1419
  */
@@ -1979,7 +1979,7 @@ declare namespace canvasDatagrid {
1979
1979
  */
1980
1980
  minColumnWidth?: number;
1981
1981
  /**
1982
- * Style of height.
1982
+ * Height of the grid as a CSS value (`300px`, `100%`). With the default `auto` the grid fills its parent element when the parent has a height of its own; otherwise it grows to fit its rows, but never past the viewport height, and scrolls for the rest.
1983
1983
  */
1984
1984
  height?: number | string;
1985
1985
  /**
@@ -2259,7 +2259,7 @@ declare namespace canvasDatagrid {
2259
2259
  */
2260
2260
  overflowX?: string;
2261
2261
  /**
2262
- * Style of width.
2262
+ * Width of the grid as a CSS value (`800px`, `100%`). With the default `auto` the grid fills its parent element when the parent has a width of its own; otherwise it grows to fit its columns, but never past the viewport width, and scrolls for the rest.
2263
2263
 
2264
2264
  ['', 'normal'],
2265
2265
  */
package/lib/docs.js CHANGED
@@ -15,7 +15,7 @@
15
15
  * @param {string} [args.name] Optional value that will allow the saving of column height, row width, etc. to the browser's local store. This name should be unique to this grid.
16
16
  * @param {boolean} [args.tree=false] - When true, an arrow will be drawn on each row that when clicked raises the See {@link canvasDatagrid#event:expandtree} event for that row and creates an inner grid. See {@link tutorial--Allow-users-to-open-trees}.
17
17
  * @param {boolean} [args.treeHorizontalScroll=false] - Reserved. Intended to make expanded child grids scroll horizontally with the parent columns; the option is accepted but not implemented yet (see issue #314), child grids always stay stationary.
18
- * @param {object} [args.cellGridAttributes] - Attributes used for cell grids. These child grids are different than the tree grids. See the {@link canvasDatagrid.data} property for more information about cell grids.
18
+ * @param {object} [args.cellGridAttributes] - Attributes used for cell grids, the inner grids drawn in the cells of a column whose schema `type` is `canvas-datagrid`. These child grids are different than the tree grids. See the {@link canvasDatagrid.data} property for more information about cell grids and {@link tutorial--Create-a-cell-grid}.
19
19
  * @param {object} [args.treeGridAttributes] - Attributes used for tree grids. These child grids are different than the cell grids. See the {@link canvasDatagrid.data} property for more information about tree grids.
20
20
  * @param {boolean} [args.showNewRow=true] - When true, a row will appear at the bottom of the data set. schema[].defaultValue will define a default value for each cell. defaultValue can be a string or a function. When a function is used, the arguments header and index will be passed to the function. The value returned by the function will be the value in the new cell. See {@link canvasDatagrid.header.defaultValue}
21
21
  * @param {boolean} [args.saveAppearance=true] - When true, and the attribute name is set, column and row sizes will be saved to the browser's localStore.
@@ -112,7 +112,7 @@
112
112
  * @param {number} [args.touchZoomMin=0.5] - The minimum zoom scale.
113
113
  * @param {number} [args.touchZoomMax=1.75] - The maximum zoom scale.
114
114
  * @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.
115
- * @param {number} [args.maxCanvasSize=16384] - Largest width or height, in CSS pixels, an auto-sized grid (`style.width`/`style.height` set to `auto`) may grow to. Browsers cannot paint larger canvases. Past this size the grid stops growing and shows a scroll bar for the rest of the data.
115
+ * @param {number} [args.maxCanvasSize=16384] - Largest width or height, in CSS pixels, an auto-sized grid (`style.width`/`style.height` left at `auto`) may grow to. Browsers cannot paint larger canvases. Past this size the grid stops growing and shows a scroll bar for the rest of the data.
116
116
  * @param {object} [args.fillCellCallback] - The callback function that is called when a cell is filled.
117
117
  * @param {canvasDatagrid.style} [args.style={}] - Sets selected values in style.
118
118
  * @param {canvasDatagrid.filter} [args.filters={}] - Sets selected values in filters. See {@link canvasDatagrid.filters}.
@@ -139,7 +139,7 @@
139
139
  * @property {canvasDatagrid.sorter} sorters - Object that contains a list of sorting functions for sorting columns. See {@tutorial sorters}.
140
140
  * @property {canvasDatagrid.filter} filters - Object that contains a list of filters for filtering data. The properties in this object match the `schema[].type` property. For example, if the schema for a given column was of the type `date` the grid would look for a filter called `filters.date` if a filter cannot be found for a given data type a warning will be logged and the string/RegExp filter will be used. See {@link canvasDatagrid.filters}.
141
141
  * @property {boolean} hasActiveFilters - When true, grid data is being filtered.
142
- * @property {canvasDatagrid.data} data - This is how data is set in the grid. Data must be an array of objects that conform to a schema. Data values can be any primitive type. However if a cell value is another data array, an inner grid will be rendered into the cell. This "cell grid" is different than a "tree grid" (the sort you drill in with a row header arrow) and uses the `cellGridAttributes` attribute for properties and styling. See {@link canvasDatagrid.data}.
142
+ * @property {canvasDatagrid.data} data - This is how data is set in the grid. Data must be an array of objects that conform to a schema. Data values can be any primitive type. A column whose schema `type` is `canvas-datagrid` renders an inner grid into each of its cells, with the cell's value, itself an array of rows, as that grid's data. An array value on its own does not create an inner grid, the column type has to be set in the schema, otherwise the array is formatted as a string. This "cell grid" is different than a "tree grid" (the sort you drill in with a row header arrow) and uses the `cellGridAttributes` attribute for properties and styling. See {@link tutorial--Create-a-cell-grid}.
143
143
  * @property {canvasDatagrid.schema} schema - Schema is optional. Schema is an array of {canvasDatagrid.header} objects. If no schema is provided one will be generated from the data, in that case all data will be assumed to be string data. See {@link canvasDatagrid.schema}.
144
144
  * @property {number} scrollHeight - The total number of pixels that can be scrolled down.
145
145
  * @property {number} scrollWidth - The total number of pixels that can be scrolled to the left.
@@ -207,7 +207,7 @@
207
207
  * @class
208
208
  * @name canvasDatagrid.header
209
209
  * @property {string} name - The name of the header. This must match the property name of an object in the {@link canvasDatagrid.data} array. This is the only required property of a {@link canvasDatagrid.header}. This value will appear at the top of the column unless {@link canvasDatagrid.header.title} is defined.
210
- * @property {string} type - The data type of this header. This value should match properties in {@link canvasDatagrid.formatters}, {@link canvasDatagrid.filters}, {@link canvasDatagrid.sorters} to take full advantage of formatting, sorting and filtering when not defining these properties within this header.
210
+ * @property {string} type - The data type of this header. This value should match properties in {@link canvasDatagrid.formatters}, {@link canvasDatagrid.filters}, {@link canvasDatagrid.sorters} to take full advantage of formatting, sorting and filtering when not defining these properties within this header. The type `canvas-datagrid` is special: each cell in the column renders an inner grid, a "cell grid", with the cell's value (an array of rows) as its data. See {@link tutorial--Create-a-cell-grid}.
211
211
  * @property {string} title - The value that is actually displayed to the user at the top of the column. If no value is present, {@link canvasDatagrid.header.name} will be used instead.
212
212
  * @property {number} width - The mutable width of this column in pixels. The user can override this value if {@link canvasDatagrid.attributes.allowColumnResizing} is set to `true`.
213
213
  * @property {boolean} hidden - When true, the column will not be included in the visible schema. This means selection, copy, and drawing functions will not display this column or values from this column.
@@ -434,7 +434,7 @@
434
434
  * @property {number} [columnHeaderOrderByArrowWidth=13] - Style of columnHeaderOrderByArrowWidth.
435
435
  * @property {number} [rowHeaderCellWidth=57] - Style of rowHeaderCellWidth.
436
436
  * @property {number} [minColumnWidth=45] - Style of minColumnWidth.
437
- * @property {(number|string)} [height=auto] - Style of height.
437
+ * @property {(number|string)} [height=auto] - Height of the grid as a CSS value (`300px`, `100%`). With the default `auto` the grid fills its parent element when the parent has a height of its own; otherwise it grows to fit its rows, but never past the viewport height, and scrolls for the rest.
438
438
  * @property {number} [minHeight=24] - Style of minHeight.
439
439
  * @property {number} [minRowHeight=24] - Style of minRowHeight.
440
440
  * @property {string} [name=default] - Style of name.
@@ -504,7 +504,7 @@
504
504
  * @property {number} [frozenMarkerWidth=1] - Style of frozenMarkerWidth.
505
505
  * @property {string} [overflowY=auto] - When set to hidden, vertical scroll bar will be hidden. When set to auto vertical scroll bar will appear when data overflows the height. When set to scroll the vertical scrollbar will always be visible.
506
506
  * @property {string} [overflowX=auto] - When set to hidden, horizontal scroll bar will be hidden. When set to auto horizontal scroll bar will appear when data overflows the width. When set to scroll the horizontal scrollbar will always be visible.
507
- * @property {(number|string)} [width=auto] - Style of width.
507
+ * @property {(number|string)} [width=auto] - Width of the grid as a CSS value (`800px`, `100%`). With the default `auto` the grid fills its parent element when the parent has a width of its own; otherwise it grows to fit its columns, but never past the viewport width, and scrolls for the rest.
508
508
 
509
509
  ['', 'normal'],
510
510
  */
@@ -724,7 +724,7 @@
724
724
  */
725
725
  /**
726
726
  * Fires just after a cell grid calls its draw method. Allows you to alter the cell data grid.
727
- * Only fires once per child grid.
727
+ * Fires every time the parent grid draws the cell, so once per cell grid per draw.
728
728
  * @event
729
729
  * @name canvasDatagrid#rendercellgrid
730
730
  * @param {object} e Event object
package/lib/dom.js CHANGED
@@ -196,9 +196,91 @@ export default function (self) {
196
196
  };
197
197
  };
198
198
  /**
199
- * Watches the host element and its parent for size changes so a grid sized
200
- * with auto/percentage dimensions follows layout changes (flex, splitters,
201
- * tab switches) without an explicit `resize()` call (#289, #239).
199
+ * The element the grid sits in: the parent of the `canvas-datagrid` host
200
+ * element, or the host of the shadow tree the grid was placed in.
201
+ * @returns {HTMLElement|undefined}
202
+ */
203
+ self.getContainerElement = function () {
204
+ var host = self.intf && self.intf.nodeType === 1 ? self.intf : self.canvas,
205
+ container = host && host.parentNode;
206
+ if (container && container.nodeType === 11 && container.host) {
207
+ container = container.host;
208
+ }
209
+ return container && container.nodeType === 1 ? container : undefined;
210
+ };
211
+ /**
212
+ * Measures the room the container offers the grid in each dimension.
213
+ * A dimension is `undefined` when the container has no size of its own
214
+ * there, that is when it grows with the grid (an auto height block, a
215
+ * shrink-to-fit width); the caller then falls back to the content size.
216
+ *
217
+ * The probe makes the canvas one pixel larger than the container's client
218
+ * size and checks whether the container followed. When it did not, the
219
+ * overflow that the probe produced tells how much of the container is
220
+ * taken by padding and siblings. Everything is restored synchronously, so
221
+ * nothing is painted and no ResizeObserver notification results.
222
+ * @returns {{width: (number|undefined), height: (number|undefined)}}
223
+ */
224
+ self.measureContainerSpace = function () {
225
+ var space = {},
226
+ canvas = self.canvas,
227
+ container = self.getContainerElement(),
228
+ cache = self.containerSpaceCache,
229
+ canvasStyle,
230
+ saved;
231
+ if (!container || !canvas) {
232
+ return space;
233
+ }
234
+ if (
235
+ cache &&
236
+ cache.container === container &&
237
+ cache.clientWidth === container.clientWidth &&
238
+ cache.clientHeight === container.clientHeight
239
+ ) {
240
+ return cache.space;
241
+ }
242
+ canvasStyle = canvas.style;
243
+ saved = { width: canvasStyle.width, height: canvasStyle.height };
244
+ ['height', 'width'].forEach(function (dim) {
245
+ var client = dim === 'height' ? 'clientHeight' : 'clientWidth',
246
+ scroll = dim === 'height' ? 'scrollHeight' : 'scrollWidth',
247
+ before = container[client],
248
+ probe = before + 1,
249
+ after;
250
+ canvasStyle[dim] = probe + 'px';
251
+ after = container[client];
252
+ if (before === 0 || after > before) {
253
+ // nothing to measure (hidden or inline) or the container grew with
254
+ // the grid: it has no size of its own in this dimension
255
+ space[dim] = undefined;
256
+ } else {
257
+ // the container kept its size and the grid overflows it by at least
258
+ // one pixel; the overflow beyond that pixel is padding and siblings
259
+ space[dim] = Math.max(
260
+ 0,
261
+ Math.min(after, 2 * after + 1 - container[scroll]),
262
+ );
263
+ }
264
+ canvasStyle[dim] = saved[dim];
265
+ });
266
+ // resize() may run several times in one frame (drags, style changes);
267
+ // the probe forces layout, so reuse the result while the container
268
+ // keeps its size
269
+ self.containerSpaceCache = {
270
+ container: container,
271
+ clientWidth: container.clientWidth,
272
+ clientHeight: container.clientHeight,
273
+ space: space,
274
+ };
275
+ requestAnimationFrame(function () {
276
+ self.containerSpaceCache = undefined;
277
+ });
278
+ return space;
279
+ };
280
+ /**
281
+ * Watches the host element and its container for size changes so a grid
282
+ * sized with auto/percentage dimensions follows layout changes (flex,
283
+ * splitters, tab switches) without an explicit `resize()` call (#289, #239).
202
284
  * Falls back to the `window` resize listener when ResizeObserver is missing.
203
285
  */
204
286
  self.initResizeObserver = function () {
@@ -240,7 +322,7 @@ export default function (self) {
240
322
  self.resizeObserver.disconnect();
241
323
  self.observedSizes = new Map();
242
324
  var host = self.intf && self.intf.nodeType === 1 ? self.intf : self.canvas;
243
- [host, host && host.parentNode].forEach(function (target) {
325
+ [host, self.getContainerElement()].forEach(function (target) {
244
326
  if (target && target.nodeType === 1) {
245
327
  self.resizeObserver.observe(target);
246
328
  }
package/lib/draw.js CHANGED
@@ -1913,15 +1913,31 @@ export default function (self) {
1913
1913
  columnGroupsAreaHeight || 0;
1914
1914
  treeGrid.parentNode.rowGroupsAreaWidth += rowGroupsAreaWidth || 0;
1915
1915
  }
1916
+ // Hit-test entry for the child grid's area. Like every other visible
1917
+ // cell it is in this grid's own coordinates (the child's offsetTop and
1918
+ // offsetLeft are canvas coordinates) and carries the real tree size:
1919
+ // `treeGrid.height`/`width` are undefined on child grids, which made
1920
+ // this entry unmatchable, so a pointer over a tree grid still counted
1921
+ // as hovering the parent and the parent scrolled along with the tree.
1916
1922
  self.visibleCells.unshift({
1917
1923
  rowIndex: rowOrderIndex,
1918
1924
  columnIndex: 0,
1919
- y: treeGrid.parentNode.offsetTop,
1920
- x: treeGrid.parentNode.offsetLeft,
1921
- height: treeGrid.height,
1922
- width: treeGrid.width,
1925
+ y: y + rowSansTreeHeight,
1926
+ x: rowHeaderCellWidth - 1,
1927
+ height: treeHeight,
1928
+ width: treeGrid.parentNode.offsetWidth,
1923
1929
  style: 'tree-grid',
1924
1930
  type: treeGrid.parentNode.nodeType,
1931
+ data: rowData,
1932
+ header: {},
1933
+ isGrid: false,
1934
+ isNormal: false,
1935
+ isHeader: false,
1936
+ isCorner: false,
1937
+ isRowHeader: false,
1938
+ isColumnHeader: false,
1939
+ selected: false,
1940
+ hovered: false,
1925
1941
  });
1926
1942
  treeGrid.draw();
1927
1943
  } else if (treeGrid) {
@@ -169,18 +169,24 @@ export default function (self) {
169
169
  rowHeaderCellWidth = self.getRowHeaderCellWidth(),
170
170
  topGroupAreaHeight = self.getColumnGroupAreaHeight(),
171
171
  leftGroupAreaWidth = self.getRowGroupAreaWidth(),
172
- ch = self.style.cellHeight;
173
- // sets actual DOM canvas element
172
+ ch = self.style.cellHeight,
173
+ containerSpace = self.isChildGrid ? {} : self.measureContainerSpace();
174
+ function isAutoSize(value) {
175
+ return value === undefined || value === 'auto' || value === '';
176
+ }
174
177
  function checkScrollBoxVisibility() {
175
- var capped = self.autoSizeCapped || {};
178
+ // an auto-sized grid shows a scroll bar only when it could not grow to
179
+ // its content (container, viewport or canvas limit); a child grid is
180
+ // always bounded by the tree row or cell that holds it
181
+ var constrained = self.autoSizeConstrained || {};
176
182
  self.scrollBox.horizontalBarVisible =
177
- ((self.style.width !== 'auto' || capped.width) &&
183
+ ((!isAutoSize(self.style.width) || constrained.width) &&
178
184
  dataWidth > self.scrollBox.width &&
179
185
  self.style.overflowX !== 'hidden') ||
180
186
  self.style.overflowX === 'scroll';
181
187
  self.scrollBox.horizontalBoxVisible = dataWidth > self.scrollBox.width;
182
188
  self.scrollBox.verticalBarVisible =
183
- ((self.style.height !== 'auto' || capped.height) &&
189
+ ((!isAutoSize(self.style.height) || constrained.height) &&
184
190
  dataHeight > self.scrollBox.height &&
185
191
  self.style.overflowY !== 'hidden') ||
186
192
  self.style.overflowY === 'scroll';
@@ -192,8 +198,13 @@ export default function (self) {
192
198
  self.scrollBox.height =
193
199
  self.height - columnHeaderCellHeight - topGroupAreaHeight;
194
200
  }
201
+ // sizes the DOM canvas element and reads back the size the grid got
195
202
  function setCanvasSize() {
196
203
  if (self.isChildGrid) {
204
+ // a child grid fills the tree row or cell that holds it
205
+ self.autoSizeConstrained = { width: true, height: true };
206
+ self.width = self.parentNode.offsetWidth;
207
+ self.height = self.parentNode.offsetHeight;
197
208
  return;
198
209
  }
199
210
  dims = {
@@ -206,34 +217,39 @@ export default function (self) {
206
217
  1,
207
218
  width: dataWidth + rowHeaderCellWidth + cellBorder + leftGroupAreaWidth,
208
219
  };
209
- // Browsers refuse to paint canvases beyond roughly 16k px per side, so
210
- // an auto-sized grid with enough rows went blank past that point
211
- // (#254). Cap the element and let it scroll for the remainder.
212
220
  var maxCanvasSize = self.attributes.maxCanvasSize;
213
- self.autoSizeCapped = { width: false, height: false };
214
- ['width', 'height'].forEach(function (dim) {
215
- if (dims[dim] > maxCanvasSize) {
216
- dims[dim] = maxCanvasSize;
217
- self.autoSizeCapped[dim] = true;
218
- }
219
- });
221
+ self.autoSizeConstrained = { width: false, height: false };
220
222
  ['width', 'height'].forEach(function (dim) {
223
+ var styleIsAuto = isAutoSize(self.style[dim]),
224
+ inlineIsAuto = isAutoSize(self.appliedInlineStyles[dim]),
225
+ size;
221
226
  //TODO: support inherit
222
- if (
223
- ['auto', undefined].indexOf(self.style[dim]) !== -1 &&
224
- ['auto', undefined].indexOf(self.appliedInlineStyles[dim]) !== -1
225
- ) {
226
- self.parentNodeStyle[dim] = dims[dim] + 'px';
227
- } else if (
228
- ['auto', undefined].indexOf(self.style[dim]) == -1 &&
229
- ['auto', undefined].indexOf(self.appliedInlineStyles[dim]) == -1
230
- ) {
231
- self.parentNodeStyle[dim] = self.style[dim];
232
- if (self.isComponent) {
233
- self.canvas.style[dim] = self.style[dim];
227
+ if (styleIsAuto && inlineIsAuto) {
228
+ // No explicit size: fill the container when it has a size of its
229
+ // own in this dimension, otherwise fit the content but never grow
230
+ // past the viewport. Browsers also refuse to paint canvases beyond
231
+ // roughly 16k px per side (#254), so cap the element there too and
232
+ // let the grid scroll for the remainder.
233
+ size = dims[dim];
234
+ if (containerSpace[dim] !== undefined) {
235
+ size = containerSpace[dim];
236
+ } else {
237
+ size = Math.min(
238
+ size,
239
+ dim === 'height' ? window.innerHeight : window.innerWidth,
240
+ );
234
241
  }
242
+ size = Math.max(0, Math.min(size, maxCanvasSize));
243
+ self.autoSizeConstrained[dim] = size < dims[dim];
244
+ self.parentNodeStyle[dim] = size + 'px';
245
+ } else if (!styleIsAuto && !inlineIsAuto) {
246
+ self.parentNodeStyle[dim] = self.style[dim];
235
247
  }
236
248
  });
249
+ self.width = self.canvas.offsetWidth;
250
+ self.height = self.canvas.offsetHeight;
251
+ self.canvasOffsetLeft = self.args.canvasOffsetLeft || 0;
252
+ self.canvasOffsetTop = self.args.canvasOffsetTop || 0;
237
253
  }
238
254
  self.autoLastColumnWidth = undefined;
239
255
  dataWidth = self.refreshScrollCacheX();
@@ -255,18 +271,6 @@ export default function (self) {
255
271
  dataHeight += self.style.cellHeight;
256
272
  }
257
273
  setCanvasSize();
258
- if (self.isChildGrid) {
259
- self.width = self.parentNode.offsetWidth;
260
- self.height = self.parentNode.offsetHeight;
261
- } else if (
262
- self.height !== self.canvas.offsetHeight ||
263
- self.width !== self.canvas.offsetWidth
264
- ) {
265
- self.height = self.canvas.offsetHeight;
266
- self.width = self.canvas.offsetWidth;
267
- self.canvasOffsetLeft = self.args.canvasOffsetLeft || 0;
268
- self.canvasOffsetTop = self.args.canvasOffsetTop || 0;
269
- }
270
274
  /// calculate scroll bar dimensions
271
275
  // non-controversial
272
276
  self.scrollBox.top =
@@ -279,18 +283,12 @@ export default function (self) {
279
283
  // if the scroll box is visible, make room for it by expanding the size of the element
280
284
  // if the other dimension is set to auto
281
285
  if (self.scrollBox.horizontalBarVisible) {
282
- if (self.style.height === 'auto' && !self.isChildGrid) {
283
- self.height += sbw;
284
- }
285
286
  dataHeight += sbw;
286
287
  setCanvasSize();
287
288
  setScrollBoxSize();
288
289
  checkScrollBoxVisibility();
289
290
  }
290
291
  if (self.scrollBox.verticalBarVisible) {
291
- if (self.style.width === 'auto' && !self.isChildGrid) {
292
- self.width += sbw;
293
- }
294
292
  dataWidth += sbw;
295
293
  setCanvasSize();
296
294
  setScrollBoxSize();
@@ -1971,43 +1969,78 @@ export default function (self) {
1971
1969
  var l,
1972
1970
  t,
1973
1971
  ev = e,
1972
+ childEvent,
1974
1973
  deltaX = e.deltaX === undefined ? e.NativeEvent.deltaX : e.deltaX,
1975
1974
  deltaY = e.deltaY === undefined ? e.NativeEvent.deltaY : e.deltaY,
1976
1975
  deltaMode =
1977
1976
  e.deltaMode === undefined ? e.NativeEvent.deltaMode : e.deltaMode;
1978
1977
  if (e.NativeEvent) e = e.NativeEvent;
1978
+ if (self.disposed) {
1979
+ return;
1980
+ }
1981
+ //BUG Issue 42: https://github.com/TonyGermaneri/canvas-datagrid/issues/42
1982
+ //https://stackoverflow.com/questions/20110224/what-is-the-height-of-a-line-in-a-wheel-event-deltamode-dom-delta-line
1983
+ if (deltaMode === 1) {
1984
+ // line mode = 17 pixels per line
1985
+ deltaY = deltaY * 17;
1986
+ }
1987
+ // A child grid receives the wheel through its parent's `wheel` grid
1988
+ // event (`ev`), not from the DOM. It leaves two marks on that event for
1989
+ // its ancestors: `hovered` says the pointer is over this grid or one of
1990
+ // its descendants, so the ancestor is not the hovered grid itself;
1991
+ // `claim` says this grid consumed the wheel, so no ancestor scrolls and
1992
+ // neither does the page. A hovered grid with nothing left to scroll in
1993
+ // the wheel's direction only marks itself hovered, so the wheel moves on
1994
+ // to the parent grid, and from the top-level grid to the page, the way
1995
+ // nested scrolling elements chain in HTML.
1996
+ function hovered() {
1997
+ if (ev !== e) {
1998
+ ev.hoveredChildGrid = true;
1999
+ }
2000
+ }
2001
+ function claim() {
2002
+ e.preventDefault();
2003
+ if (ev !== e) {
2004
+ ev.claimedByChildGrid = true;
2005
+ ev.preventDefault();
2006
+ }
2007
+ }
2008
+ function canScroll() {
2009
+ var box = self.scrollBox;
2010
+ return (
2011
+ (box.scrollTop < box.scrollHeight && deltaY > 0) ||
2012
+ (box.scrollLeft < box.scrollWidth && deltaX > 0) ||
2013
+ (box.scrollTop > 0 && deltaY < 0) ||
2014
+ (box.scrollLeft > 0 && deltaX < 0)
2015
+ );
2016
+ }
1979
2017
  if (wheeling) {
1980
- ev.preventDefault(e);
2018
+ // still applying the previous wheel, this one belongs here too
2019
+ claim();
1981
2020
  return;
1982
2021
  }
1983
- if (self.dispatchEvent('wheel', { NativeEvent: e })) {
2022
+ childEvent = { NativeEvent: e };
2023
+ if (self.dispatchEvent('wheel', childEvent)) {
2024
+ if (childEvent.claimedByChildGrid) {
2025
+ claim();
2026
+ }
1984
2027
  return;
1985
2028
  }
1986
2029
  self.touchHaltAnimation = true;
2030
+ if (!self.hasFocus && !childEvent.hoveredChildGrid) {
2031
+ return;
2032
+ }
2033
+ hovered();
2034
+ if (!canScroll()) {
2035
+ return;
2036
+ }
2037
+ claim();
1987
2038
  l = self.scrollBox.scrollLeft;
1988
2039
  t = self.scrollBox.scrollTop;
1989
- if (self.hasFocus) {
1990
- //BUG Issue 42: https://github.com/TonyGermaneri/canvas-datagrid/issues/42
1991
- //https://stackoverflow.com/questions/20110224/what-is-the-height-of-a-line-in-a-wheel-event-deltamode-dom-delta-line
1992
- if (deltaMode === 1) {
1993
- // line mode = 17 pixels per line
1994
- deltaY = deltaY * 17;
1995
- }
1996
- if (
1997
- (self.scrollBox.scrollTop < self.scrollBox.scrollHeight &&
1998
- deltaY > 0) ||
1999
- (self.scrollBox.scrollLeft < self.scrollBox.scrollWidth &&
2000
- deltaX > 0) ||
2001
- (self.scrollBox.scrollTop > 0 && deltaY < 0) ||
2002
- (self.scrollBox.scrollLeft > 0 && deltaX < 0)
2003
- ) {
2004
- ev.preventDefault(e);
2005
- }
2006
- wheeling = setTimeout(function () {
2007
- wheeling = undefined;
2008
- self.scrollBox.scrollTo(deltaX + l, deltaY + t);
2009
- }, 1);
2010
- }
2040
+ wheeling = setTimeout(function () {
2041
+ wheeling = undefined;
2042
+ self.scrollBox.scrollTo(deltaX + l, deltaY + t);
2043
+ }, 1);
2011
2044
  };
2012
2045
  self.pasteData = function (
2013
2046
  pasteValue,
package/lib/intf.js CHANGED
@@ -749,7 +749,12 @@ export default function (self, ctor) {
749
749
  self.eventParent.removeEventListener('dblclick', self.dblclick, false);
750
750
  self.eventParent.removeEventListener('click', self.click, false);
751
751
  self.eventParent.removeEventListener('mousemove', self.mousemove);
752
- self.eventParent.removeEventListener('wheel', self.scrollWheel, false);
752
+ // child grids listen for the wheel on the parent grid's event, not the DOM
753
+ self[self.isChildGrid ? 'parentGrid' : 'eventParent'].removeEventListener(
754
+ 'wheel',
755
+ self.scrollWheel,
756
+ false,
757
+ );
753
758
  self.canvas.removeEventListener(
754
759
  'contextmenu',
755
760
  self.contextmenuEvent,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canvas-datagrid",
3
- "version": "0.26.0",
3
+ "version": "0.27.1",
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",