UNPKG

highcharts

Version:
269 lines (268 loc) 7.53 kB
/* * * * (c) 2009-2026 Highsoft AS * * A commercial license may be required depending on use. * See www.highcharts.com/license * * * Authors: * - Sophie Bremer * * */ 'use strict'; import DataConnector from './Connectors/DataConnector.js'; import { addEvent, fireEvent, merge } from '../Shared/Utilities.js'; /* * * * Class * * */ /** * Data pool to load connectors on-demand. * * @class * @name Data.DataPool * * @param {DataPoolOptions} options * Pool options with all connectors. */ class DataPool { /* * * * Constructor * * */ constructor(options) { this.options = merge(DataPool.defaultOptions, options); this.connectors = {}; this.waiting = {}; } /* * * * Methods * * */ /** * Emits an event on this data pool to all registered callbacks of the given * event. * * @param {DataTableEvent} e * Event object with event information. */ emit(e) { fireEvent(this, e.type, e); } /** * Loads the connector. * * @function Data.DataPool#getConnector * * @param {string} connectorId * ID of the connector. * * @return {Promise<Data.DataConnectorType>} * Returns the connector. */ getConnector(connectorId) { const connector = this.connectors[connectorId]; // Already loaded if (connector?.loaded) { return Promise.resolve(connector); } let waitingList = this.waiting[connectorId]; // Start loading if (!waitingList) { waitingList = this.waiting[connectorId] = []; const connectorOptions = this.getConnectorOptions(connectorId); if (!connectorOptions) { throw new Error(`Connector '${connectorId}' not found.`); } // eslint-disable-next-line @typescript-eslint/no-floating-promises this .loadConnector(connectorOptions) .then((connector) => { delete this.waiting[connectorId]; for (let i = 0, iEnd = waitingList.length; i < iEnd; ++i) { waitingList[i][0](connector); } })['catch']((error) => { delete this.waiting[connectorId]; for (let i = 0, iEnd = waitingList.length; i < iEnd; ++i) { waitingList[i][1](error); } }); } // Add request to waiting list return new Promise((resolve, reject) => { waitingList.push([resolve, reject]); }); } /** * Returns the IDs of all connectors. * * @private * * @return {Array<string>} * Names of all connectors. */ getConnectorIds() { const connectors = this.options.connectors, connectorIds = []; for (let i = 0, iEnd = connectors.length; i < iEnd; ++i) { connectorIds.push(connectors[i].id); } return connectorIds; } /** * Loads the options of the connector. * * @private * * @param {string} connectorId * ID of the connector. * * @return {DataConnectorTypeOptions | undefined} * Returns the options of the connector, or `undefined` if not found. */ getConnectorOptions(connectorId) { const connectors = this.options.connectors; for (let i = 0, iEnd = connectors.length; i < iEnd; ++i) { if (connectors[i].id === connectorId) { return connectors[i]; } } } /** * Tests whether the connector has never been requested. * * @param {string} connectorId * Name of the connector. * * @return {boolean} * Returns `true`, if the connector has never been requested, otherwise * `false`. */ isNewConnector(connectorId) { return !this.connectors[connectorId]; } /** * Instantiates the connector class for the given options and loads its * data. * * @private * * @param {Data.DataPoolConnectorOptions} options * Options of connector. * * @return {Promise<Data.DataConnectorType>} * Returns the connector. */ loadConnector(options) { return new Promise((resolve, reject) => { this.emit({ type: 'load', options }); const ConnectorClass = DataConnector.types[options.type]; if (!ConnectorClass) { throw new Error(`Connector type not found. (${options.type})`); } const connector = this.connectors[options.id] = new ConnectorClass(options); // eslint-disable-next-line @typescript-eslint/no-floating-promises connector .load() .then(({ converter }) => { connector.converter = converter; connector.loaded = true; this.emit({ type: 'afterLoad', options }); resolve(connector); })['catch'](reject); }); } /** * Cancels all data connectors pending requests. */ cancelPendingRequests() { const { connectors } = this; for (const connectorKey of Object.keys(connectors)) { connectors[connectorKey].stopPolling(); } } /** * Registers a callback for a specific event. * * @function Highcharts.DataPool#on * * @param {string} type * Event type as a string. * * @param {Highcharts.EventCallbackFunction<Highcharts.DataPool>} callback * Function to register for an event callback. * * @return {Function} * Function to unregister callback from the event. */ on(type, callback) { return addEvent(this, type, callback); } /** * Sets connector options under the specified `options.id`. * * @param {object} options * Connector options to set. * * @param {boolean} [update] * Whether to update the existing connector with the new options and reload * it (`true`) or replace it with a new connector instance (`false`). */ async setConnectorOptions(options, update) { const connectorsOptions = this.options.connectors; const connectorsInstances = this.connectors; this.emit({ type: 'setConnectorOptions', options }); for (let i = 0, iEnd = connectorsOptions.length; i < iEnd; ++i) { if (connectorsOptions[i].id === options.id) { connectorsOptions.splice(i, 1); break; } } let existingConnector = connectorsInstances[options.id]; if (existingConnector) { if (update) { await existingConnector.update(options, true); } else { existingConnector.stopPolling(); existingConnector = void 0; delete connectorsInstances[options.id]; } } if (!existingConnector) { connectorsOptions.push(options); } this.emit({ type: 'afterSetConnectorOptions', options }); } } /* * * * Static Properties * * */ DataPool.defaultOptions = { connectors: [] }; /* * * * Default Export * * */ export default DataPool;