UNPKG

ag-charts-community

Version:

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

411 lines (410 loc) 23.6 kB
import type { BoxBounds, ChartAnimationPhase, DomainWithMetadata, DynamicContext, NormalisedColorType, NormalisedSeriesMarkerStyle, NormalisedTextOrSegments, PlacedLabel, PointLabelDatum } from 'ag-charts-core'; import { type Callback, type CallbackParam, ChartAxisDirection, CleanupRegistry, type DistantObject, EventEmitter, LRUCache, type Point, type RequireOptional, type SeriesPluginModuleInstance } from 'ag-charts-core'; import type { AgActiveItemState, AgChartLabelFormatterParams, AgDrawingMode, AgInitialStateLegendOptions, AgNumericValue, AgSeriesTooltipRendererParams, AgSeriesVisibilityChange, FormatterPropertyType, HighlightState as PublicHighlightState, SelectionState as PublicSelectionState, SeriesType } from 'ag-charts-types'; import type { HighlightChangeEvent, HighlightNodeDatum, LegendItemClickEvent, LegendItemDoubleClickEvent } from '../../core/eventsHub'; import type { AxisFormattableLabel } from '../../module/axisContext'; import type { ChartRegistry, ChartSeriesRegistry } from '../../module/moduleContext'; import { ModuleMap } from '../../module/moduleMap'; import type { SeriesGrouping } from '../../module/seriesGrouping'; import { BBox } from '../../scene/bbox'; import { Group, TranslatableGroup } from '../../scene/group'; import { type Node } from '../../scene/node'; import type { Selection } from '../../scene/selection'; import type { Path } from '../../scene/shape/path'; import type { TypedEvent, TypedEventListener } from '../../util/observable'; import { Observable } from '../../util/observable'; import type { ChartAxis } from '../chartAxis'; import type { ChartMode } from '../chartMode'; import type { DataController } from '../data/dataController'; import type { DataModel, ProcessedData } from '../data/dataModel'; import { DataSet } from '../data/dataSet'; import type { ChartLegendDatum, ChartLegendType } from '../legend/legendDatum'; import type { Marker } from '../marker/marker'; import type { TooltipContent, TooltipStructuredContent } from '../tooltip/tooltip'; import type { SeriesMarker } from './seriesMarker'; import type { SeriesProperties } from './seriesProperties'; import type { SeriesTooltip } from './seriesTooltip'; import { type BucketLookupFeature, type DatumIndex, HighlightState, type INodeEvent, type ISeries, type ISeriesProperties, type NodeDataDependencies, SelectionState, type SeriesNodeDatum, type SeriesNodeEventTypes } from './seriesTypes'; import { type ShapeFillBBox } from './shapeUtil'; export interface SeriesDataEvent { readonly dataModel: DataModel<any, any, any>; readonly processedData: ProcessedData<any>; } /** Modes of matching user interactions to rendered nodes (e.g. hover or click) */ export declare enum SeriesNodePickMode { /** Pick matches based upon pick coordinates being inside a matching shape/marker. */ EXACT_SHAPE_MATCH = 0, /** Pick matches based upon distance to ideal position */ NEAREST_NODE = 1, /** Pick matches based upon distance from axis */ AXIS_ALIGNED = 2 } export type SeriesNodePickIntent = 'tooltip' | 'highlight' | 'highlight-tooltip' | 'context-menu' | 'event'; export type SeriesNodePickMatch = { datum: SeriesNodeDatum; distance: number; }; export type PickFocusInputs = { readonly datumIndex: number; readonly datumIndexDelta: number; readonly otherIndex: number; readonly otherIndexDelta: number; readonly seriesRect?: BBox; }; export type PickViewportFocusInputs = { readonly otherIndex: number; readonly where: 'data-start' | 'data-end' | 'viewport-start' | 'viewport-end'; readonly hoverRect: Readonly<BoxBounds>; }; export type PickFocusOutputs = { datumIndex: number; datum: SeriesNodeDatum; otherIndex?: number; bounds: BBox | Path; movedBounds?: BBox; clipFocusBox: boolean; }; export type PickResult = { pickMode: SeriesNodePickMode; datums: SeriesNodeDatum[]; distance: number; }; export type PickNodesInBBoxPredicate = (selectionBox: BoxBounds, node: Node<unknown>) => boolean; export type INodeEventConstructor<TDatum extends SeriesNodeDatum, TSeries extends Series<TDatum, object, any>, TEvent extends string = SeriesNodeEventTypes> = new <T extends TEvent>(type: T, event: Event, nodeDatum: TDatum, series: TSeries, selectionState: PublicSelectionState | undefined) => INodeEvent<T>; export declare class SeriesNodeEvent<TDatum extends SeriesNodeDatum, TEvent extends string = SeriesNodeEventTypes> implements INodeEvent<TEvent> { readonly type: TEvent; readonly event: Event; readonly datum: unknown; readonly datums?: unknown[]; readonly totalValue?: AgNumericValue; readonly seriesId: string; readonly itemId: string | number; readonly dataIdKey: string | undefined; readonly selectionState: PublicSelectionState | undefined; defaultPrevented: boolean; constructor(type: TEvent, event: Event, nodeDatum: TDatum, series: ISeries<TDatum, ISeriesProperties, unknown>, selectionState: PublicSelectionState | undefined); preventDefault(): void; } export type SeriesNodeDataContext<S = SeriesNodeDatum, L = S> = { itemId: string; nodeData: S[]; labelData: L[]; }; export type SeriesNodeStyleContext<TStyle> = { [HighlightState.None]: TStyle; [HighlightState.Item]: TStyle; [HighlightState.Series]: TStyle; [HighlightState.OtherSeries]: TStyle; [HighlightState.OtherItem]: TStyle; }; /** Cache-miss callback for `runMarkerStylePass` — computes a value keyed by (highlight, selection[, keyExtra]). */ export type MarkerStyleCompute<TSeries, TCtx, TDatum, TCache> = (this: void, series: TSeries, ctx: TCtx, highlightState: HighlightState, selectionState: SelectionState | undefined, datum: TDatum) => TCache; /** Per-non-garbage-datum callback for `runMarkerStylePass`. */ export type MarkerStyleApply<TSeries, TCtx, TDatum, TCache> = (this: void, series: TSeries, ctx: TCtx, datum: TDatum, highlightState: HighlightState, selectionState: SelectionState | undefined, cached: TCache) => void; export type SeriesDirectionKeysMapping<P extends SeriesProperties<any>> = { [key in ChartAxisDirection | FormatterPropertyType]?: (keyof P & string)[]; }; export declare class SeriesGroupingChangedEvent implements TypedEvent { series: Series<any, object, any>; seriesGrouping: SeriesGrouping | undefined; type: string; constructor(series: Series<any, object, any>, seriesGrouping: SeriesGrouping | undefined); } export type SeriesConstructorOpts<TProps extends SeriesProperties<any>> = { moduleCtx: DynamicContext<ChartRegistry>; pickModes: SeriesNodePickMode[]; propertyKeys?: SeriesDirectionKeysMapping<TProps>; propertyNames?: SeriesDirectionKeysMapping<TProps>; canHaveAxes?: boolean; usesPlacedLabels?: boolean; alwaysClip?: boolean; supportsStandaloneZoom?: boolean; }; export type UnknownSeries = Series<SeriesNodeDatum, object, SeriesProperties<object>>; export declare abstract class Series<TDatum extends SeriesNodeDatum, TOpts extends object, TProps extends SeriesProperties<TOpts>, TLabel = TDatum, TContext extends SeriesNodeDataContext<TDatum, TLabel> = SeriesNodeDataContext<TDatum, TLabel>> extends Observable implements ISeries<TDatum, TProps, TLabel> { static readonly className: string; protected cleanup: CleanupRegistry; abstract readonly properties: TProps; pickModes: SeriesNodePickMode[]; usesPlacedLabels: boolean; readonly alwaysClip: boolean; /** Opts into StandaloneChart zoom (axis registration + scale/translate viewport). */ readonly supportsStandaloneZoom: boolean; protected hasChangesOnHighlight: boolean; protected hasChangesOnSelection: boolean; get pickModeAxis(): 'main' | 'main-category' | undefined; seriesGrouping: SeriesGrouping | undefined; protected readonly NodeEvent: INodeEventConstructor<TDatum, any>; readonly internalId: string; get id(): string; readonly canHaveAxes: boolean; get type(): SeriesType; readonly contentGroup: TranslatableGroup<unknown>; readonly highlightGroup: TranslatableGroup<unknown>; readonly highlightNodeGroup: Group<TDatum>; readonly highlightLabelGroup: Group<TLabel>; readonly annotationGroup: TranslatableGroup<unknown>; readonly labelGroup: TranslatableGroup<TLabel>; chart?: { mode: ChartMode; isMiniChart: boolean; flashOnUpdateEnabled: boolean; seriesRect?: BBox; }; axes: { [K in ChartAxisDirection]?: ChartAxis; }; directions: ChartAxisDirection[]; private readonly propertyKeys; private readonly propertyNames; protected nodeDataRefresh: boolean; protected processedDataUpdated: boolean; protected readonly moduleMap: ModuleMap<SeriesPluginModuleInstance>; protected _data?: DataSet<any>; protected _chartData?: DataSet<any>; private _dataConnected; private readonly datumCallbackCache; connectsToYAxis: boolean; get focusable(): boolean; get data(): DataSet<any> | undefined; set visible(newVisibility: boolean); get visible(): boolean; get hasData(): boolean; get tooltipEnabled(): boolean | undefined; protected onDataChange(): void; setOptionsData(input: DataSet | undefined): void; isHighlightEnabled(): boolean; isSelectionEnabled(): boolean; isDatumSelectable(_datumIndex: DatumIndex): boolean; setChartData(input: DataSet | undefined): void; private onSeriesGroupingChange; getBandScalePadding(): { inner: number; outer: number; }; readonly ctx: DynamicContext<ChartRegistry>; private moduleContext?; constructor(seriesOpts: SeriesConstructorOpts<TProps>); attachSeries(seriesContentNode: Group, seriesNode: Group, annotationNode: Group | undefined): void; detachSeries(_seriesContentNode: Group | undefined, _seriesNode: Group, _annotationNode: Group | undefined): void; declarationOrder: number; private _broughtToFront; setSeriesIndex(index: number, forceUpdate?: boolean): boolean; setZIndex(zIndex: number): void; renderToOffscreenCanvas(): boolean; disconnectData(): void; reconnectData(): void; protected hasHighlightOpacity(): boolean; protected getDrawingMode(isHighlight?: boolean, highlightDrawingMode?: AgDrawingMode): AgDrawingMode; protected getAnimationDrawingModes(): { start: { drawingMode: AgDrawingMode; }; finish: { drawingMode: AgDrawingMode; }; }; readonly events: EventEmitter<{ 'data-update': SeriesDataEvent; 'data-processed': SeriesDataEvent; 'data-selection-change': null; }>; addEventListener(type: 'seriesVisibilityChange', listener: (e: AgSeriesVisibilityChange) => void): void; addEventListener(type: 'seriesNodeClick', listener: (e: SeriesNodeEvent<any>) => void): void; addEventListener(type: 'seriesNodeDoubleClick', listener: (e: SeriesNodeEvent<any>) => void): void; addEventListener(type: string, listener: TypedEventListener): void; removeEventListener(type: 'seriesVisibilityChange', listener: (e: AgSeriesVisibilityChange) => void): void; removeEventListener(type: 'seriesNodeClick', listener: (e: SeriesNodeEvent<any>) => void): void; removeEventListener(type: 'seriesNodeDoubleClick', listener: (e: SeriesNodeEvent<any>) => void): void; removeEventListener(type: string, listener: TypedEventListener): void; hasEventListener(type: 'seriesVisibilityChange'): boolean; hasEventListener(type: 'seriesNodeClick'): boolean; hasEventListener(type: 'seriesNodeDoubleClick'): boolean; hasEventListener(type: string): boolean; updatedDomains(): void; destroy(): void; abstract resetAnimation(chartAnimationPhase: ChartAnimationPhase): void; private getPropertyValues; getKeyAxis(_direction: ChartAxisDirection): string | undefined; getKeys(direction: ChartAxisDirection): string[]; getKeyProperties(direction: ChartAxisDirection): (keyof TProps & string)[]; getNames(direction: ChartAxisDirection): (string | undefined)[]; getFormatterContext(property: FormatterPropertyType): Array<{ seriesId: string; key: string; name: string | undefined; }>; resolveKeyDirection(direction: ChartAxisDirection): ChartAxisDirection; getDomain(direction: ChartAxisDirection): DomainWithMetadata<any>; getRange(direction: ChartAxisDirection, visibleRange: [number, number]): [number, number] | []; getMinimumRangeSeries(_range: number[]): void; getMinimumRangeChart(_ranges: number[]): number; getZoomRangeFittingItems(_xVisibleRange: [number, number], _yVisibleRange: [number, number] | undefined, _minVisibleItems: number): { x: [number, number]; y: [number, number] | undefined; } | undefined; getVisibleItems(_xVisibleRange: [number, number], _yVisibleRange: [number, number] | undefined, _minVisibleItems: number): number; abstract dataCount(): number; abstract getSeriesDomain(direction: ChartAxisDirection): DomainWithMetadata<any>; abstract getSeriesRange(direction: ChartAxisDirection, visibleRange: [number, number]): [number, number] | []; abstract processData(dataController: DataController): Promise<void> | void; abstract createNodeData(): TContext | undefined; abstract findNodeDatum(itemIdOrIndex: AgActiveItemState['itemId']): SeriesNodeDatum | undefined; toCanvasFromMidPoint(nodeDatum: { midPoint?: Point; }): Point; markNodeDataDirty(): void; private visibleMaybeChanged; abstract update(opts: { seriesRect?: BBox; }): Promise<void> | void; getOpacity(): number; getHighlightState(highlightedDatum: HighlightNodeDatum | undefined, isHighlight?: boolean, datumIndex?: DatumIndex, legendItemValues?: string[]): HighlightState; getDataSelectionState(datumIndex: DatumIndex | undefined): SelectionState | undefined; getDataCandidacyState(datumIndex: DatumIndex | undefined): SelectionState | undefined; /** * Per-series aggregation-aware bucket lookup. Optional — populated * lazily for aggregating series only. Owns both the per-bucket SELECTED * roll-up and the bucket→datum-range mapping used by the data-selection * drag handler. `DataModelSeries.getDataSelectionState` consults this * for marker styling; `data-selection-change` and aggregation rebuilds * keep the roll-up in sync. */ protected bucketLookup?: BucketLookupFeature; /** * Construct the series-specific {@link BucketLookupFeature}. Default * `undefined` for non-aggregating series. Aggregating series override to * return either {@link BucketLookupManager} (single `indexData`) or * {@link SplitBucketLookupManager} (split positive/negative). */ protected createBucketLookupFeature(): BucketLookupFeature | undefined; /** * Lazy-init `bucketLookup` on first access. The just-created feature is * refreshed once so it reflects the current selection bitset and * aggregation filters — without this any `filtersChanged` events emitted * before the lazy-init would have been missed. */ ensureBucketLookupFeature(): BucketLookupFeature | undefined; getHighlightStateString(datum: HighlightNodeDatum | undefined, isHighlight?: boolean, datumIndex?: DatumIndex, legendItemValues?: string[]): PublicHighlightState; getSelectionStateString(datumIndex: DatumIndex | undefined, selectionState?: SelectionState): PublicSelectionState | undefined; getCandidateStateString(datumIndex: DatumIndex | undefined, candidateState?: SelectionState): PublicSelectionState | undefined; protected onChangeHighlight(event: HighlightChangeEvent): void; bringToFront(): boolean; isSeriesHighlighted(highlightedDatum: HighlightNodeDatum | undefined, _legendItemValues?: string[]): boolean; protected isItemHighlighted(highlightedDatum?: HighlightNodeDatum, datumIndex?: DatumIndex): boolean | undefined; private hasDataSelection; getHighlightStyle(isHighlight?: boolean, datumIndex?: DatumIndex, highlightState?: HighlightState, legendItemValues?: string[]): Partial<TOpts & { fill: NormalisedColorType; fillOpacity: number; stroke: string; strokeWidth: number; strokeOpacity: number; lineDash: number[]; lineDashOffset: number; opacity: number; }>; getSelectionStyle(datumIndex?: DatumIndex, selectionState?: SelectionState, candidateState?: SelectionState): Partial<TOpts & { fill: NormalisedColorType; fillOpacity: number; stroke: string; strokeWidth: number; strokeOpacity: number; lineDash: number[]; lineDashOffset: number; opacity: number; }> | undefined; protected resolveMarkerDrawingModeForState(drawingMode: AgDrawingMode, style?: NormalisedSeriesMarkerStyle): AgDrawingMode; protected abstract hasItemStylers(): boolean; filterItemStylerFillParams(fill: NormalisedColorType | undefined): NormalisedColorType | undefined; protected getModuleTooltipParams(): object; abstract getTooltipContent(datumIndex: DatumIndex, removeThisDatum: TDatum | undefined): TooltipContent | undefined; protected _pickNodeCache: LRUCache<PickResult | undefined, string>; pickNodes(point: Point, intent: SeriesNodePickIntent, exactMatchOnly?: boolean): PickResult | undefined; protected pickNodesExactShape(point: Point): SeriesNodeDatum[]; protected pickNodeClosestDatum(_point: Point): SeriesNodePickMatch | undefined; pickNodeNearestDistantObject<T extends Node & DistantObject>(point: Point, items: Iterable<T>): SeriesNodePickMatch | undefined; protected pickNodeMainAxisFirst(_point: Point, _requireCategoryAxis: boolean): SeriesNodePickMatch | undefined; protected pickNodesInBBoxPredicate(): PickNodesInBBoxPredicate; pickNodesInBBox(selectionBox: BoxBounds): Iterable<TDatum>; isPointInArea?(x: number, y: number): boolean; getLabelData(): (TLabel & PointLabelDatum)[]; updatePlacedLabelData(_labels: PlacedLabel<TLabel>[]): void; private readonly fireEventWrapper; protected fireEvent<TEvent extends TypedEvent>(event: TEvent): void; fireNodeClickEvent(event: Event, datum: TDatum): boolean; fireNodeDoubleClickEvent(event: Event, datum: TDatum): boolean; createNodeContextMenuActionEvent(event: Event, datum: TDatum): INodeEvent<'nodeContextMenuAction'>; onLegendInitialState(legendType: ChartLegendType, initialState: AgInitialStateLegendOptions | undefined): void; onLegendItemClick(event: LegendItemClickEvent): void; onLegendItemDoubleClick(event: LegendItemDoubleClickEvent): void; abstract getLegendData<T extends ChartLegendType>(legendType: T): ChartLegendDatum<T>[]; abstract getLegendData(legendType: ChartLegendType): ChartLegendDatum<ChartLegendType>[]; protected toggleSeriesItem(enabled: boolean, legendType: ChartLegendType, itemId: string | number | undefined, legendItemName: string | undefined, legendEvent?: { legendItemName?: string; }): void; isEnabled(): boolean; getModuleMap(): ModuleMap<SeriesPluginModuleInstance>; createModuleContext(): DynamicContext<ChartSeriesRegistry>; protected getAxisValueText(axis: ChartAxis, source: 'tooltip', value: any, datum: any, key: string, legendItemName: string | undefined, allowNull?: boolean): string; protected getLabelText<TParams extends object>(value: any, datum: any, key: string, property: FormatterPropertyType, domain: any[], label: AxisFormattableLabel<AgChartLabelFormatterParams<any> & RequireOptional<TParams>>, baseParams: RequireOptional<TParams> & Omit<AgChartLabelFormatterParams<any>, 'seriesId'>, allowNullValue?: boolean): NormalisedTextOrSegments; getMarkerStyle<TParams>(marker: SeriesMarker<TParams>, { datumIndex, datum, point }: Partial<TDatum>, params?: TParams, opts?: { highlightState?: HighlightState; /** Pre-resolved by per-datum hot paths to skip the getDataSelectionState() lookup. */ selectionState?: SelectionState; isHighlight?: boolean; checkForHighlight?: boolean; resolveMarkerSubPath?: string[]; resolveStyler?: boolean; hideWithSize0?: boolean; }, defaultOverrideStyle?: NormalisedSeriesMarkerStyle & { size: number; }, inheritedStyle?: NormalisedSeriesMarkerStyle): Omit<import("ag-charts-types").AgSeriesMarkerStyle & {}, keyof import("ag-charts-core").FillStrokeMorph> & import("ag-charts-core").FillStrokeMorph & { size: number; opacity?: number; }; protected applyMarkerStyle(style: NormalisedSeriesMarkerStyle, markerNode: Marker, point: { x: number; y: number; size?: number; focusSize?: number; } | undefined, fillBBox: ShapeFillBBox | undefined, opts: { applyPosition?: boolean; crossFilterSelected?: boolean; hideWithSize0: boolean; }): void; /** * Per-datum marker-style pass with a state-keyed cache, shared across all marker-rendering series. * Callbacks take `series` and `ctx` explicitly so callers pass static methods (stable function * identity) and keep V8's inline cache monomorphic across series sharing this helper. * * @param opts.keyExtra - optional extra cache-key dimension (e.g. range-area's `datum.itemType`) * @param opts.cacheable - set false when `compute` returns a value mutated per datum (e.g. bubble + colorScale) * @param opts.compute - called once per distinct (highlight, selection[, keyExtra]) tuple * @param opts.apply - called per non-garbage datum with the cached value */ protected runMarkerStylePass<TCtx, TPassDatum extends SeriesNodeDatum, TCache, TSeries = this>(datumSelection: Selection<TPassDatum, Marker<TPassDatum>>, isHighlight: boolean, ctx: TCtx, opts: { keyExtra?: (datum: TPassDatum) => string; cacheable?: boolean; compute: MarkerStyleCompute<TSeries, TCtx, TPassDatum, TCache>; apply: MarkerStyleApply<TSeries, TCtx, TPassDatum, TCache>; }): void; /** Default `apply` for the no-itemStyler path — writes the cached style straight onto the datum. */ protected static readonly assignCachedStyle: MarkerStyleApply<unknown, unknown, { style?: unknown; }, unknown>; protected _nodeDataDependencies?: NodeDataDependencies; get nodeDataDependencies(): NodeDataDependencies; protected checkResize(newSeriesRect?: BBox): boolean; pickFocus(_opts: PickFocusInputs): PickFocusOutputs | undefined; pickViewportFocus(_opts: PickViewportFocusInputs): PickFocusOutputs | undefined; mapFocusBBoxToPanTarget(_seriesRect: BoxBounds, focusBBox: Readonly<BBox>): BoxBounds; resetDatumCallbackCache(): void; cachedDatumCallback<T>(id: any, fn: () => T): T | undefined; cachedCallWithContext<F extends Callback>(fn: F, params: CallbackParam<F>, cacheKey?: string): ReturnType<F> | undefined; callWithContext<F extends Callback>(fn: F, params: CallbackParam<F>): ReturnType<F>; protected formatTooltipWithContext<P extends AgSeriesTooltipRendererParams<any>, Tooltip extends SeriesTooltip<P>>(tooltip: Tooltip, content: TooltipStructuredContent, params: RequireOptional<P>): TooltipContent; abstract getCategoryValue(datumIndex: DatumIndex): any; abstract datumIndexForCategoryValue(categoryValue: any): DatumIndex | undefined; minTimeInterval(): number | undefined; needsDataModelDiff(): boolean; }