UNPKG

ag-charts-community

Version:

Advanced Charting / Charts supporting Javascript / Typescript / React / Angular / Vue

163 lines (162 loc) 8.19 kB
import { type DomainWithMetadata } from 'ag-charts-core'; import type { EventsHub } from '../../core/eventsHub'; import type { ChartMode } from '../chartMode'; import type { DataGroup, DataModelOptions, GroupDatumIteratorOutput, GroupedData, ProcessedData, ProcessedDataDef, PropertyDefinition, ScopeProvider, UngroupedData } from './dataModelTypes'; import type { DataChangeDescription, DataSet } from './dataSet'; import { type SortOrder } from './sortOrder'; export * from './dataModelTypes'; export { fixNumericExtent, getMissCount, datumKeys, getPathComponents, NULL_KEY_STRING, UNDEFINED_KEY_STRING, } from './data-model/utils/helpers'; /** * Transforms raw chart data into a structured, renderable format for series visualization. * * The DataModel is responsible for processing data through a multi-stage pipeline: * - Extracting and validating data from input datasets * - Grouping data by keys (for categorical axes or stacked series) * - Computing aggregations (sum, average, etc.) for grouped data * - Calculating domains (value ranges) for axes and scales * - Managing scoped data processing for multi-series charts * - Supporting incremental updates when data changes * * The class orchestrates several specialized subsystems: * - DataExtractor: Extracts and validates raw data * - DataGrouper: Groups data by keys * - Aggregator: Computes aggregations over grouped data * - DomainManager: Calculates and maintains value domains * - IncrementalProcessor: Handles efficient data updates * * Performance optimizations: * * 1. SHARED MEMORY OPTIMIZATION (groupsUnique=true): * When each datum has unique keys, all groups share the same datumIndices array * containing [0], since each datum's relative offset from its group is always 0. * * 2. BANDED DOMAIN PROCESSING: * Large datasets are divided into bands for efficient domain calculation. * Only dirty bands are recalculated during incremental updates. * * 3. BATCH MERGING: * Column batches with identical characteristics (keys, invalidity) are merged * to reduce processing overhead. * * 4. INCREMENTAL REPROCESSING: * When supported, only changed data is reprocessed instead of full recalculation. */ export declare class DataModel<D extends object, K extends keyof D & string = keyof D & string, Grouped extends boolean | undefined = undefined> { private readonly opts; private readonly mode; private readonly suppressFieldDotNotation; private readonly eventsHub?; private readonly debug; private readonly scopeCache; private readonly keys; private readonly values; private readonly resolvers; private readonly scopeCacheManager; private readonly domainInitializer; private readonly domainManager; private readonly reducerManager; private readonly dataExtractor; private readonly dataGrouper; private readonly aggregator; private readonly incrementalProcessor; private readonly aggregates; private readonly groupProcessors; private readonly propertyProcessors; private readonly reducers; private readonly processors; constructor(opts: DataModelOptions<K, Grouped, true>, mode?: ChartMode, suppressFieldDotNotation?: boolean, eventsHub?: EventsHub | undefined); resolveProcessedDataDefById(scope: ScopeProvider, searchId: string): ProcessedDataDef | never; resolveProcessedDataIndexById(scope: ScopeProvider, searchId: string): number; resolveKeysById<T = string>(scope: ScopeProvider, searchId: string, processedData: UngroupedData<any> | GroupedData<any>): T[]; hasColumnById(scope: ScopeProvider, searchId: string): boolean; resolveColumnById<T = any>(scope: ScopeProvider, searchId: string, processedData: UngroupedData<any> | GroupedData<any>): T[]; resolveColumnNeedsValueOf(scope: ScopeProvider, searchId: string, processedData: UngroupedData<any> | GroupedData<any>): boolean; resolveMissingDataCount(scope: ScopeProvider): number; /** * Provides a convenience iterator to iterate over all of the extract datum values in a * specific DataGroup. * * @param scope to which datums should belong * @param group containing the datums * @param processedData containing the group * @param groupIndex index of the group in processedData.groups */ forEachDatum(scope: ScopeProvider, processedData: GroupedData<any>, group: DataGroup, groupIndex: number): Generator<any, void, unknown>; private getUniqueDataSets; /** * Provides a convenience iterator to iterate over all of the extracted datum values in a * GroupedData. * * @param scope to which datums should belong * @param processedData to iterate through */ forEachGroupDatum(scope: ScopeProvider, processedData: GroupedData<any>): Generator<GroupDatumIteratorOutput, void, unknown>; getDomain(scope: ScopeProvider, searchId: string, type: PropertyDefinition<any>['type'], processedData: ProcessedData<K>): DomainWithMetadata<any>; getDomainBetweenRange(scope: ScopeProvider, searchIds: string[], [i0, i1]: [number, number], processedData: ProcessedData<K>): [number, number]; getKeySortOrder(scope: ScopeProvider, searchId: string, processedData: ProcessedData<K>): SortOrder; getColumnSortOrder(scope: ScopeProvider, searchId: string, processedData: ProcessedData<K>): SortOrder; /** * Get sort metadata for a key column if available. * Returns undefined if metadata is not available, is dirty, or data is unsorted. */ getKeySortMetadata(scope: ScopeProvider, searchId: string, processedData: ProcessedData<K>): { sortOrder: 1 | -1 | undefined; isUnique?: boolean; } | undefined; processData(sources: Map<string, DataSet<unknown>>): (Grouped extends true ? GroupedData<D> : UngroupedData<D>) | undefined; /** * Determines if incremental reprocessing is supported for the given data. * * Reprocessing is supported when: * - For ungrouped data: No aggregates, reducers, processors, or property processors * - For grouped data: Additionally requires: * - groupsUnique=true (each datum has unique keys) * - Single data source (all scopes share same DataSet) * - No invalid keys (to maintain groups.length === columns.length invariant) * - All group processors support reprocessing * * When unsupported, falls back to full reprocessing automatically. * * @returns true if incremental reprocessing can be used, false otherwise */ isReprocessingSupported(processedData: ProcessedData<D>): boolean; reprocessData(processedData: ProcessedData<D>, dataSets?: Map<DataSet<any>, DataChangeDescription | undefined>): ProcessedData<D>; /** * Recomputes domains from transformed arrays. * Uses BandedDomain optimization for continuous domains to avoid full rescans. */ private recomputeDomains; private warnDataMissingProperties; private processScopeCache; private valueGroupIdxLookup; private valueIdxLookup; private extractData; /** * Reprocesses group processors for incremental updates. * Only processes newly inserted groups to avoid double-processing. * This is safe only when all group processors support reprocessing. * Deduplicates change descriptions to avoid processing the same groups multiple times * when multiple scopes share the same DataSet. */ private reprocessGroupProcessors; private postProcessProperties; private reduceData; private shouldUseReducerBanding; private reduceWithBands; private reduceStandard; private postProcessData; private initDataDomainProcessor; /** * Collects optimization metadata for debugging purposes. * Only called when debug mode is enabled. */ private collectOptimizationMetadata; /** * Collects reducer banding metadata for debugging purposes. * Tracks which reducers used banding and their performance stats. */ private collectReducerBandingMetadata; buildAccessors(defs: Iterable<{ property: string; }>): Map<string, (d: any) => any>; }