UNPKG

highcharts

Version:
1,517 lines (1,502 loc) 254 kB
// SPDX-License-Identifier: LicenseRef-Highcharts /** * @license Highcharts JS v13.0.1 (2026-08-17) * @module highcharts/modules/data-tools * @requires highcharts * * Highcharts * * (c) 2010-2026 Highsoft AS * * A commercial license may be required depending on use, * see www.highcharts.com/license */ import * as __WEBPACK_EXTERNAL_MODULE__highcharts_src_js_8202131d__ from "../highcharts.src.js"; /******/ // The require scope /******/ const __webpack_require__ = {}; /******/ /************************************************************************/ /******/ /* webpack/runtime/compat get default export */ /******/ (() => { /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = (module) => { /******/ const getter = module && module.__esModule ? /******/ () => (module['default']) : /******/ () => (module); /******/ __webpack_require__.d(getter, { a: getter }); /******/ return getter; /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter/value functions for harmony exports /******/ __webpack_require__.d = (exports, definition) => { /******/ if(Array.isArray(definition)) { /******/ var i = 0; /******/ while(i < definition.length) { /******/ var key = definition[i++]; /******/ var binding = definition[i++]; /******/ if(!__webpack_require__.o(exports, key)) { /******/ if(binding === 0) { /******/ Object.defineProperty(exports, key, { enumerable: true, value: definition[i++] }); /******/ } else { /******/ Object.defineProperty(exports, key, { enumerable: true, get: binding }); /******/ } /******/ } else if(binding === 0) { i++; } /******/ } /******/ } else { /******/ for(var key in definition) { /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); /******/ } /******/ } /******/ } /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ /******/ (() => { /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) /******/ })(); /******/ /************************************************************************/ ;// external ["../highcharts.src.js","default"] const external_highcharts_src_js_default_namespaceObject = __WEBPACK_EXTERNAL_MODULE__highcharts_src_js_8202131d__["default"]; var external_highcharts_src_js_default_default = /*#__PURE__*/__webpack_require__.n(external_highcharts_src_js_default_namespaceObject); ;// ./code/es-modules/Data/Modifiers/DataModifier.js /* * * * (c) 2009-2026 Highsoft AS * * Integration of this software requires a license. * - For commercial use, see www.highcharts.com/license * - For non-commercial, see www.highcharts.com/license-eula * * * Authors: * - Sophie Bremer * - Gøran Slettemark * - Dawid Draguła * * */ /* * * * Class * * */ /** * Abstract class to provide an interface for modifying a table. */ class DataModifier { /** * Adds a modifier class to the registry. The modifier class has to provide * the `DataModifier.options` property and the `DataModifier.modifyTable` * method to modify the table. * * @private * * @param {string} key * Registry key of the modifier class. * * @param {DataModifierType} DataModifierClass * Modifier class (aka class constructor) to register. * * @return {boolean} * Returns true, if the registration was successful. False is returned, if * their is already a modifier registered with this key. */ static registerType(key, DataModifierClass) { return (!!key && !DataModifier.types[key] && !!(DataModifier.types[key] = DataModifierClass)); } /* * * * Functions * * */ /** * Runs a timed execution of the modifier on the given datatable. * Can be configured to run multiple times. * * @param {DataTable} dataTable * The datatable to execute * * @param {BenchmarkOptions} options * Options. Currently supports `iterations` for number of iterations. * * @return {Array<number>} * An array of times in milliseconds * */ benchmark(dataTable, options) { const results = []; const modifier = this; const execute = () => { modifier.modifyTable(dataTable); modifier.emit({ type: 'afterBenchmarkIteration' }); }; const defaultOptions = { iterations: 1 }; const { iterations } = (0,external_highcharts_src_js_default_namespaceObject.merge)(defaultOptions, options); modifier.on('afterBenchmarkIteration', () => { if (results.length === iterations) { modifier.emit({ type: 'afterBenchmark', results }); return; } // Run again execute(); }); const times = { startTime: 0, endTime: 0 }; // Add timers modifier.on('modify', () => { times.startTime = window.performance.now(); }); modifier.on('afterModify', () => { times.endTime = window.performance.now(); results.push(times.endTime - times.startTime); }); // Initial run execute(); return results; } /** * Emits an event on the modifier to all registered callbacks of this event. * * @param {DataModifierEvent} [e] * Event object containing additional event information. */ emit(e) { (0,external_highcharts_src_js_default_namespaceObject.fireEvent)(this, e.type, e); } /** * Modifies the given table and sets its `modified` property as a reference * to the modified table. If `modified` property does not exist on the * original table, it's always created. * * @param {Highcharts.DataTable} table * Table to modify. * * @param {DataEventDetail} [eventDetail] * Custom information for pending events. * * @return {Promise<Highcharts.DataTable>} * Table with `modified` property as a reference. */ modify(table, eventDetail) { const modifier = this; return new Promise((resolve, reject) => { if (!table.modified) { table.modified = table.clone(false, eventDetail); } try { resolve(modifier.modifyTable(table, eventDetail)); } catch (e) { modifier.emit({ type: 'error', detail: eventDetail, table }); reject(e instanceof Error ? e : new Error('' + e)); } }); } /** * Registers a callback for a specific modifier event. * * @param {string} type * Event type as a string. * * @param {DataEventCallback} callback * Function to register for an modifier callback. * * @return {Function} * Function to unregister callback from the modifier event. */ on(type, callback) { return (0,external_highcharts_src_js_default_namespaceObject.addEvent)(this, type, callback); } } /* * * * Static Properties * * */ /** * Registry as a record object with modifier names and their class * constructor. */ DataModifier.types = {}; /* * * * Default Export * * */ /* harmony default export */ const Modifiers_DataModifier = (DataModifier); ;// ./code/es-modules/Data/ColumnUtils.js /* * * * (c) 2020-2026 Highsoft AS * * Integration of this software requires a license. * - For commercial use, see www.highcharts.com/license * - For non-commercial, see www.highcharts.com/license-eula * * * Authors: * - Dawid Draguła * * */ /* * * * Functions * * */ /** * Sets the length of the column array. * * @param {DataTableColumn} column * Column to be modified. * * @param {number} length * New length of the column. * * @param {boolean} asSubarray * If column is a typed array, return a subarray instead of a new array. It * is faster `O(1)`, but the entire buffer will be kept in memory until all * views of it are destroyed. Default is `false`. * * @return {DataTableColumn} * Modified column. * * @private */ function setLength(column, length, asSubarray) { if (Array.isArray(column)) { column.length = length; return column; } return column[asSubarray ? 'subarray' : 'slice'](0, length); } /** * Splices a column array. * * @param {DataTableColumn} column * Column to be modified. * * @param {number} start * Index at which to start changing the array. * * @param {number} deleteCount * An integer indicating the number of old array elements to remove. * * @param {boolean} removedAsSubarray * If column is a typed array, return a subarray instead of a new array. It * is faster `O(1)`, but the entire buffer will be kept in memory until all * views to it are destroyed. Default is `true`. * * @param {Array<number>|TypedArray} items * The elements to add to the array, beginning at the start index. If you * don't specify any elements, `splice()` will only remove elements from the * array. * * @return {SpliceResult} * Object containing removed elements and the modified column. * * @private */ function splice(column, start, deleteCount, removedAsSubarray, items = []) { if (Array.isArray(column)) { if (!Array.isArray(items)) { items = Array.from(items); } return { removed: column.splice(start, deleteCount, ...items), array: column }; } const Constructor = Object.getPrototypeOf(column) .constructor; const removed = column[removedAsSubarray ? 'subarray' : 'slice'](start, start + deleteCount); const newLength = column.length - deleteCount + items.length; const result = new Constructor(newLength); result.set(column.subarray(0, start), 0); result.set(items, start); result.set(column.subarray(start + deleteCount), start + items.length); return { removed: removed, array: result }; } /** * Converts a cell value to a number. * * @param {DataTableCellType} value * Cell value to convert to a number. * * @param {boolean} useNaN * If `true`, returns `NaN` for non-numeric values; if `false`, * returns `null` instead. * * @return {number | null} * Number or `null` if the value is not a number. * * @private */ function convertToNumber(value, useNaN) { switch (typeof value) { case 'boolean': return (value ? 1 : 0); case 'number': return (isNaN(value) && !useNaN ? null : value); default: value = parseFloat(`${value ?? ''}`); return (isNaN(value) && !useNaN ? null : value); } } /* * * * Default Export * * */ const ColumnUtils = { convertToNumber, setLength, splice }; /* harmony default export */ const Data_ColumnUtils = (ColumnUtils); ;// ./code/es-modules/Data/DataTableCore.js /* * * * (c) 2009-2026 Highsoft AS * * Integration of this software requires a license. * - For commercial use, see www.highcharts.com/license * - For non-commercial, see www.highcharts.com/license-eula * * * Authors: * - Sophie Bremer * - Gøran Slettemark * - Torstein Hønsi * * */ const { setLength: DataTableCore_setLength, splice: DataTableCore_splice } = Data_ColumnUtils; /* * * * Class * * */ /** * Class to manage columns and rows in a table structure. It provides methods * to add, remove, and manipulate columns and rows, as well as to retrieve data * from specific cells. * * Highcharts allows passing a `DataTable` or a configuration object for a data * table in the `dataTable` property, either chart-level * [dataTable](https://api.highcharts.com/highcharts/dataTable) or as * [series.dataTable](https://api.highcharts.com/highcharts/series.dataTable). * The `DataTable` is then used as a source for the series data points, mapped * by the `series.dataMapping` option. * * After chart instantiation, the data table can be accessed from the series as * `series.dataTable`. CRUD operations on the data table will be reflected in * the chart. * * @example * const dataTable = new Highcharts.DataTable({ * columns: { * year: [2020, 2021, 2022, 2023], * cost: [11, 13, 12, 14], * revenue: [12, 15, 14, 18] * } * }); * * @class * @name Highcharts.DataTable * * @param {Highcharts.DataTableOptionsObject} [options] * Options to initialize the new DataTable instance. */ class DataTableCore { constructor(options = {}) { this.isDataTable = true; this.autoId = !options.id; this.columns = {}; this.id = (options.id || (0,external_highcharts_src_js_default_namespaceObject.uniqueKey)()); this.rowCount = 0; this.versionTag = (0,external_highcharts_src_js_default_namespaceObject.uniqueKey)(); let rowCount = 0; (0,external_highcharts_src_js_default_namespaceObject.objectEach)(options.columns || {}, (column, columnId) => { this.columns[columnId] = column.slice(); rowCount = Math.max(rowCount, column.length); }); this.applyRowCount(rowCount); } /* * * * Functions * * */ /** * Applies a row count to the table by setting the `rowCount` property and * adjusting the length of all columns. * * @private * @param {number} rowCount The new row count. */ applyRowCount(rowCount) { this.rowCount = rowCount; (0,external_highcharts_src_js_default_namespaceObject.objectEach)(this.columns, (column, columnId) => { if (column.length !== rowCount) { this.columns[columnId] = DataTableCore_setLength(column, rowCount); } }); } /** * Delete rows. Simplified version of the full * `DataTable.deleteRows` method. * * @sample highcharts/datatable/live-chart/ * Add and delete rows in a live chart * @sample highcharts/datatable/shared-with-grid/ * Chart with data table CRUD operations * * @function Highcharts.DataTable#deleteRows * * @param {number} rowIndex * The start row index * * @param {number} [rowCount=1] * The number of rows to delete * * @return {void} * * @emits #afterDeleteRows */ deleteRows(rowIndex, rowCount = 1) { if (rowCount > 0 && rowIndex < this.rowCount) { let length = 0; (0,external_highcharts_src_js_default_namespaceObject.objectEach)(this.columns, (column, columnId) => { this.columns[columnId] = DataTableCore_splice(column, rowIndex, rowCount).array; length = column.length; }); this.rowCount = length; } (0,external_highcharts_src_js_default_namespaceObject.fireEvent)(this, 'afterDeleteRows', { rowIndex, rowCount }); this.versionTag = (0,external_highcharts_src_js_default_namespaceObject.uniqueKey)(); } /** * Fetches the given column by the canonical column ID. Simplified version * of the full `DataTable.getRow` method, always returning by reference. * * @function Highcharts.DataTable#getColumn * * @param {string} columnId * ID of the column to get. * * @return {Highcharts.DataTableColumn|undefined} * A copy of the column, or `undefined` if not found. */ getColumn(columnId, // eslint-disable-next-line @typescript-eslint/no-unused-vars asReference) { return this.columns[columnId]; } /** * Retrieves all or the given columns. Simplified version of the full * `DataTable.getColumns` method, always returning by reference. * * @function Highcharts.DataTable#getColumns * * @param {Array<string>} [columnIds] * Column ids to retrieve. * * @return {Highcharts.DataTableColumnCollection} * Collection of columns. If a requested column was not found, it is * `undefined`. */ getColumns(columnIds, // eslint-disable-next-line @typescript-eslint/no-unused-vars asReference) { return (columnIds || Object.keys(this.columns)).reduce((columns, columnId) => { columns[columnId] = this.columns[columnId]; return columns; }, {}); } /** * Retrieves the row at a given index. * * @function Highcharts.DataTable#getRowObject * * @param {number} rowIndex * Row index to retrieve. First row has index 0. * * @param {Array<string>} [columnNames] * Column names to retrieve. * * @return {Record<string, number|string|undefined>|undefined} * Returns the row values, or `undefined` if not found. */ getRowObject(rowIndex, columnNames) { const row = {}, columns = this.columns; columnNames ?? (columnNames = Object.keys(this.columns)); for (const columnName of columnNames) { row[columnName] = columns[columnName]?.[rowIndex]; } return row; } /** * Sets cell values for a column. Will insert a new column, if not found. * * @function Highcharts.DataTable#setColumn * * @param {string} columnId * Column name to set. * * @param {Highcharts.DataTableColumn} [column] * Values to set in the column. * * @param {number} [rowIndex] * Index of the first row to change. (Default: 0) * * @param {Record<string, (boolean|number|string|null|undefined)>} [eventDetail] * Custom information for pending events. * * @emits #setColumns * @emits #afterSetColumns */ setColumn(columnId, column = [], rowIndex = 0, eventDetail) { this.setColumns({ [columnId]: column }, rowIndex, eventDetail); } /** * Sets cell values for multiple columns. Will insert new columns, if not * found. Simplified version of the full `DataTable.setColumns`, limited * to full replacement of the columns (undefined `rowIndex`). * * @sample highcharts/datatable/shared-with-grid/ * Chart with data table CRUD operations * * @function Highcharts.DataTable#setColumns * * @param {Highcharts.DataTableColumnCollection} columns * Columns as a collection, where the keys are the column names. * * @param {number} [rowIndex] * Index of the first row to change. Ignored in the simplified `DataTable`, * as it always replaces the full column. * * @param {Record<string, (boolean|number|string|null|undefined)>} [eventDetail] * Custom information for pending events. * * @emits #setColumns * @emits #afterSetColumns */ setColumns(columns, rowIndex, eventDetail) { let rowCount = this.rowCount; (0,external_highcharts_src_js_default_namespaceObject.objectEach)(columns, (column, columnId) => { this.columns[columnId] = column.slice(); rowCount = column.length; }); this.applyRowCount(rowCount); if (!eventDetail?.silent) { (0,external_highcharts_src_js_default_namespaceObject.fireEvent)(this, 'afterSetColumns'); this.versionTag = (0,external_highcharts_src_js_default_namespaceObject.uniqueKey)(); } } /** * Sets cell values of a row. Will insert a new row if no index was * provided, or if the index is higher than the total number of table rows. * A simplified version of the full `DateTable.setRow`, limited to objects. * * @sample highcharts/datatable/live-chart/ * Add and delete rows in a live chart * @sample stock/datatable/live-candlestick/ * Live candlestick * @sample highcharts/datatable/shared-with-grid/ * Chart with data table CRUD operations * * @function Highcharts.DataTable#setRow * * @param {Record<string, number|string|undefined>} row * Cell values to set. * * @param {number} [rowIndex] * Index of the row to set. Leave `undefined` to add as a new row. * * @param {boolean} [insert] * Whether to insert the row at the given index, or to overwrite the row. * * @param {Record<string, (boolean|number|string|null|undefined)>} [eventDetail] * Custom information for pending events. * * @emits #afterSetRows */ setRow(row, rowIndex = this.rowCount, insert, eventDetail) { var _a; const { columns } = this, indexRowCount = insert ? this.rowCount + 1 : rowIndex + 1, rowKeys = Object.keys(row); if (eventDetail?.addColumns !== false) { for (let i = 0, iEnd = rowKeys.length; i < iEnd; i++) { columns[_a = rowKeys[i]] || (columns[_a] = new Array(this.rowCount)); } } (0,external_highcharts_src_js_default_namespaceObject.objectEach)(columns, (column, columnId) => { if (column) { if (insert) { column = DataTableCore_splice(column, rowIndex, 0, true, [row[columnId]]).array; } else { column[rowIndex] = // Preserve explicit null and undefined but fall back // to existing value if the new row does not have the // key columnId in row ? row[columnId] : column[rowIndex]; } columns[columnId] = column; } }); this.applyRowCount(Math.max(indexRowCount, this.rowCount)); if (!eventDetail?.silent) { (0,external_highcharts_src_js_default_namespaceObject.fireEvent)(this, 'afterSetRows', { rowIndex }); this.versionTag = (0,external_highcharts_src_js_default_namespaceObject.uniqueKey)(); } } /** * Returns the modified (clone) or the original data table if the modified * one does not exist. * * @return {Highcharts.DataTable} * The modified (clone) or the original data table. */ getModified() { return this.modified || this; } } /* * * * Default Export * * */ /* harmony default export */ const Data_DataTableCore = (DataTableCore); /* * * * API Declarations * * */ /** * A collection of data table columns defined by a object where the key is the * column ID and the value is an array of the column values. Typed arrays are * supported. * * @type {Highcharts.DataTableColumnCollection|undefined} * @apioption dataTable.columns */ /** * Custom ID to identify the new DataTable instance. * * @type {string|undefined} * @apioption dataTable.id */ /** * A typed array. * @typedef {Int8Array|Uint8Array|Uint8ClampedArray|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array} Highcharts.TypedArray */ /** * A column of values in a data table. * @typedef {Array<boolean|null|number|string|undefined>|Highcharts.TypedArray} Highcharts.DataTableColumn */ /** * A collection of data table columns defined by a object where the key is the * column ID and the value is an array of the column values. Typed arrays are * supported. * @typedef {Record<string, Highcharts.DataTableColumn>} Highcharts.DataTableColumnCollection */ /** * Options for the `DataTable` or `DataTableCore` classes. * @interface Highcharts.DataTableOptionsObject */ /** * The column options for the data table. The columns are defined by an object * where the key is the column ID and the value is an array of the column * values. * * @name Highcharts.DataTableOptionsObject.columns * @type {Highcharts.DataTableColumnCollection|undefined} */ /** * Custom ID to identify the new DataTable instance. * * @name Highcharts.DataTableOptionsObject.id * @type {string|undefined} */ (''); // Keeps doclets above in JS file ;// ./code/es-modules/Data/DataTable.js /* * * * (c) 2009-2026 Highsoft AS * * Integration of this software requires a license. * - For commercial use, see www.highcharts.com/license * - For non-commercial, see www.highcharts.com/license-eula * * * Authors: * - Sophie Bremer * - Gøran Slettemark * - Jomar Hønsi * - Dawid Draguła * * */ const { splice: DataTable_splice, setLength: DataTable_setLength } = Data_ColumnUtils; /* * * * Class * * */ /** * Class to manage columns and rows in a table structure. It provides methods * to add, remove, and manipulate columns and rows, as well as to retrieve data * from specific cells. * * @class * @name Highcharts.DataTable * * @param {Highcharts.DataTableOptionsObject} [options] * Options to initialize the new DataTable instance. */ class DataTable extends Data_DataTableCore { /* * * * Constructor * * */ constructor(options = {}) { super(options); this.metadata = options.metadata; } /* * * * Functions * * */ /** * Returns a clone of this table. The cloned table is completely independent * of the original, and any changes made to the clone will not affect * the original table. * * @function Highcharts.DataTable#clone * * @param {boolean} [skipColumns] * Whether to clone columns or not. * * @param {Highcharts.DataTableEventDetail} [eventDetail] * Custom information for pending events. * * @return {Highcharts.DataTable} * Clone of this data table. * * @emits #cloneTable * @emits #afterCloneTable */ clone(skipColumns, eventDetail) { const table = this, tableOptions = {}; table.emit({ type: 'cloneTable', detail: eventDetail }); if (!skipColumns) { tableOptions.columns = table.columns; } if (!table.autoId) { tableOptions.id = table.id; } const tableClone = new DataTable(tableOptions); if (!skipColumns) { tableClone.versionTag = table.versionTag; tableClone.originalRowIndexes = table.originalRowIndexes; tableClone.localRowIndexes = table.localRowIndexes; } tableClone.metadata = { ...table.metadata }; table.emit({ type: 'afterCloneTable', detail: eventDetail, tableClone }); return tableClone; } /** * Deletes columns from the table. * * @function Highcharts.DataTable#deleteColumns * * @param {Array<string>} [columnIds] * Names of columns to delete. If no array is provided, all * columns will be deleted. * * @param {Highcharts.DataTableEventDetail} [eventDetail] * Custom information for pending events. * * @return {Highcharts.DataTableColumnCollection|undefined} * Returns the deleted columns, if found. * * @emits #deleteColumns * @emits #afterDeleteColumns */ deleteColumns(columnIds, eventDetail) { const table = this, columns = table.columns, deletedColumns = {}, modifiedColumns = {}, modifier = table.modifier, rowCount = table.rowCount; columnIds = (columnIds || Object.keys(columns)); if (columnIds.length) { table.emit({ type: 'deleteColumns', columnIds, detail: eventDetail }); for (let i = 0, iEnd = columnIds.length, column, columnId; i < iEnd; ++i) { columnId = columnIds[i]; column = columns[columnId]; if (column) { deletedColumns[columnId] = column; modifiedColumns[columnId] = new Array(rowCount); } delete columns[columnId]; } if (!Object.keys(columns).length) { table.rowCount = 0; this.deleteRowIndexReferences(); } if (modifier) { modifier.modifyTable(table); } table.emit({ type: 'afterDeleteColumns', columns: deletedColumns, columnIds, detail: eventDetail }); return deletedColumns; } } /** * Deletes the row index references. This is useful when the original table * is deleted, and the references are no longer needed. This table is * then considered an original table or a table that has the same rows * order as the original table. */ deleteRowIndexReferences() { delete this.originalRowIndexes; delete this.localRowIndexes; } /** * Deletes rows in this table. * * @function Highcharts.DataTable#deleteRows * * @param {number | number[]} [rowIndex] * Index of the row where deletion should start, or an array of indices for * deleting multiple rows. If not specified, all rows will be deleted. * * @param {number} [rowCount] * Number of rows to delete. * * @param {Highcharts.DataTableEventDetail} [eventDetail] * Custom information for pending events. * * @return {Array<Highcharts.DataTableRow>} * Returns the deleted rows, if found. * * @emits #deleteRows * @emits #afterDeleteRows */ deleteRows(rowIndex, rowCount = 1, eventDetail) { const { columns, modifier } = this; const deletedRows = []; let indices; let actualRowCount; if (!(0,external_highcharts_src_js_default_namespaceObject.defined)(rowIndex)) { // No index provided - delete all rows. indices = [0]; actualRowCount = this.rowCount; } else if (Array.isArray(rowIndex)) { // Array of indices provided - delete the specified rows. indices = rowIndex // Remove negative indices, and indices beyond the row count, // and remove duplicates. .filter((index, i, arr) => (index >= 0 && index < this.rowCount && arr.indexOf(index) === i)) // Sort indices in descending order. .sort((a, b) => b - a); actualRowCount = indices.length; } else { // Single index provided - delete the specified range of rows. indices = [rowIndex]; actualRowCount = rowCount; } this.emit({ type: 'deleteRows', detail: eventDetail, rowCount: actualRowCount, rowIndex: rowIndex ?? 0 }); if (actualRowCount > 0) { const columnIds = Object.keys(columns); for (let i = 0; i < columnIds.length; ++i) { const columnId = columnIds[i]; const column = columns[columnId]; let deletedCells; // Perform a range splice. if (indices.length === 1 && actualRowCount > 1) { const result = DataTable_splice(column, indices[0], actualRowCount); deletedCells = result.removed; columns[columnId] = result.array; } else { // Perform a index splice for each index in the array. deletedCells = []; for (const index of indices) { deletedCells.push(column[index]); DataTable_splice(column, index, 1); } // Reverse the deleted cells to maintain the correct order. deletedCells.reverse(); } if (!i) { this.rowCount = column.length; } for (let j = 0, jEnd = deletedCells.length; j < jEnd; ++j) { deletedRows[j] = deletedRows[j] || []; deletedRows[j][i] = deletedCells[j]; } } } if (modifier) { modifier.modifyTable(this); } this.emit({ type: 'afterDeleteRows', detail: eventDetail, rowCount: actualRowCount, rowIndex: rowIndex ?? 0, rows: deletedRows }); return deletedRows; } /** * Emits an event on this table to all registered callbacks of the given * event. * @private * * @param {Event} e * Event object with event information. */ emit(e) { if ([ 'afterDeleteColumns', 'afterDeleteRows', 'afterSetCell', 'afterSetColumns', 'afterSetRows' ].includes(e.type)) { this.versionTag = (0,external_highcharts_src_js_default_namespaceObject.uniqueKey)(); } (0,external_highcharts_src_js_default_namespaceObject.fireEvent)(this, e.type, e); } /** * Fetches a single cell value. * * @function Highcharts.DataTable#getCell * * @param {string} columnId * Column name of the cell to retrieve. * * @param {number} rowIndex * Row index of the cell to retrieve. * * @return {Highcharts.DataTableCellType|undefined} * Returns the cell value or `undefined`. */ getCell(columnId, rowIndex) { const table = this; const column = table.columns[columnId]; if (column) { return column[rowIndex]; } } /** * Fetches the given column by the canonical column name. * This function is a simplified wrap of {@link getColumns}. * * @function Highcharts.DataTable#getColumn * * @param {string} columnId * Name of the column to get. * * @param {boolean} [asReference] * Whether to return the column as a readonly reference. * * @return {Highcharts.DataTableColumn|undefined} * A copy of the column, or `undefined` if not found. */ getColumn(columnId, asReference) { return this.getColumns([columnId], asReference)[columnId]; } /** * Fetches all column IDs. * * @function Highcharts.DataTable#getColumnIds * * @return {Array<string>} * Returns all column IDs. */ getColumnIds() { return Object.keys(this.columns); } /** * Retrieves all or the given columns. * * @function Highcharts.DataTable#getColumns * * @param {Array<string>} [columnIds] * Column names to retrieve. * * @param {boolean} [asReference] * Whether to return columns as a readonly reference. * * @param {boolean} [asBasicColumns] * Whether to transform all typed array columns to normal arrays. * * @return {Highcharts.DataTableColumnCollection} * Collection of columns. If a requested column was not found, it is * `undefined`. */ getColumns(columnIds, asReference, asBasicColumns) { const table = this, tableColumns = table.columns, columns = {}; columnIds = (columnIds || Object.keys(tableColumns)); for (let i = 0, iEnd = columnIds.length, column, columnId; i < iEnd; ++i) { columnId = columnIds[i]; column = tableColumns[columnId]; if (column) { if (asReference) { columns[columnId] = column; } else if (asBasicColumns && !Array.isArray(column)) { columns[columnId] = Array.from(column); } else { columns[columnId] = column.slice(); } } } return columns; } /** * Takes the original row index and returns the local row index in the * modified table for which this function is called. * * @param {number} originalRowIndex * Original row index to get the local row index for. * * @return {number|undefined} * Returns the local row index or `undefined` if not found. */ getLocalRowIndex(originalRowIndex) { const { localRowIndexes } = this; if (localRowIndexes) { return localRowIndexes[originalRowIndex]; } return originalRowIndex; } /** * Returns the modifier associated with this table, if any. * * @return {Highcharts.DataModifier|undefined} * Returns the modifier or `undefined`. * * @private */ getModifier() { return this.modifier; } /** * Takes the local row index and returns the index of the corresponding row * in the original table. * * @param {number} rowIndex * Local row index to get the original row index for. * * @return {number|undefined} * Returns the original row index or `undefined` if not found. */ getOriginalRowIndex(rowIndex) { const { originalRowIndexes } = this; if (originalRowIndexes) { return originalRowIndexes[rowIndex]; } return rowIndex; } /** * Retrieves the row at a given index. This function is a simplified wrap of * {@link getRows}. * * @function Highcharts.DataTable#getRow * * @param {number} rowIndex * Row index to retrieve. First row has index 0. * * @param {Array<string>} [columnIds] * Column names in order to retrieve. * * @return {Highcharts.DataTableRow} * Returns the row values, or `undefined` if not found. */ getRow(rowIndex, columnIds) { return this.getRows(rowIndex, 1, columnIds)[0]; } /** * Returns the number of rows in this table. * * @function Highcharts.DataTable#getRowCount * * @return {number} * Number of rows in this table. */ getRowCount() { // @todo Implement via property getter `.length` browsers supported return this.rowCount; } /** * Retrieves the index of the first row matching a specific cell value. * * @function Highcharts.DataTable#getRowIndexBy * * @param {string} columnId * Column to search in. * * @param {Highcharts.DataTableCellType} cellValue * Cell value to search for. `NaN` and `undefined` are not supported. * * @param {number} [rowIndexOffset] * Index offset to start searching. * * @return {number|undefined} * Index of the first row matching the cell value. */ getRowIndexBy(columnId, cellValue, rowIndexOffset) { const table = this; const column = table.columns[columnId]; if (column) { let rowIndex = -1; if (Array.isArray(column)) { // Normal array rowIndex = column.indexOf(cellValue, rowIndexOffset); } else if ((0,external_highcharts_src_js_default_namespaceObject.isNumber)(cellValue)) { // Typed array rowIndex = column.indexOf(cellValue, rowIndexOffset); } if (rowIndex !== -1) { return rowIndex; } } } /** * Retrieves the row at a given index. This function is a simplified wrap of * {@link getRowObjects}. * * @function Highcharts.DataTable#getRowObject * * @param {number} rowIndex * Row index. * * @param {Array<string>} [columnIds] * Column names and their order to retrieve. * * @return {Highcharts.DataTableRowObject} * Returns the row values, or `undefined` if not found. */ getRowObject(rowIndex, columnIds) { return this.getRowObjects(rowIndex, 1, columnIds)[0]; } /** * Fetches all or a number of rows as an object. * * @function Highcharts.DataTable#getRowObjects * * @param {number} [rowIndex] * Index of the first row to fetch. Defaults to first row at index `0`. * * @param {number} [rowCount] * Number of rows to fetch. Defaults to maximal number of rows. * * @param {Array<string>} [columnIds] * Column names and their order to retrieve. * * @return {Highcharts.DataTableRowObject} * Returns retrieved rows. */ getRowObjects(rowIndex = 0, rowCount = (this.rowCount - rowIndex), columnIds) { const table = this, columns = table.columns, rows = new Array(rowCount); columnIds = (columnIds || Object.keys(columns)); for (let i = rowIndex, i2 = 0, iEnd = Math.min(table.rowCount, (rowIndex + rowCount)), column, row; i < iEnd; ++i, ++i2) { row = rows[i2] = {}; for (const columnId of columnIds) { column = columns[columnId]; row[columnId] = (column ? column[i] : void 0); } } return rows; } /** * Fetches all or a number of rows as an array. * * @function Highcharts.DataTable#getRows * * @param {number} [rowIndex] * Index of the first row to fetch. Defaults to first row at index `0`. * * @param {number} [rowCount] * Number of rows to fetch. Defaults to maximal number of rows. * * @param {Array<string>} [columnIds] * Column names and their order to retrieve. * * @return {Highcharts.DataTableRow} * Returns retrieved rows. */ getRows(rowIndex = 0, rowCount = (this.rowCount - rowIndex), columnIds) { const table = this, columns = table.columns, rows = new Array(rowCount); columnIds = (columnIds || Object.keys(columns)); for (let i = rowIndex, i2 = 0, iEnd = Math.min(table.rowCount, (rowIndex + rowCount)), column, row; i < iEnd; ++i, ++i2) { row = rows[i2] = []; for (const columnId of columnIds) { column = columns[columnId]; row.push(column ? column[i] : void 0); } } return rows; } /** * Returns the unique version tag of the current state of the table. * * @function Highcharts.DataTable#getVersionTag * * @return {string} * Unique version tag. */ getVersionTag() { return this.versionTag; } /** * Determines whether all specified column names exist in the table. * * @function Highcharts.DataTable#hasColumns * * @param {Array<string>} columnIds * Column names to check. * * @return {boolean} * Returns `true` if all columns have been found, otherwise `false`. */ hasColumns(columnIds) { const table = this, columns = table.columns; for (let i = 0, iEnd = columnIds.length, columnId; i < iEnd; ++i) { columnId = columnIds[i]; if (!columns[columnId]) { return false; } } return true; } /** * Checks if any row in the specified column contains the given cell value. * * @function Highcharts.DataTable#hasRowWith * * @param {string} columnId * Column to search in. * * @param {Highcharts.DataTableCellType} cellValue * Cell value to search for. `NaN` and `undefined` are not supported. * * @return {boolean} * True, if a row has been found, otherwise false. */ hasRowWith(columnId, cellValue) { const table = this; const column = table.columns[columnId]; // Normal array if (Array.isArray(column)) { return (column.indexOf(cellValue) !== -1); } // Typed array if ((0,external_highcharts_src_js_default_namespaceObject.defined)(cellValue) && Number.isFinite(cellValue)) { return (column.indexOf(+cellValue) !== -1); } return false; } /** * Registers a callback function to be executed when a specific event is * emitted. To stop listening to the event, call the function returned by * this method. * * @function Highcharts.DataTable#on * * @param {string} type * Event type as a string. * * @param {Highcharts.EventCallbackFunction<Highcharts.DataTable>} callback * Function to register for an event callback. * * @return {Function} * Function to unregister callback from the event. */ on(type, callback) { return (0,external_highcharts_src_js_default_namespaceObject.addEvent)(this, type, callback); } /** * Changes the ID of an existing column to a new ID, effectively renaming * the column. * * @function Highcharts.DataTable#changeColumnId * * @param {string} columnId * Id of the column to be changed. * * @param {string} newColumnId * New id of the column. * * @return {boolean} * Returns `true` if successful, `false` if the column was not found. */ changeColumnId(columnId, newColumnId) { const table = this, columns = table.columns; if (columns[columnId]) { if (columnId !== newColumnId) { columns[newColumnId] = columns[columnId]; delete columns[columnId]; } return true; } return false; } /** * Sets the value of a specific cell identified by column ID and row index. * If the column does not exist, it will be created. If the row index is * beyond the current row count, the table will be expanded to accommodate * the new cell. * * @function Highcharts.DataTable#setCell * * @param {string} columnId * Column name to set. * * @param {number|undefined} rowIndex * Row index to set. * * @param {Highcharts.DataTableCellType} cellValue * Cell value to set. * * @param {Highcharts.DataTableEventDetail} [eventDetail] * Custom information for pending events. * * @emits #setCell * @emits #afterSetCell */ setCell(columnId, rowIndex, cellValue, eventDetail) { const table = this, columns = table.columns, modifier = table.modifier; let column = columns[columnId]; if (column && column[rowIndex] === cellValue) { return; } table.emit({ type: 'setCell', cellValue, columnId: columnId, detail: eventDetail, rowIndex }); if (!column) { column = columns[columnId] = new Array(table.rowCount); } if (rowIndex >= table.rowCount) { table.rowCount = (rowIndex + 1); } column[rowIndex] = cellValue; if (modifier) { modifier.modifyTable(table); } table.emit({ type: 'afterSetCell', cellValue, columnId: columnId, detail: eventDetail, rowIndex }); } /** * Replaces or updates multiple columns in the table with new data. If a * column does not exist, it will be created and added to the table. * * @function Highcharts.DataTable#setColumns * * @param {Highcharts.DataTableColumnCollection} columns * Columns as a collection, where the keys are the column names. * * @param {number} [rowIndex] * Index of the first row to change. Keep undefined to reset. * * @param {Highcharts.DataTableEventDetail} [eventDetail] * Custom information for pending events. * * @param {boolean} [typeAsOriginal=false] * Determines whether the original column retains its type when data * replaced. If `true`, the original column keeps its type. If not * (default), the original column will adopt the type of the replacement * column. * * @emits #setColumns * @emits #afterSetColumns */ setColumns(columns, rowIndex, eventDetail, typeAsOriginal) { const table = this, tableColumns = table.columns, tableModifier = table.modifier, columnIds = Object.keys(columns); let rowCount = table.rowCount; table.emit({ type: 'setColumns', columns, columnIds, detail: eventDetail, rowIndex }); if (!(0,external_highcharts_src_js_default_namespaceObject.defined)(rowIndex) && !typeAsOriginal) { super.setColumns(columns, rowIndex, (0,external_highcharts_src_js_default_namespaceObject.extend)(eventDetail, { silent: true })); } else { for (let i = 0, iEnd = columnIds.length, column, tableColumn, columnId, ArrayConstructor; i < iEnd; ++i) { columnId = columnIds[i]; column = columns[columnId]; tableColumn = tableColumns[columnId]; ArrayConstructor = Object.getPrototypeOf((tableColumn && typeAsOriginal) ? tableColumn : column).constructor; if (!tableColumn) { tableColumn = new ArrayConstructor(rowCount); } else if (ArrayConstructor === Array) { if (!Array.isArray(tableColumn)) { tableColumn = Array.from(tableColumn); } } else if (tableColumn.length < rowCount) { tableColumn = new ArrayConstructor(rowCount); tableColumn.set(tableColumns[columnId]); } tableColumns[columnId] = tableColumn; for (let i