diff --git a/dist/hermes.cjs.js b/dist/hermes.cjs.js index d37abf5..dbe0cb2 100644 --- a/dist/hermes.cjs.js +++ b/dist/hermes.cjs.js @@ -251,6 +251,9 @@ const isString = (data) => typeof data === 'string'; const clone = (data) => { return JSON.parse(JSON.stringify(data)); }; +const capDataRange = (data, range) => { + return Math.min(range[1], Math.max(range[0], data)); +}; const getDataRange = (data) => { return data.reduce((acc, x) => { if (isNumber(x)) { @@ -665,7 +668,7 @@ const DRAG = { }, filters: { active: FILTER, - axes: {}, + existing: false, key: undefined, }, shared: { @@ -1473,16 +1476,22 @@ class Hermes { // See if there is an existing matching filter based on position. const index = (_filters[key] || []).findIndex(filter => pos >= filter.p0 && pos <= filter.p1); if (index !== -1) { + const filter = _filters[key][index]; _drf.active = _filters[key][index]; + _drf.active.startP0 = filter.p0; + _drf.active.startP1 = filter.p1; + _drf.existing = true; } else { _drf.active = { p0: pos, p1: pos, value0: value, value1: value }; + _drf.existing = false; // Store active filter into filter list. _filters[key] = _filters[key] || []; _filters[key].push(_drf.active); } } - updateActiveFilter(finalize = false) { + updateActiveFilter(e) { + var _a, _b; if (!this._) return; const _dl = this._.dims.list; @@ -1494,17 +1503,40 @@ class Hermes { const filterKey = isHorizontal ? 'y' : 'x'; if (_drag.type !== DragType.DimensionFilterCreate || !_drf.key) return; - // Update filter data before removing reference. const bound = _dl[_drs.index].layout.bound; - const axisStart = _dl[_drs.index].layout.axisStart; - const axisStop = _dl[_drs.index].layout.axisStop; - // Cap the p1 position to the axis limits. - let p1 = _drs.p1[filterKey] - bound[filterKey] - axisStart[filterKey]; - p1 = Math.min(axisStop[filterKey] - axisStart[filterKey], Math.max(0, p1)); - _drf.active.p1 = p1; - _drf.active.value1 = getAxisPositionValue(_drf.active.p1, axisStop[filterKey] - axisStart[filterKey], this.dimensions[_drs.index].axis.scale); + const axisStart = _dl[_drs.index].layout.axisStart[filterKey]; + const axisStop = _dl[_drs.index].layout.axisStop[filterKey]; + const axisRange = [0, axisStop - axisStart]; + /** + * If the active filter previously exists, we want to drag it, + * otherwise we want to change the size of the new one based on event position. + */ + if (_drf.existing) { + const startP0 = (_a = _drf.active.startP0) !== null && _a !== void 0 ? _a : 0; + const startP1 = (_b = _drf.active.startP1) !== null && _b !== void 0 ? _b : 0; + const startLength = startP1 - startP0; + const shift = _drs.p1[filterKey] - _drs.p0[filterKey]; + _drf.active.p0 = startP0 + shift; + _drf.active.p1 = startP1 + shift; + // Cap the drag to the axis edges. + if (_drf.active.p0 < axisRange[0]) { + _drf.active.p0 = 0; + _drf.active.p1 = startLength; + } + else if (_drf.active.p1 > axisRange[1]) { + _drf.active.p0 = axisRange[1] - startLength; + _drf.active.p1 = axisRange[1]; + } + _drf.active.value0 = getAxisPositionValue(_drf.active.p0, axisStop - axisStart, this.dimensions[_drs.index].axis.scale); + _drf.active.value1 = getAxisPositionValue(_drf.active.p1, axisStop - axisStart, this.dimensions[_drs.index].axis.scale); + } + else { + // Update filter data before removing reference. + _drf.active.p1 = capDataRange(_drs.p1[filterKey] - bound[filterKey] - axisStart, axisRange); + _drf.active.value1 = getAxisPositionValue(_drf.active.p1, axisStop - axisStart, this.dimensions[_drs.index].axis.scale); + } // Whether or not to finalize active filter and removing reference to it. - if (!finalize) + if (e.type !== 'mouseup') return; /** * Check to see if the release event is near the starting event. @@ -1525,7 +1557,7 @@ class Hermes { [_drf.active.p0, _drf.active.value0] = [tempP, tempValue]; } // Overwrite active filter to remove reference to filter in filters list. - _drf.active = FILTER; + _drf.active = { ...FILTER }; _drf.key = undefined; this.mergeFilters(); } @@ -1553,7 +1585,6 @@ class Hermes { var _a; if (!this._) return; - // console.time('render time'); const { h, w } = this.size; const _dl = this._.dims.list; const _dsl = this._.dims.shared.label; @@ -1669,7 +1700,6 @@ class Hermes { drawRect(this.ctx, x, y, w, h, axesStyle.filter); }); }); - // console.timeEnd('render time'); } drawDebugOutline() { if (!this._) @@ -1708,7 +1738,6 @@ class Hermes { return; const [x, y] = [e.clientX, e.clientY]; const _drag = this.drag; - this.filters; const _drs = this.drag.shared; const _drd = this.drag.dimension; const _drf = this.drag.filters; @@ -1779,7 +1808,7 @@ class Hermes { } } // Update dimension filter creating dragging data. - this.updateActiveFilter(); + this.updateActiveFilter(e); this.calculate(); } handleMouseUp(e) { @@ -1788,7 +1817,7 @@ class Hermes { const [x, y] = [e.clientX, e.clientY]; const _drs = this.drag.shared; _drs.p1 = { x, y }; - this.updateActiveFilter(true); + this.updateActiveFilter(e); // Reset drag info. this.drag = clone(DRAG); this.calculate(); diff --git a/dist/hermes.esm.js b/dist/hermes.esm.js index 5608f57..95d800d 100644 --- a/dist/hermes.esm.js +++ b/dist/hermes.esm.js @@ -249,6 +249,9 @@ const isString = (data) => typeof data === 'string'; const clone = (data) => { return JSON.parse(JSON.stringify(data)); }; +const capDataRange = (data, range) => { + return Math.min(range[1], Math.max(range[0], data)); +}; const getDataRange = (data) => { return data.reduce((acc, x) => { if (isNumber(x)) { @@ -663,7 +666,7 @@ const DRAG = { }, filters: { active: FILTER, - axes: {}, + existing: false, key: undefined, }, shared: { @@ -1471,16 +1474,22 @@ class Hermes { // See if there is an existing matching filter based on position. const index = (_filters[key] || []).findIndex(filter => pos >= filter.p0 && pos <= filter.p1); if (index !== -1) { + const filter = _filters[key][index]; _drf.active = _filters[key][index]; + _drf.active.startP0 = filter.p0; + _drf.active.startP1 = filter.p1; + _drf.existing = true; } else { _drf.active = { p0: pos, p1: pos, value0: value, value1: value }; + _drf.existing = false; // Store active filter into filter list. _filters[key] = _filters[key] || []; _filters[key].push(_drf.active); } } - updateActiveFilter(finalize = false) { + updateActiveFilter(e) { + var _a, _b; if (!this._) return; const _dl = this._.dims.list; @@ -1492,17 +1501,40 @@ class Hermes { const filterKey = isHorizontal ? 'y' : 'x'; if (_drag.type !== DragType.DimensionFilterCreate || !_drf.key) return; - // Update filter data before removing reference. const bound = _dl[_drs.index].layout.bound; - const axisStart = _dl[_drs.index].layout.axisStart; - const axisStop = _dl[_drs.index].layout.axisStop; - // Cap the p1 position to the axis limits. - let p1 = _drs.p1[filterKey] - bound[filterKey] - axisStart[filterKey]; - p1 = Math.min(axisStop[filterKey] - axisStart[filterKey], Math.max(0, p1)); - _drf.active.p1 = p1; - _drf.active.value1 = getAxisPositionValue(_drf.active.p1, axisStop[filterKey] - axisStart[filterKey], this.dimensions[_drs.index].axis.scale); + const axisStart = _dl[_drs.index].layout.axisStart[filterKey]; + const axisStop = _dl[_drs.index].layout.axisStop[filterKey]; + const axisRange = [0, axisStop - axisStart]; + /** + * If the active filter previously exists, we want to drag it, + * otherwise we want to change the size of the new one based on event position. + */ + if (_drf.existing) { + const startP0 = (_a = _drf.active.startP0) !== null && _a !== void 0 ? _a : 0; + const startP1 = (_b = _drf.active.startP1) !== null && _b !== void 0 ? _b : 0; + const startLength = startP1 - startP0; + const shift = _drs.p1[filterKey] - _drs.p0[filterKey]; + _drf.active.p0 = startP0 + shift; + _drf.active.p1 = startP1 + shift; + // Cap the drag to the axis edges. + if (_drf.active.p0 < axisRange[0]) { + _drf.active.p0 = 0; + _drf.active.p1 = startLength; + } + else if (_drf.active.p1 > axisRange[1]) { + _drf.active.p0 = axisRange[1] - startLength; + _drf.active.p1 = axisRange[1]; + } + _drf.active.value0 = getAxisPositionValue(_drf.active.p0, axisStop - axisStart, this.dimensions[_drs.index].axis.scale); + _drf.active.value1 = getAxisPositionValue(_drf.active.p1, axisStop - axisStart, this.dimensions[_drs.index].axis.scale); + } + else { + // Update filter data before removing reference. + _drf.active.p1 = capDataRange(_drs.p1[filterKey] - bound[filterKey] - axisStart, axisRange); + _drf.active.value1 = getAxisPositionValue(_drf.active.p1, axisStop - axisStart, this.dimensions[_drs.index].axis.scale); + } // Whether or not to finalize active filter and removing reference to it. - if (!finalize) + if (e.type !== 'mouseup') return; /** * Check to see if the release event is near the starting event. @@ -1523,7 +1555,7 @@ class Hermes { [_drf.active.p0, _drf.active.value0] = [tempP, tempValue]; } // Overwrite active filter to remove reference to filter in filters list. - _drf.active = FILTER; + _drf.active = { ...FILTER }; _drf.key = undefined; this.mergeFilters(); } @@ -1551,7 +1583,6 @@ class Hermes { var _a; if (!this._) return; - // console.time('render time'); const { h, w } = this.size; const _dl = this._.dims.list; const _dsl = this._.dims.shared.label; @@ -1667,7 +1698,6 @@ class Hermes { drawRect(this.ctx, x, y, w, h, axesStyle.filter); }); }); - // console.timeEnd('render time'); } drawDebugOutline() { if (!this._) @@ -1706,7 +1736,6 @@ class Hermes { return; const [x, y] = [e.clientX, e.clientY]; const _drag = this.drag; - this.filters; const _drs = this.drag.shared; const _drd = this.drag.dimension; const _drf = this.drag.filters; @@ -1777,7 +1806,7 @@ class Hermes { } } // Update dimension filter creating dragging data. - this.updateActiveFilter(); + this.updateActiveFilter(e); this.calculate(); } handleMouseUp(e) { @@ -1786,7 +1815,7 @@ class Hermes { const [x, y] = [e.clientX, e.clientY]; const _drs = this.drag.shared; _drs.p1 = { x, y }; - this.updateActiveFilter(true); + this.updateActiveFilter(e); // Reset drag info. this.drag = clone(DRAG); this.calculate(); diff --git a/dist/hermes.iife.js b/dist/hermes.iife.js index 1133976..dcc8c54 100644 --- a/dist/hermes.iife.js +++ b/dist/hermes.iife.js @@ -252,6 +252,9 @@ var Hermes = (function () { const clone = (data) => { return JSON.parse(JSON.stringify(data)); }; + const capDataRange = (data, range) => { + return Math.min(range[1], Math.max(range[0], data)); + }; const getDataRange = (data) => { return data.reduce((acc, x) => { if (isNumber(x)) { @@ -666,7 +669,7 @@ var Hermes = (function () { }, filters: { active: FILTER, - axes: {}, + existing: false, key: undefined, }, shared: { @@ -1474,16 +1477,22 @@ var Hermes = (function () { // See if there is an existing matching filter based on position. const index = (_filters[key] || []).findIndex(filter => pos >= filter.p0 && pos <= filter.p1); if (index !== -1) { + const filter = _filters[key][index]; _drf.active = _filters[key][index]; + _drf.active.startP0 = filter.p0; + _drf.active.startP1 = filter.p1; + _drf.existing = true; } else { _drf.active = { p0: pos, p1: pos, value0: value, value1: value }; + _drf.existing = false; // Store active filter into filter list. _filters[key] = _filters[key] || []; _filters[key].push(_drf.active); } } - updateActiveFilter(finalize = false) { + updateActiveFilter(e) { + var _a, _b; if (!this._) return; const _dl = this._.dims.list; @@ -1495,17 +1504,40 @@ var Hermes = (function () { const filterKey = isHorizontal ? 'y' : 'x'; if (_drag.type !== DragType.DimensionFilterCreate || !_drf.key) return; - // Update filter data before removing reference. const bound = _dl[_drs.index].layout.bound; - const axisStart = _dl[_drs.index].layout.axisStart; - const axisStop = _dl[_drs.index].layout.axisStop; - // Cap the p1 position to the axis limits. - let p1 = _drs.p1[filterKey] - bound[filterKey] - axisStart[filterKey]; - p1 = Math.min(axisStop[filterKey] - axisStart[filterKey], Math.max(0, p1)); - _drf.active.p1 = p1; - _drf.active.value1 = getAxisPositionValue(_drf.active.p1, axisStop[filterKey] - axisStart[filterKey], this.dimensions[_drs.index].axis.scale); + const axisStart = _dl[_drs.index].layout.axisStart[filterKey]; + const axisStop = _dl[_drs.index].layout.axisStop[filterKey]; + const axisRange = [0, axisStop - axisStart]; + /** + * If the active filter previously exists, we want to drag it, + * otherwise we want to change the size of the new one based on event position. + */ + if (_drf.existing) { + const startP0 = (_a = _drf.active.startP0) !== null && _a !== void 0 ? _a : 0; + const startP1 = (_b = _drf.active.startP1) !== null && _b !== void 0 ? _b : 0; + const startLength = startP1 - startP0; + const shift = _drs.p1[filterKey] - _drs.p0[filterKey]; + _drf.active.p0 = startP0 + shift; + _drf.active.p1 = startP1 + shift; + // Cap the drag to the axis edges. + if (_drf.active.p0 < axisRange[0]) { + _drf.active.p0 = 0; + _drf.active.p1 = startLength; + } + else if (_drf.active.p1 > axisRange[1]) { + _drf.active.p0 = axisRange[1] - startLength; + _drf.active.p1 = axisRange[1]; + } + _drf.active.value0 = getAxisPositionValue(_drf.active.p0, axisStop - axisStart, this.dimensions[_drs.index].axis.scale); + _drf.active.value1 = getAxisPositionValue(_drf.active.p1, axisStop - axisStart, this.dimensions[_drs.index].axis.scale); + } + else { + // Update filter data before removing reference. + _drf.active.p1 = capDataRange(_drs.p1[filterKey] - bound[filterKey] - axisStart, axisRange); + _drf.active.value1 = getAxisPositionValue(_drf.active.p1, axisStop - axisStart, this.dimensions[_drs.index].axis.scale); + } // Whether or not to finalize active filter and removing reference to it. - if (!finalize) + if (e.type !== 'mouseup') return; /** * Check to see if the release event is near the starting event. @@ -1526,7 +1558,7 @@ var Hermes = (function () { [_drf.active.p0, _drf.active.value0] = [tempP, tempValue]; } // Overwrite active filter to remove reference to filter in filters list. - _drf.active = FILTER; + _drf.active = { ...FILTER }; _drf.key = undefined; this.mergeFilters(); } @@ -1554,7 +1586,6 @@ var Hermes = (function () { var _a; if (!this._) return; - // console.time('render time'); const { h, w } = this.size; const _dl = this._.dims.list; const _dsl = this._.dims.shared.label; @@ -1670,7 +1701,6 @@ var Hermes = (function () { drawRect(this.ctx, x, y, w, h, axesStyle.filter); }); }); - // console.timeEnd('render time'); } drawDebugOutline() { if (!this._) @@ -1709,7 +1739,6 @@ var Hermes = (function () { return; const [x, y] = [e.clientX, e.clientY]; const _drag = this.drag; - this.filters; const _drs = this.drag.shared; const _drd = this.drag.dimension; const _drf = this.drag.filters; @@ -1780,7 +1809,7 @@ var Hermes = (function () { } } // Update dimension filter creating dragging data. - this.updateActiveFilter(); + this.updateActiveFilter(e); this.calculate(); } handleMouseUp(e) { @@ -1789,7 +1818,7 @@ var Hermes = (function () { const [x, y] = [e.clientX, e.clientY]; const _drs = this.drag.shared; _drs.p1 = { x, y }; - this.updateActiveFilter(true); + this.updateActiveFilter(e); // Reset drag info. this.drag = clone(DRAG); this.calculate(); diff --git a/src/classes/CategoricalScale.ts b/src/classes/CategoricalScale.ts index e4f30bc..a162430 100644 --- a/src/classes/CategoricalScale.ts +++ b/src/classes/CategoricalScale.ts @@ -1,4 +1,4 @@ -import { Primitive, Range } from '../types'; +import { Primitive } from '../types'; import { value2str } from '../utils/string'; import NiceScale from './NiceScale'; diff --git a/src/classes/NiceScale.ts b/src/classes/NiceScale.ts index 2c95468..94b5ddb 100644 --- a/src/classes/NiceScale.ts +++ b/src/classes/NiceScale.ts @@ -5,7 +5,7 @@ * https://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks */ -import { Primitive, Range } from '../types'; +import { Primitive } from '../types'; const MIN_TICK_DISTANCE = 50; diff --git a/src/defaults.ts b/src/defaults.ts index 998caca..8d2a297 100644 --- a/src/defaults.ts +++ b/src/defaults.ts @@ -85,14 +85,14 @@ export const HERMES_OPTIONS: t.HermesOptions = { }, }; -export const FILTER = { +export const FILTER: t.Filter = { p0: Number.NaN, p1: Number.NaN, value0: Number.NaN, value1: Number.NaN, }; -export const DRAG = { +export const DRAG: t.Drag = { dimension: { bound0: undefined, bound1: undefined, @@ -100,7 +100,7 @@ export const DRAG = { }, filters: { active: FILTER, - axes: {}, + existing: false, key: undefined, }, shared: { diff --git a/src/index.ts b/src/index.ts index 2041bf0..dd8c4c5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,7 +9,7 @@ import * as DEFAULT from './defaults'; import * as t from './types'; import * as canvas from './utils/canvas'; import { scale2rgba } from './utils/color'; -import { clone, getDataRange } from './utils/data'; +import { capDataRange, clone, getDataRange } from './utils/data'; import { getElement } from './utils/dom'; import * as ix from './utils/interaction'; import { distance, isPointInTriangle, percentRectIntersection, shiftRect } from './utils/math'; @@ -403,9 +403,14 @@ class Hermes { // See if there is an existing matching filter based on position. const index = (_filters[key] || []).findIndex(filter => pos >= filter.p0 && pos <= filter.p1); if (index !== -1) { + const filter = _filters[key][index]; _drf.active = _filters[key][index]; + _drf.active.startP0 = filter.p0; + _drf.active.startP1 = filter.p1; + _drf.existing = true; } else { _drf.active = { p0: pos, p1: pos, value0: value, value1: value }; + _drf.existing = false; // Store active filter into filter list. _filters[key] = _filters[key] || []; @@ -413,7 +418,7 @@ class Hermes { } } - private updateActiveFilter(finalize = false): void { + private updateActiveFilter(e: MouseEvent): void { if (!this._) return; const _dl = this._.dims.list; @@ -426,24 +431,55 @@ class Hermes { if (_drag.type !== t.DragType.DimensionFilterCreate || !_drf.key) return; - // Update filter data before removing reference. const bound = _dl[_drs.index].layout.bound; - const axisStart = _dl[_drs.index].layout.axisStart; - const axisStop = _dl[_drs.index].layout.axisStop; + const axisStart = _dl[_drs.index].layout.axisStart[filterKey]; + const axisStop = _dl[_drs.index].layout.axisStop[filterKey]; + const axisRange: t.Range = [ 0, axisStop - axisStart ]; - // Cap the p1 position to the axis limits. - let p1 = _drs.p1[filterKey] - bound[filterKey] - axisStart[filterKey]; - p1 = Math.min(axisStop[filterKey] - axisStart[filterKey], Math.max(0, p1)); + /** + * If the active filter previously exists, we want to drag it, + * otherwise we want to change the size of the new one based on event position. + */ + if (_drf.existing) { + const startP0 = _drf.active.startP0 ?? 0; + const startP1 = _drf.active.startP1 ?? 0; + const startLength = startP1 - startP0; + const shift = _drs.p1[filterKey] - _drs.p0[filterKey]; + + _drf.active.p0 = startP0 + shift; + _drf.active.p1 = startP1 + shift; + + // Cap the drag to the axis edges. + if (_drf.active.p0 < axisRange[0]) { + _drf.active.p0 = 0; + _drf.active.p1 = startLength; + } else if (_drf.active.p1 > axisRange[1]) { + _drf.active.p0 = axisRange[1] - startLength; + _drf.active.p1 = axisRange[1]; + } - _drf.active.p1 = p1; - _drf.active.value1 = ix.getAxisPositionValue( - _drf.active.p1, - axisStop[filterKey] - axisStart[filterKey], - this.dimensions[_drs.index].axis.scale, - ); + _drf.active.value0 = ix.getAxisPositionValue( + _drf.active.p0, + axisStop - axisStart, + this.dimensions[_drs.index].axis.scale, + ); + _drf.active.value1 = ix.getAxisPositionValue( + _drf.active.p1, + axisStop - axisStart, + this.dimensions[_drs.index].axis.scale, + ); + } else { + // Update filter data before removing reference. + _drf.active.p1 = capDataRange(_drs.p1[filterKey] - bound[filterKey] - axisStart, axisRange); + _drf.active.value1 = ix.getAxisPositionValue( + _drf.active.p1, + axisStop - axisStart, + this.dimensions[_drs.index].axis.scale, + ); + } // Whether or not to finalize active filter and removing reference to it. - if (!finalize) return; + if (e.type !== 'mouseup') return; /** * Check to see if the release event is near the starting event. @@ -465,7 +501,7 @@ class Hermes { } // Overwrite active filter to remove reference to filter in filters list. - _drf.active = DEFAULT.FILTER; + _drf.active = { ...DEFAULT.FILTER }; _drf.key = undefined; this.mergeFilters(); @@ -494,8 +530,6 @@ class Hermes { private draw(): void { if (!this._) return; - // console.time('render time'); - const { h, w } = this.size; const _dl = this._.dims.list; const _dsl = this._.dims.shared.label; @@ -630,8 +664,6 @@ class Hermes { canvas.drawRect(this.ctx, x, y, w, h, axesStyle.filter); }); }); - - // console.timeEnd('render time'); } private drawDebugOutline(): void { @@ -688,7 +720,6 @@ class Hermes { const [ x, y ] = [ e.clientX, e.clientY ]; const _drag = this.drag; - const _filters = this.filters; const _drs = this.drag.shared; const _drd = this.drag.dimension; const _drf = this.drag.filters; @@ -779,7 +810,7 @@ class Hermes { } // Update dimension filter creating dragging data. - this.updateActiveFilter(); + this.updateActiveFilter(e); this.calculate(); } @@ -792,7 +823,7 @@ class Hermes { _drs.p1 = { x, y }; - this.updateActiveFilter(true); + this.updateActiveFilter(e); // Reset drag info. this.drag = clone(DEFAULT.DRAG); diff --git a/src/types.ts b/src/types.ts index 1328c6f..0488668 100644 --- a/src/types.ts +++ b/src/types.ts @@ -125,6 +125,11 @@ export interface Filter { value1: Primitive; // ending axis value. } +export interface FilterActive extends Filter { + startP0?: number; // Initial p0 value before an existing filter is shifted via dragging. + startP1?: number; // Initial p1 value before an existing filter is shifted via dragging. +} + export interface FilterOptions extends StyleShape { width: number; } @@ -178,7 +183,8 @@ export interface Drag { offset: Point; }; filters: { - active: Filter; + active: FilterActive; + existing: boolean; key?: DimensionKey; }; shared: { diff --git a/src/utils/data.ts b/src/utils/data.ts index 8bacc1b..e2ee4ea 100644 --- a/src/utils/data.ts +++ b/src/utils/data.ts @@ -16,6 +16,10 @@ export const clone = (data: T): T => { return JSON.parse(JSON.stringify(data)); }; +export const capDataRange = (data: number, range: Range): number => { + return Math.min(range[1], Math.max(range[0], data)); +}; + export const getDataRange = (data: unknown[]): Range => { return data.reduce((acc: Range, x) => { if (isNumber(x)) {