### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-chart\x-chart.component.html
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-chart\x-chart.component.scss :host { display: block; width: 100%; height: 100%; } .x-chart-wrapper { width: 100%; height: 100%; min-height: 300px; /* ارتفاع پیش‌فرض برای جلوگیری از فروپاشی layout */ } .x-chart-container { width: 100%; height: 100%; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-chart\x-chart.component.ts import { Component, ViewChild, ElementRef, ChangeDetectionStrategy, } from '@angular/core'; import { isChartType, XChartAction, XChartOptions, XChartSeriesType, XChartContainerComponent, } from './x-chart.typings'; import { Subscription } from 'rxjs'; import ApexCharts from 'apexcharts'; import { isNullOrUndefined, nameof } from 'x-framework-core'; @Component({ selector: 'x-chart', templateUrl: './x-chart.component.html', styleUrls: ['./x-chart.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XChartComponent extends XChartContainerComponent { // //#region Props ... // private CHART_CONTAINER: ElementRef | undefined; @ViewChild('chartContainer', { static: false }) set chartContainer(el: ElementRef | undefined) { // if (isNullOrUndefined(el)) { // this.destroyComponent(); return; } // this.CHART_CONTAINER = el; this.initializeComponent(); } get chartContainer() { return this.CHART_CONTAINER; } // private CHART_OPTIONS: XChartOptions = null; // private chartInstance: ApexCharts = null; // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; //#endregion // //#region LifeCycles ... async afterViewInit() { super.afterViewInit(); // await this.initializeComponent(); } async onChange(changeKeys: string[]) { super.onChange(changeKeys); // // Auto Update ... const isAutoUpdateChanged = changeKeys.includes( nameof('autoUpdate'), ); if (isAutoUpdateChanged) { // if (isNullOrUndefined(this.autoUpdate)) { this.autoUpdate = this.propertyProvider.autoUpdate; } } // // Action Provider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider'), ); if (isActionProviderChanged) { this.registerActionProvider(); } // // Check Auto Update ... var autoUpdate = await this.getValueAsync(this.autoUpdate); if ( autoUpdate && !isNullOrUndefined(this.chartInstance) && !isNullOrUndefined(this.chartContainer) && !isNullOrUndefined(this.chartContainer.nativeElement) ) { // // Options Changed ... const isOptionsChanged = changeKeys.includes( nameof('options'), ); if (isOptionsChanged) { // if (isNullOrUndefined(this.options)) { this.options = this.propertyProvider.options; } // await this.handleChartUpdate(); } // // Chart Type ... const isTypeChanged = changeKeys.includes( nameof('type'), ); if (isTypeChanged) { // if (isNullOrUndefined(this.type)) { this.type = this.propertyProvider.type; } // var type = await this.getValueAsync(this.type); if (!isChartType(type)) { // type = await this.getValueAsync(this.propertyProvider.type); this.type = type; } // await this.handleChartUpdate(); } // // Series Changed ... const isSeriesChanged = changeKeys.includes( nameof('series'), ); if (isSeriesChanged) { // if (isNullOrUndefined(this.series)) { this.series = this.propertyProvider.series; } // await this.handleChartUpdate(); } } // this.detectChanges(); } onDestroy() { super.onDestroy(); // this.destroyComponent(); this.unregisterActionProvider(); } //#endregion // //#region Private ... private async initializeComponent() { // if (isNullOrUndefined(this.CHART_CONTAINER)) { return; } // // Reading Requirement Properties ... const type = await this.getValueAsync(this.type); const chartId = await this.getValueAsync(this.uuid); const series = await this.getValueAsync(this.series); const options = await this.getValueAsync(this.options); // const computedStyle = getComputedStyle(document.documentElement); const primaryColor = computedStyle.getPropertyValue('--x-color-primary').trim() || '#008ffb'; const textColor = computedStyle.getPropertyValue('--x-color-dark-contrast').trim() || '#373d3f'; const gridColor = computedStyle.getPropertyValue('--x-color-light-shade').trim() || '#e0e0e0'; // this.CHART_OPTIONS = { ...options, series: series || options.series, chart: { ...options.chart, id: chartId, type: type as any, foreColor: textColor, events: { ...options.chart?.events, mounted: (chartContext, config) => { this.chartRendered.emit(); options.chart?.events?.mounted?.(chartContext, config); }, dataPointSelection: (event, chartContext, config) => { this.dataPointSelected.emit({ event, chartContext, config }); options.chart?.events?.dataPointSelection?.( event, chartContext, config, ); }, zoomed: (chartContext, { xaxis, yaxis }) => { this.zoomed.emit({ xaxis, yaxis }); options.chart?.events?.zoomed?.(chartContext, { xaxis, yaxis }); }, }, }, theme: { ...options.theme, palette: options.theme?.palette || 'palette1', }, colors: options.colors || [primaryColor], grid: { ...options.grid, borderColor: gridColor, }, }; // this.chartInstance = new ApexCharts( this.chartContainer.nativeElement, this.CHART_OPTIONS, ); // await this.chartInstance.render(); } private async handleChartUpdate() { // if ( isNullOrUndefined(this.chartInstance) || isNullOrUndefined(this.CHART_OPTIONS) || isNullOrUndefined(this.chartContainer) || isNullOrUndefined(this.chartContainer.nativeElement) ) { return; } // // Reading Requirement Properties ... const type = await this.getValueAsync(this.type); const series = await this.getValueAsync(this.series); // const options = await this.getValueAsync(this.options); this.CHART_OPTIONS = { ...options, ...this.CHART_OPTIONS, chart: { ...this.CHART_OPTIONS.chart, type: type as any, }, }; // await this.chartInstance.updateOptions(this.CHART_OPTIONS); await this.chartInstance.updateSeries(series); } private destroyComponent() { // if (isNullOrUndefined(this.chartInstance)) { return; } // this.chartInstance.destroy(); this.chartInstance = null; } private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = this.propertyProvider.actionProvider; } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // switch (model.action) { // case XChartAction.Refresh: this.detectChanges(); break; // case XChartAction.Destroy: this.onDestroy(); break; // case XChartAction.UpdateSeries: // if ( !isNullOrUndefined(model.payload) || !isNullOrUndefined(this.chartInstance) ) { // this.series = await this.getValueAsync( model.payload as XChartSeriesType, ); await this.chartInstance.updateSeries(this.series); this.detectChanges(); } break; // case XChartAction.UpdateOptions: // if ( !isNullOrUndefined(model.payload) || !isNullOrUndefined(this.chartInstance) ) { // this.options = await this.getValueAsync( model.payload as XChartOptions, ); await this.chartInstance.updateOptions(this.options); this.detectChanges(); } break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-chart\x-chart.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XCardModule } from '../x-card/x-card.module'; import { XIconModule } from '../x-icon/x-icon.module'; import { XChartComponent } from './x-chart.component'; import { XSlotterModule } from '../x-slotter/x-slotter.module'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ providers: [], entryComponents: [], declarations: [XChartComponent], imports: [ XCardModule, XIconModule, CommonModule, XSlotterModule, XBaseComponentModule, ], exports: [ XCardModule, XIconModule, CommonModule, XSlotterModule, XChartComponent, XBaseComponentModule, ], }) export class XChartModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-chart\x-chart.typings.ts import { Input, Inject, NgZone, Output, Component, Renderer2, ElementRef, Injectable, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, isValueInEnum, XOneOrManyType, XColorIdentifier, XResourceIdentifier, } from 'x-framework-core'; import { XCardActionModel, XComponentCardContainer, IXComponentCardContainer, XComponentCardContainerComponent, } from '../x-card/x-card.typings'; import { concatMap, map } from 'rxjs/operators'; import { forkJoin, Observable, Subject } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; // //#region Chart ... export type XChartAnnotationStyle = { background?: string; color?: string; fontFamily?: string; fontWeight?: string | number; fontSize?: string; cssClass?: string; padding?: { left?: number; right?: number; top?: number; bottom?: number; }; }; export type XChartAnnotationLabel = { borderColor?: string; borderWidth?: number; borderRadius?: number; text?: string | string[]; textAnchor?: string; offsetX?: number; offsetY?: number; style?: XChartAnnotationStyle; position?: string; orientation?: string; mouseEnter?: (annotation: XChartAnnotationLabel, e: MouseEvent) => void; mouseLeave?: (annotation: XChartAnnotationLabel, e: MouseEvent) => void; click?: (annotation: XChartAnnotationLabel, e: MouseEvent) => void; }; export type XCahrtAxisBaseAnnotations = { id?: number | string; strokeDashArray?: number; fillColor?: string; borderColor?: string; borderWidth?: number; opacity?: number; offsetX?: number; offsetY?: number; label?: XChartAnnotationLabel; draggable?: boolean; }; export type XChartYAxisAnnotations = XCahrtAxisBaseAnnotations & { y?: null | number | string; y2?: null | number | string; width?: number | string; yAxisIndex?: number; }; export type XChartXAxisAnnotations = XCahrtAxisBaseAnnotations & { x?: null | number | string; x2?: null | number | string; }; export type XChartPointAnnotations = { id?: number | string; x?: number | string; y?: null | number; yAxisIndex?: number; seriesIndex?: number; /** * Ink Layer (#7): make this point annotation draggable. Overrides * `chart.ink.enabled`. Requires the `ink` feature. */ draggable?: boolean; mouseEnter?: (annotation: XChartPointAnnotations, e: MouseEvent) => void; mouseLeave?: (annotation: XChartPointAnnotations, e: MouseEvent) => void; click?: (annotation: XChartPointAnnotations, e: MouseEvent) => void; marker?: { size?: number; fillColor?: string; strokeColor?: string; strokeWidth?: number; shape?: string; offsetX?: number; offsetY?: number; cssClass?: string; }; label?: XChartAnnotationLabel; image?: { path?: string; width?: number; height?: number; offsetX?: number; offsetY?: number; }; /** * Show a hover tooltip over the annotation marker, like a regular data * point. Useful for surfacing more detail than fits in the label. */ tooltip?: { enabled?: boolean; /** * Static tooltip content (HTML allowed; an array is joined with line * breaks). Falls back to `label.text` when omitted. */ text?: string | string[]; /** * Returns the tooltip markup (HTML). Takes precedence over `text`. */ formatter?: (opts: { annotation: XChartPointAnnotations; seriesIndex?: number; id?: number | string; w: any; }) => string; /** * Tooltip theme. Falls back to the global `tooltip.theme`. */ theme?: 'light' | 'dark'; offsetX?: number; offsetY?: number; }; /** * Render arbitrary SVG markup at the annotation's position. Deprecated in * favor of `image`/`marker`, but still supported. */ customSVG?: { SVG?: string; cssClass?: string; offsetX?: number; offsetY?: number; }; }; export type XChartTextAnnotations = { x?: number; y?: number; text?: string; textAnchor?: string; foreColor?: string; fontSize?: string | number; fontFamily?: undefined | string; fontWeight?: string | number; /** CSS selector for the parent element the text is appended to. */ appendTo?: string; backgroundColor?: string; borderColor?: string; borderRadius?: number; borderWidth?: number; paddingLeft?: number; paddingRight?: number; paddingTop?: number; paddingBottom?: number; }; export type XChartImageAnnotations = { path?: string; x?: number; y?: number; width?: number; height?: number; }; export type XChartAnnotations = { texts?: XChartTextAnnotations[]; yaxis?: XChartYAxisAnnotations[]; xaxis?: XChartXAxisAnnotations[]; points?: XChartPointAnnotations[]; images?: XChartImageAnnotations[]; }; export type XChartContext = { config: XChartOptions; globals: any; [key: string]: any; }; export type XChartColorFormatterOpts = { value: number; seriesIndex: number; dataPointIndex: number; w: XChartContext; }; export type XChartFormatterOpts = { seriesIndex: number; dataPointIndex: number; series?: any[][]; w: XChartContext; [key: string]: any; }; export type XChartDropShadow = { enabled?: boolean; top?: number; left?: number; blur?: number; opacity?: number; /** * Shadow color. A single string applies to all series; an array applies * per-series (only respected by `chart.dropShadow`). */ color?: string | string[]; }; export type XChartDataLabels = { enabled?: boolean; enabledOnSeries?: undefined | number[]; textAnchor?: 'start' | 'middle' | 'end'; distributed?: boolean; /** * Horizontal offset of the label. Pass a function to vary the offset per * data point, e.g. to separate labels that would otherwise overlap. * The function must be pure, as it may be called more than once per label. */ offsetX?: number | ((opts: XChartFormatterOpts) => number); /** * Vertical offset of the label. Pass a function to vary the offset per * data point, e.g. to separate labels that would otherwise overlap. * The function must be pure, as it may be called more than once per label. */ offsetY?: number | ((opts: XChartFormatterOpts) => number); style?: { fontSize?: string; fontFamily?: string; fontWeight?: string | number; colors?: string[]; }; background?: { enabled?: boolean; foreColor?: string; backgroundColor?: string; borderRadius?: number; padding?: number; opacity?: number; borderWidth?: number; borderColor?: string; dropShadow?: XChartDropShadow; }; dropShadow?: XChartDropShadow; /** * Ride data labels to their new position on a data-change update (e.g. a bar * chart race) instead of snapping. Off by default. Bar/column only; speed and * easing follow chart.animations.dynamicAnimation. */ animate?: { enabled?: boolean; }; /** * Count the numeric value up/down from its previous value on update, like * countUp.js. Off by default. The formatter runs each frame so number * formatting is preserved. Bar/column only. */ countUp?: { enabled?: boolean; }; formatter?( val: string | number | number[], opts?: XChartFormatterOpts, ): string | number | (string | number)[]; }; export type XChartHierarchyNode = { /** The node's label. `name` is accepted as an alias. */ x?: string | number; name?: string; /** The node's value. `value` is accepted as an alias. */ y?: number | null; value?: number | null; color?: string; fillColor?: string; /** A second metric driving colour rather than size (`treemap`). */ colorValue?: number; meta?: unknown; children?: XChartHierarchyNode[]; /** * The `id` of a `drilldown.series` entry, read as another level by the * sunburst (and by the treemap with * `plotOptions.treemap.nested.drilldownAsLevels`). */ drilldown?: string | number; }; export type XChartParsing = { x?: string; y?: string | string[]; z?: string; }; export type XChartColorStop = { offset: number; color: string; opacity: number; }; export type XChartFill = { colors?: string[]; opacity?: number | number[]; type?: string | string[]; gradient?: { shade?: string; type?: string; shadeIntensity?: number; gradientToColors?: string[]; inverseColors?: boolean; opacityFrom?: number | number[]; opacityTo?: number | number[]; stops?: number[]; colorStops?: XChartColorStop[][] | XChartColorStop[]; }; image?: { src?: string | string[]; width?: number; height?: number; }; pattern?: { style?: string | string[]; width?: number; height?: number; strokeWidth?: number; }; }; export type XChartAxisChartSeries = { name?: string; type?: string; color?: string; group?: string; hidden?: boolean; zIndex?: number; parsing?: XChartParsing; data: | (number | null)[] | { /** * A category label, a timestamp, or a `Date`. On a `datetime` axis all * three keep millisecond resolution. */ x: string | number | Date; /** * A plain value for most charts. For `candlestick`/`boxPlot`, the * summary array (`[O,H,L,C]` / `[min,Q1,median,Q3,max]`). For `violin`, an * object carrying the precomputed density profile (`[value, weight]` pairs) * plus the raw observations rendered as jitter. For a `scatter` strip plot * (`plotOptions.scatter.jitter`), the array of observations in this category. */ y: | number | null | number[] | { density: [number, number][]; points?: number[] }; /** * Optional raw observations for a `boxPlot` data point, rendered as jitter * dots when `plotOptions.boxPlot.points.show` is enabled. */ points?: number[]; fill?: XChartFill; fillColor?: string; strokeColor?: string; meta?: unknown; /** * A second metric that drives this point's COLOUR, independent of `y` * which drives its size (`treemap`). See * `plotOptions.treemap.colorScale.colorValue` to read a different key. */ colorValue?: number; /** * Nested hierarchy: this point is a branch containing these children, * to any depth (`treemap`, `sunburst`). A branch normally omits `y` and * takes the sum of its children instead. */ children?: XChartHierarchyNode[]; /** * Drilldown target: the `id` of a `drilldown.series` entry. Clicking this * point drills into that level. Requires the Drilldown feature. */ drilldown?: string | number; goals?: { name?: string; value: number; strokeHeight?: number; strokeWidth?: number; strokeColor?: string; strokeDashArray?: number; strokeLineCap?: 'butt' | 'square' | 'round'; }[]; barHeightOffset?: number; columnWidthOffset?: number; }[] | [number, number | null][] | [number, (number | null)[]][] | number[][] // A `children` hierarchy for the partition charts, where a branch carries no // value of its own. Listed before the catch-all so authors get completion on // the node shape instead of falling through to `Record`. | XChartHierarchyNode[] | Record[]; }[]; export type XChartNonAxisChartSeries = number[] | XChartAxisChartSeries; export type XChartGradientLegend = { enabled?: boolean; /** * Strip length for horizontal placements (top/bottom). Accepts a number * (pixels) or percentage string (e.g. `'70%'`, resolved against the chart's * SVG width). Default `'70%'`. */ width?: number | string; /** * Strip length for vertical placements (left/right). Accepts a number * (pixels) or percentage string (e.g. `'70%'`, resolved against the chart's * SVG height). Default `'70%'`. */ height?: number | string; /** Strip thickness (short axis) in pixels. Default 12. */ thickness?: number; /** * Strip alignment within the legend area. * - top/bottom: 'start' = left, 'center', 'end' = right * - left/right: 'start' = top, 'center', 'end' = bottom * Default `'center'`. */ align?: 'start' | 'center' | 'end'; /** * Number of color stops sampled from the shade function when no explicit * `ranges` (or continuous scale) supply their own. Default 16. */ stops?: number; /** Show min/max labels at the ends of the strip. Default true. */ showLabels?: boolean; /** Show a value tooltip next to the arrow on mark hover. Default true. */ showHoverValue?: boolean; labelStyle?: { fontSize?: string; fontFamily?: string; colors?: string; }; arrow?: { size?: number; color?: string; }; /** Formatter for min/max labels and the hover value tooltip. */ formatter?(value: number): string; }; export type XChartTreemapLevel = { /** Inset between a parent's edge and the children inside it. Default 4. */ padding?: number; /** Container fill. Defaults to a neutral tint that deepens with each level. */ fill?: string; fillOpacity?: number; borderColor?: string; borderWidth?: number; /** Falls back to `plotOptions.treemap.borderRadius`. */ borderRadius?: number; hover?: { /** Outline the container on hover. Default true. */ show?: boolean; color?: string; width?: number; }; header?: { show?: boolean; /** Height of the strip reserved at the top of the container. Default 22. */ height?: number; /** * Skip the strip on tiles narrower than this, where no name could be read * anyway. Default 40. */ minWidth?: number; align?: 'left' | 'center' | 'right'; offsetX?: number; offsetY?: number; /** Append the branch's aggregate to its name. Default false. */ showValue?: boolean; formatter?( name: string, opts: { value: number; depth: number; seriesIndex: number; node: any; w: any; }, ): string; style?: { fontSize?: string; fontFamily?: string; fontWeight?: number | string; color?: string; background?: string; cssClass?: string; }; }; }; export type XChartBreadcrumb = { show?: boolean; position?: 'top-left' | 'top-right'; separator?: string; /** Label of the leftmost crumb, the "everything" level. Default 'All'. */ rootLabel?: string; offsetX?: number; offsetY?: number; formatter?( label: string, opts: { index: number; depth: number; data?: any }, ): string; }; export interface XChartUnitObject { /** * Stable identity. The datum's own `id`/`name` when the per-unit object form * supplies one, so a provider can address a specific unit ("Texas", * "employee 41") rather than a positional slot; otherwise * `":"`. */ id: string; /** Global draw order across every category. */ index: number; /** Category this mark belongs to. */ seriesIndex: number; /** Index within its category. */ dataPointIndex: number; /** Category label. */ label: string; /** The datum's value, when the per-unit object form supplies one. */ value?: number; /** The raw per-unit datum, when supplied. */ datum?: any; /** The radius the engine would use, so a size-aware provider need not redo it. */ r: number; } export interface XChartUnitPosition { /** Must match an `ApexUnitObject.id`; unknown ids are ignored. */ id: string; x: number; y: number; /** Overrides the engine's radius for this mark. */ r?: number; } export type XChartUnitLayout = ( objects: XChartUnitObject[], rect: { x: number; y: number; width: number; height: number }, ) => XChartUnitPosition[]; export type XChartPlotOptions = { line?: { isSlopeChart?: boolean; colors?: { threshold?: number; colorAboveThreshold?: string; colorBelowThreshold?: string; }; }; area?: { fillTo?: 'origin' | 'end'; }; bar?: { horizontal?: boolean; columnWidth?: string | number; barHeight?: string | number; distributed?: boolean; borderRadius?: number; borderRadiusApplication?: 'around' | 'end'; borderRadiusWhenStacked?: 'all' | 'last'; hideZeroBarsWhenGrouped?: boolean; rangeBarOverlap?: boolean; rangeBarGroupRows?: boolean; isDumbbell?: boolean; dumbbellColors?: string[][]; isFunnel?: boolean; isFunnel3d?: boolean; colors?: { ranges?: { from?: number; to?: number; color?: string; }[]; backgroundBarColors?: string[]; backgroundBarOpacity?: number; backgroundBarRadius?: number; }; dataLabels?: { maxItems?: number; hideOverflowingLabels?: boolean; position?: string; orientation?: 'horizontal' | 'vertical'; total?: { enabled?: boolean; formatter?(val?: string, opts?: XChartFormatterOpts): string; offsetX?: number; offsetY?: number; style?: { color?: string; fontSize?: string; fontFamily?: string; fontWeight?: number | string; }; }; }; }; bubble?: { zScaling?: boolean; minBubbleRadius?: number; maxBubbleRadius?: number; }; scatter?: { /** * Spread overlapping points apart ("jitter"). Two uses, one engine: * - Strip plot: supply data as `{ x: 'Category', y: [v1, v2, ...] }`. Each * category becomes a band and the values scatter horizontally within it. * - Overplotting: ordinary `{ x, y }` points get a small random offset so * dense clusters fan out. The underlying data (and tooltip values) stay * exact; only the drawn position moves. * Offsets are in axis units and deterministic (stable across re-renders). */ jitter?: { enabled?: boolean; /** Max ± horizontal offset, in x-axis units (1 = one category step). */ x?: number; /** Max ± vertical offset, in y-axis units. */ y?: number; /** Single series: colour each band differently (by its position). */ distributed?: boolean; /** Per-band cap; values beyond this are stride-thinned. */ maxPoints?: number; }; }; candlestick?: { type?: string; colors?: { upward?: string | string[]; downward?: string | string[]; }; wick?: { useFillColor?: boolean; }; }; boxPlot?: { colors?: { upper?: string | string[]; lower?: string | string[]; }; /** * Where the whiskers reach when the summary is DERIVED from raw * observations: a datum supplying `points` instead of a five-number `y`, * which requires `import 'apexcharts/features/stats'`. A precomputed * summary is drawn exactly as given and ignores this. * * `'minmax'` (default) reaches the extremes, so nothing is hidden. * `'tukey'` stops at the last observation within 1.5 * IQR of each * quartile; points beyond the fence then fall outside the whisker, so pair * it with `points.show` or they become invisible. */ whiskers?: 'minmax' | 'tukey'; /** * Individual observations ("jitter") overlaid on each box. Inert unless a * data point supplies a `points: number[]` array; `show` is false by * default so existing boxPlot charts are unchanged. * * `points` is also the sample the five-number summary is derived from when * a datum has no `y` (see `whiskers`), so the observations live in one * place whether the library summarises them or you do. */ points?: { show?: boolean; shape?: 'circle' | 'square'; /** Marker radius in pixels. */ size?: number; /** 0..1 fraction of the box half-width to scatter within. */ jitter?: number; /** Cap per box; observations beyond this are stride-thinned. */ maxPoints?: number; opacity?: number; /** * Dot fill colour. Defaults to 'series-dark' (a darker shade of the * series colour). Use 'series' for the series colour, or any literal * colour string. */ fillColor?: string; /** Colour of the outline around each dot. Defaults to '#fff'. */ strokeColor?: string; /** Width of the dot's outline in pixels. Defaults to 1; 0 disables it. */ strokeWidth?: number; /** * Colour each dot by its value along a colour ramp (overrides fillColor). * Points are bucketed into `steps` shades to keep rendering performant. */ colorScale?: { colors: string[]; min?: number; max?: number; steps?: number; }; }; }; violin?: { /** * Multiplies the density-derived half-width. 1 maps the density's own * maxWeight to half the category slot. */ bandwidthScale?: number; /** * Kernel density estimation, used only when the density is DERIVED from raw * observations: a datum supplying `points`, or a flat number array as `y`, * which requires `import 'apexcharts/features/stats'`. A precomputed * density profile is drawn exactly as given. */ kde?: { /** * Kernel width in value units. Unset uses Silverman's rule of thumb. * This is the statistical parameter; `bandwidthScale` above only scales * the drawn width. */ bandwidth?: number; /** Density samples per violin (default 64). */ resolution?: number; }; /** * 'individual' (default): each violin is scaled to its own peak density, so * all violins reach the full slot width. 'group': all violins share the * densest violin's scale, keeping widths proportional to density across * categories. */ normalize?: 'individual' | 'group'; /** Individual observations ("jitter") overlaid on the violin shape. */ points?: { show?: boolean; shape?: 'circle' | 'square'; /** Marker radius in pixels. */ size?: number; /** 0..1 fraction of the half-width to scatter within. */ jitter?: number; /** Clamp jitter to the density width at each value so points stay inside. */ constrainToViolin?: boolean; /** Cap per violin; observations beyond this are stride-thinned. */ maxPoints?: number; opacity?: number; /** * Dot fill colour. Defaults to 'series-dark' (a darker shade of each * violin's own colour). Use 'series' for the violin's colour as-is, or * any literal colour string (e.g. '#fff'). */ fillColor?: string; /** Colour of the ring/outline around each dot. Defaults to '#fff'. */ strokeColor?: string; /** Width of the dot's outline in pixels. Defaults to 1; 0 disables it. */ strokeWidth?: number; /** * Colour each dot by its value along a colour ramp (overrides fillColor). * Points are bucketed into `steps` shades to keep rendering performant. */ colorScale?: { /** Hex colour stops, low → high (a sequential colour ramp). */ colors: string[]; /** Value mapped to the first stop. Defaults to the data minimum. */ min?: number; /** Value mapped to the last stop. Defaults to the data maximum. */ max?: number; /** Number of shade buckets. Defaults to 24. */ steps?: number; }; }; }; /** * `chart.type: 'histogram'`. The series carry raw observations (a flat * number array, or `{ y }` objects) and are binned into one column per bin; * all series share one set of edges so overlaid distributions stay * comparable. * * Requires the optional stats feature. Import from `apexcharts/histogram`, * or add `import 'apexcharts/features/stats'` alongside `apexcharts/bar`. * The default `apexcharts` bundle already includes it. Without it the chart * warns and draws nothing, rather than rendering one bar per observation. */ histogram?: { /** * How the bin width is chosen: a rule name, or a fixed bin count. * `'auto'` takes the narrower of Freedman-Diaconis and Sturges, falling * back to Sturges when the IQR is 0. */ bins?: 'auto' | 'fd' | 'sturges' | 'scott' | 'rice' | 'sqrt' | number; /** * Explicit bin width in value units. Wins over `bins`, for when the * boundaries carry meaning (decades, 5-minute buckets) rather than being * a statistical choice. */ binWidth?: number; /** `[min, max]` to bin over instead of the data's own extent. */ range?: number[]; /** * y units: observations per bin, percent of the series total, or * `count / (n * binWidth)` so the total area is 1. */ normalize?: 'count' | 'relative' | 'density'; /** Running total across bins, i.e. a cumulative distribution. */ cumulative?: boolean; /** * With more than one series, draw every distribution across the full bin * so they overlay, instead of dividing the bin between them. Defaults to * `true`: all series already share one set of edges, and comparing two * shapes is the reason to put them on one axis. Set `false` for * side-by-side bars. * * An overlay also softens the fill and drops the bin separator stroke, so * the overlapping region reads. Both remain overridable. */ overlap?: boolean; }; heatmap?: { radius?: number; enableShades?: boolean; shadeIntensity?: number; reverseNegativeShade?: boolean; distributed?: boolean; useFillColorAsStroke?: boolean; colorScale?: { ranges?: { from?: number; to?: number; color?: string; foreColor?: string; name?: string; }[]; inverse?: boolean; min?: number; max?: number; /** * When enabled, replaces the default categorical legend with a * continuous color gradient strip and a hover indicator arrow that * tracks the currently hovered mark's value along the spectrum. * Follows `legend.position` (top / right / bottom / left); the arrow * orientation flips to point at the strip from the chart-facing side. */ gradientLegend?: XChartGradientLegend; }; }; funnel?: { /** * 'rectangle' (default) preserves the existing centered-rectangle funnel * geometry. 'trapezoid' produces continuous sloped sides between * consecutive stages (each stage's bottom width matches the next stage's * top width). */ shape?: 'rectangle' | 'trapezoid'; /** * For `shape: 'trapezoid'` only — last stage's bottom edge: * 'flat' (default, parallel sides) or 'taper' (taper to a point). */ lastShape?: 'flat' | 'taper'; }; treemap?: { enableShades?: boolean; shadeIntensity?: number; distributed?: boolean; reverseNegativeShade?: boolean; useFillColorAsStroke?: boolean; dataLabels?: { format?: 'scale' | 'truncate'; /** * Skip a tile's label when it would render below this size in px. * * With `format: 'scale'` the font size follows the tile's area, so a * dense treemap asks for a lot of text only a few pixels tall. Each such * label still has to be built and measured against the DOM, which on a * large chart dominates the render. Default 4, below the smallest label * any bundled sample draws. Set 0 to label every tile regardless. */ minFontSize?: number; }; borderRadius?: number; colorScale?: { inverse?: boolean; ranges?: { from?: number; to?: number; color?: string; foreColor?: string; name?: string; }[]; min?: number; max?: number; /** * Colour a tile by a SECOND metric, independent of the value that sizes * it: area is how big something is, colour is how it did. Reads * `datum.colorValue` by default; pass a key name to read a different * property, or an accessor to compute one. */ colorValue?: | string | (( datum: any, opts: { seriesIndex: number; dataPointIndex: number; w: any }, ) => number); /** * Continuous interpolation between colour stops, for the metric above. * Active as soon as any datum carries a colour metric; `enabled: false` * opts out and `true` forces it on. `ranges` is unaffected and still * applies wherever it is set. */ gradient?: { enabled?: boolean; /** Domain low. Defaults to the extent of the colour metric. */ min?: number; /** Domain high. Defaults to the extent of the colour metric. */ max?: number; /** * The value the middle colour is pinned to. Defaults to 0 when the * domain straddles zero (a diverging metric), otherwise none. Pass * `null` to force a plain sequential ramp. */ midpoint?: number | null; /** * With a midpoint, balance the domain around it so equal moves in * either direction read as equally saturated. Default true. */ symmetric?: boolean; /** Low -> mid -> high. Two colours make a sequential ramp. */ colors?: string[]; /** Explicit stops; overrides `colors` and `midpoint`. */ stops?: { value: number; color: string }[]; }; /** * Continuous colour legend for the metric above: a gradient strip with * end labels and a hover indicator, in place of the categorical legend. */ gradientLegend?: XChartGradientLegend; }; /** * Arbitrary-depth treemap. A datum may carry `children` to any depth; * every branch is drawn as a real container with a header strip and its * children inset below it. */ nested?: { /** * Parent containers appear on their own as soon as the data is nested. * `false` forces the flat two-level layout. */ enabled?: boolean; /** * Read `drilldown: ''` ids as extra levels instead of as a click * target for the drilldown feature. Default false, because on a treemap * that id has always meant "descend on click". */ drilldownAsLevels?: boolean; }; /** * How a branch is drawn once the data is nested. Per-level overrides go in * `levels`. */ parents?: XChartTreemapLevel & { /** `'auto'` (default): on when the data carries `children`. */ show?: boolean | 'auto'; tooltip?: { formatter?(opts: { name: string; value: number; depth: number; leafCount: number; percentOfParent: number; percentOfTotal: number; node: any; w: any; }): string; }; }; /** * Per-depth overrides of `parents`, indexed from the outermost group * actually drawn (0 = the series, or the first authored level when a * single series is unwrapped). */ levels?: XChartTreemapLevel[]; /** * Click a group to fill the canvas with it; a breadcrumb goes back. * * Ignored when the drilldown feature is active on the same chart: both * navigate the hierarchy, and drilldown owns the click there. */ zoom?: { enabled?: boolean; /** * Overrides `drilldown.breadcrumb` for this chart only, so a zoomed * treemap and a drilled-in chart present the same affordance without * importing the drilldown feature. */ breadcrumb?: XChartBreadcrumb; }; seriesTitle?: { show?: boolean; offsetY?: number; offsetX?: number; borderColor?: string; borderWidth?: number; borderRadius?: number; style?: { background?: string; color?: string; fontSize?: string; fontFamily?: string; fontWeight?: number | string; cssClass?: string; padding?: { left?: number; right?: number; top?: number; bottom?: number; }; }; }; }; unit?: { /** * 'grouped' (default): each category is its own cluster, laid out in a row. * 'packed': one blob; categories are coloured and (with sortByGroup) ordered * smallest-first so the minority group nests in the centre. * 'columns': each category is a vertical bar built from stacked dots (a unit * / waffle column) whose height encodes the count. * 'grid': one lattice of cells filled in category order - a waffle / * part-to-whole square "pie" (`chart.type: 'waffle'` presets this layout). * 'scatter': beeswarm - each unit placed on a real numeric X value axis by * its per-unit value, laned by category on Y (draws its own axis + lanes). * 'arc': parliament / hemicycle - seats in concentric arced rows, filled in * category order so each category is a contiguous wedge (see `arc`). * 'custom': positions come from `positions`. */ layout?: | 'grouped' | 'packed' | 'columns' | 'grid' | 'scatter' | 'arc' | 'custom'; /** * `layout: 'custom'` only. The layout provider: either a function returning * plot-pixel positions, or the name of one registered with * `ApexCharts.registerUnitLayout`. * * A layout is objects in, positions out. It knows nothing about animation, * because the engine already tweens position, radius and colour and already * keeps each mark's identity across a relayout, so an arrangement the * built-in layouts cannot express needs no new transition code. * * A mark whose id the provider omits animates out; ids matching no mark are * ignored. */ positions?: string | XChartUnitLayout; /** * How dots are matched between renders on an update (which previous dot a * new dot tweens from). * 'group' (default): keyed per category, so a dot stays in its group and * category-level enters/exits fade in and out. * 'flow': keyed by global draw order, so the anonymous crowd migrates (and * recolours) across a regroup - the circles-to-bars transition. * 'identity': keyed by each datum's `id`/`name`, so a SPECIFIC unit migrates * across any regroup or relayout keeping its colour and size. Requires the * per-unit object form with unique ids/names. */ transition?: 'group' | 'flow' | 'identity'; /** Mark shape for each unit. `'image'` renders an icon (isotype pictogram). */ shape?: 'circle' | 'square' | 'image'; /** Icon used when `shape: 'image'`. */ image?: { /** Icon URL or data URI. */ src?: string; width?: number; height?: number; /** * Recolour a monochrome icon to the category colour (or a per-unit * `fillColor`) so the pictogram matches the legend. Leave off (default) * for multi-colour icons that should keep their own colours. */ tint?: boolean; }; /** Dot radius in px, or 'auto' to size dots so the largest cluster fits. */ size?: number | 'auto'; /** * The 'columns' layout can size its dots independently of `size` (which the * circle layouts / storyboard beats often pin to a constant so dots do not * resize while migrating). */ columns?: { /** * 'inherit' (default) uses `size`; 'auto' sizes dots to fill the plot * height; a number pins a columns-only size. Circle / square only (image * icons keep their intrinsic size). */ size?: 'inherit' | 'auto' | number; }; /** * The 'grid' (waffle) layout: one lattice of cells filled in category order. */ grid?: { /** Cells per row. Defaults to 10. */ columns?: number; /** * Fixed cell budget (e.g. 100 for a percentage waffle); largest-remainder * allocates the cells to categories. Leave undefined for one cell per unit * (respects unitValue / maxUnits). */ total?: number; /** First row of the fill: 'bottom' (default) or 'top'. */ fillFrom?: 'bottom' | 'top'; /** * Small multiples: render ONE mini-waffle per category in a trellis * instead of a single shared lattice. Each tile has `total` cells * (default 100) and fills value/`max` of them; the rest show as a faint * `trackColor` backdrop, and each tile carries its own label. */ split?: boolean; /** Small-multiple tiles per row; undefined = auto (near-square). */ tileColumns?: number; /** * Small-multiple value -> filled-cell denominator; undefined = the largest * count (leader fills its tile). Set to 100 for true "of 100" percentage tiles. */ max?: number; /** Small-multiple empty ("track") cell colour; undefined = neutral grey. */ trackColor?: string; }; /** * The 'scatter' layout places units on real value axes (needs the object-form * data). `y:'lanes'` (default) is a beeswarm (X value axis, Y category lane); * `y:'value'` is a 2D value-value scatter (each datum's `x`/`y` on two numeric * axes, category = colour). `sizeRange` turns dots into bubbles. */ scatter?: { /** 'lanes' (beeswarm, default) or 'value' (2D value-value scatter). */ y?: 'lanes' | 'value'; /** 'swarm' (anti-overlap pack, default) or 'jitter' (random lane spread). */ spread?: 'swarm' | 'jitter'; /** * Beeswarm orientation (1D `y:'lanes'` mode only). 'horizontal' (default): * value on X, category lanes stacked on Y. 'vertical': value on Y, * category lanes as columns across X. The value-axis config keys * (`xMin`/`xMax`/`xTitle`/`xFormatter`/`tickAmount`) describe the value * axis in both orientations. */ orientation?: 'horizontal' | 'vertical'; /** Approximate number of value-axis ticks. Defaults to 5. */ tickAmount?: number; /** Fixed X-axis min / max; undefined = derived (nice-numbered) from data. */ xMin?: number; xMax?: number; /** X-axis title drawn under the tick labels. */ xTitle?: string; /** X tick-label formatter, `(value) => string`. */ xFormatter?: (value: number) => string; /** Approximate number of Y-axis ticks (2D mode). Defaults to 5. */ yTickAmount?: number; /** Fixed Y-axis min / max (2D mode); undefined = nice-numbered from data. */ yMin?: number; yMax?: number; /** Y-axis title (2D mode), drawn rotated at the left. */ yTitle?: string; /** Y tick-label formatter, `(value) => string`. */ yFormatter?: (value: number) => string; /** Datum key holding the bubble size value. Defaults to 'z'. */ sizeField?: string; /** `[minRadius, maxRadius]` in px: turns dots into area-scaled bubbles. */ sizeRange?: [number, number]; /** Left-gutter width reserved for lane (category) labels (lanes mode). */ laneLabelWidth?: number; /** Draw the faint gridlines. Defaults to true. */ gridlines?: boolean; }; /** * Opt-in bubble sizing: scale each dot's radius by its per-unit value * (requires the object-form data, `series: [{ data: [{ value }] }]`). * Circle shape only; the lattice is spaced for the largest bubble so dots * never overlap. Ignored when there are no per-unit values. */ sizeByValue?: { enabled?: boolean; /** Radius (px) for the largest value, or 'auto' to fit it to the plot. */ maxRadius?: number | 'auto'; /** Radius (px) for the smallest value; defaults to ~35% of maxRadius. */ minRadius?: number; /** 'area' (bubble area proportional to value) or 'linear'. */ scale?: 'area' | 'linear'; }; /** Packing gap factor between spiral shells (1 = dots touch). */ spacing?: number; /** * How marks move between layouts on an update, and where entering marks * come from. */ gather?: { /** * 'spring' settles each mark on a damped spring, so a gather interrupted * by the next update carries the marks' velocity into it instead of * restarting them from a standstill. 'tween' runs the fixed-duration * `easing` below. 'auto' (the default) is spring, unless `easing` was set * to something other than the default. */ motion?: 'auto' | 'spring' | 'tween'; /** * Spring character (`motion: 'spring'` only): 'crisp' (default), * 'gentle' (softer, for large reflows) or 'snappy' (faster, a hint of * settle). Scaled by `chart.animations.speed`. */ spring?: 'crisp' | 'gentle' | 'snappy'; /** Tween curve: 'outCubic' (default: decelerate and stop), 'inOutCubic' (weighted start), or 'outBack' (overshoot + settle). Setting this implies `motion: 'tween'`. */ easing?: 'outCubic' | 'inOutCubic' | 'outBack'; /** Overshoot strength for `easing: 'outBack'`. Defaults to 1.70158 (~10% overshoot). */ overshoot?: number; /** * Where an ENTERING mark animates from (fresh mount, or a category * appearing): 'burst' (default) flies out from the cluster centre, * 'fade' materialises in place, 'rise' fades in while drifting gently * up into its slot. */ enter?: 'burst' | 'fade' | 'rise'; }; /** * Options for `layout: 'arc'` (parliament / hemicycle). Angles use the * radialBar convention: 0 = top, clockwise. The default sweep is a top * semicircle; a full circle is `startAngle: 0, endAngle: 360`. */ arc?: { /** Sweep start angle in degrees (0 = top, clockwise). Default -90. */ startAngle?: number; /** Sweep end angle in degrees. Default 90 (a top semicircle). */ endAngle?: number; /** Donut hole: inner radius as a fraction of the outer radius. Default 0.4. */ innerRadiusRatio?: number; /** Number of concentric seat rows, or 'auto' to size dots as large as fit. */ rows?: number | 'auto'; }; /** Corner radius for shape:'square'. */ borderRadius?: number; /** 1 dot represents this many units of value (waffle scaling). */ unitValue?: number; /** Safety cap on total dots; counts scale down proportionally above it. */ maxUnits?: number; /** Packed layout: order categories smallest-first (minority centred). */ sortByGroup?: boolean; clusterLabels?: { show?: boolean; /** Label placement relative to the cluster/bar. Defaults to 'top'. A 'bottom' label is always straight (the curved arc rides the top crown only). */ position?: 'top' | 'bottom'; curved?: boolean; fontSize?: string; fontFamily?: string; fontWeight?: number | string; /** Defaults to the cluster's own colour when undefined. */ color?: string; offsetY?: number; /** Return "\n"-separated text to split an outer label over several lines. */ formatter?( name: string, opts: { seriesIndex: number; value: number; percent: number; w: any }, ): string; /** * Outer (name) labels, as pie/donut draw them: the label sits in the margin * beside the shape and a leader line joins it to the colour band it names, * so the crowd can be read without a legend. * * `layout: 'custom'` only, and best on a silhouette whose categories stack * vertically (the default row ordering): those alternate down the left and * right gutters. A column-ordered shape sends each label to the side its own * band sits on. The margin is taken off both sides so the shape stays * centred, so turning this on makes the silhouette a little smaller. */ external?: { show?: boolean; connector?: { show?: boolean; width?: number; /** Defaults to the band's own colour when undefined. */ color?: string; /** Air between the band's outermost dot and the leader line's bend. */ gap?: number; /** Length of the run out to the label. */ length?: number; }; offsetX?: number; offsetY?: number; }; }; /** Per-unit (per-dot) tooltip. */ tooltip?: { /** * Return the tooltip body for a single hovered dot. The dot's category is * `seriesIndex` and its index within that category is `dataPointIndex`, so * the formatter can index into per-unit data. Return a string or HTML. * Defaults to `"# of "`. */ formatter?(opts: { seriesName: string; seriesIndex: number; dataPointIndex: number; /** Number of dots drawn for this category (after unitValue + maxUnits). */ count: number; /** Raw category value (before unitValue scaling). */ value: number; unitValue: number; /** * This dot's own datum when the per-unit object form was supplied * (`series: [{ name, data: [...] }]`); otherwise undefined. */ datum: any; color: string; w: any; }): string; }; }; pie?: { startAngle?: number; endAngle?: number; customScale?: number; offsetX?: number; offsetY?: number; expandOnClick?: boolean; /** * How far a clicked slice slides out of the pie (px), measured along its * own mid-angle. The slice is translated, not redrawn at a bigger radius, * so its shape is unchanged and a gap opens between it and the rest of the * pie. Defaults to 10. Ignored for polarArea, and in a drilldown pie/donut * where a slice click navigates instead. Set 0 to keep the slice in place * on click. */ expandOffset?: number; /** * Hover outline: a translucent band traced just outside the rim of the * hovered slice, so the slice keeps its own colour instead of being * lightened. Takes the place of the `states.hover` filter for pie, donut * and polarArea, and is skipped when `states.hover.filter.type` is * `'none'`. */ hoverOutline?: { show?: boolean; /** Band thickness in px. Defaults to 8. */ size?: number; /** * Extra clearance between the slice rim and the band, in px, on top of * the slice stroke (the band always starts at the outer edge of the * stroke, never under it). Defaults to 0, since a stroke is normally * present and already reads as the separation. */ gap?: number; /** Band opacity over the slice colour. Defaults to 0.3. */ opacity?: number; /** Band colour. Defaults to the hovered slice's colour. */ color?: string; }; /** * Rounds the corners of each slice (in px). Applies to pie, donut and * polarArea. Defaults to 0 (sharp corners). The value is clamped per * slice so corner fillets never cross on thin or narrow slices. */ borderRadius?: number; /** * Gap between adjacent slices (in px). Applies to pie, donut and * polarArea. Defaults to 0 (slices touch). Each slice is inset * symmetrically, so its mid-angle (data label and hit region) is kept. */ spacing?: number; dataLabels?: { offset?: number; minAngleToShowLabel?: number; /** * External (outer) labels: render the category/series name outside the * slice, joined by a leader (connector) line, so the chart is readable * without the legend. The percentage keeps rendering inside the slice. * Applies to pie and donut only (ignored for polarArea, where the radial * length already encodes the value). */ external?: { show?: boolean; offsetX?: number; offsetY?: number; fontSize?: string; fontFamily?: string; fontWeight?: string | number; color?: string; /** * Return a string for a single-line label, or an array of strings to * stack multiple lines (e.g. `[name, percent + '%']`). */ formatter?( name: string, opts: { seriesIndex: number; percent: number; value: number; w: XChartContext; }, ): string | string[]; /** Leader line from the slice edge to the label. */ connector?: { show?: boolean; width?: number; color?: string; length?: number; gap?: number; }; }; }; donut?: { size?: string; background?: string; labels?: { show?: boolean; name?: { show?: boolean; fontSize?: string; fontFamily?: string; fontWeight?: string | number; color?: string; offsetY?: number; formatter?(val: string): string; }; value?: { show?: boolean; fontSize?: string; fontFamily?: string; fontWeight?: string | number; color?: string; offsetY?: number; formatter?(val: number | string): string; }; total?: { show?: boolean; showAlways?: boolean; fontFamily?: string; fontWeight?: string | number; fontSize?: string; label?: string; color?: string; formatter?(w: XChartContext): string; }; }; }; }; polarArea?: { rings?: { strokeWidth?: number; strokeColor?: string; }; spokes?: { strokeWidth?: number; connectorColors?: string | string[]; }; }; /** * Sunburst / nested pie-donut (hierarchical radial). Rings go from the centre * hole outward, one per hierarchy level; each child arc is nested inside its * parent's angular wedge. Accepts a native `children` hierarchy or an existing * `drilldown` config (adapter). */ sunburst?: { offsetX?: number; offsetY?: number; startAngle?: number; endAngle?: number; /** Centre hole radius as a % of the max radius (e.g. '15%'). */ innerSize?: string; /** Corner rounding of each arc (px), same semantics as pie borderRadius. */ borderRadius?: number; /** Gap between adjacent arcs (px), same semantics as pie spacing. */ spacing?: number; /** Draw a shallow branch's leaf to the rim ('extend') or stop it ('stop'). */ leaf?: 'extend' | 'stop'; /** Angular partition of a parent's wedge among its children. */ partition?: 'normalize' | 'strict'; /** Per-depth lightening of the parent colour (0 = same, 1 = white). */ tint?: number; /** Click a wedge to zoom into its branch (breadcrumb to go back). Default true. */ zoomOnClick?: boolean; dataLabels?: { show?: boolean; /** Hide the label on any arc narrower than this (degrees). */ minAngleToShow?: number; style?: { fontSize?: string; fontFamily?: string; fontWeight?: string | number; colors?: string[]; }; }; }; radar?: { size?: number; offsetX?: number; offsetY?: number; polygons?: { strokeColors?: string | string[]; strokeWidth?: number | number[] | string | string[]; connectorColors?: string | string[]; fill?: { colors?: string[]; }; }; }; radialBar?: { inverseOrder?: boolean; startAngle?: number; endAngle?: number; offsetX?: number; offsetY?: number; /** * Gauge sub-shape. 'arc' (default) renders the existing filled value-arc * gauge; 'needle' replaces the value-arc with a rotating pointer/needle. * Bands and ticks are independent and work for both shapes. */ shape?: 'arc' | 'needle'; /** * Value-to-angle mapping (gauge). Defaults: min: 0, max: 100. Override * for gauges with a custom domain (e.g. min: 0, max: 240 speedometer). */ min?: number; max?: number; /** * Threshold bands rendered as colored arc segments along the gauge arc. * Each band spans [`from`, `to`] in the gauge's `min..max` domain and is * filled with `color`. */ bands?: Array<{ from: number; to: number; color: string; label?: string; }>; bandsStyle?: { strokeWidth?: string; gap?: number; hideTrackWhenPresent?: boolean; linecap?: 'butt' | 'round' | 'square'; }; ticks?: { show?: boolean; major?: { count?: number; length?: number; width?: number; color?: string; placement?: 'inside' | 'outside'; }; minor?: { count?: number; length?: number; width?: number; color?: string; placement?: 'inside' | 'outside'; }; labels?: { show?: boolean; offset?: number; fontSize?: string; fontFamily?: string; fontWeight?: string | number; color?: string; formatter?: (value: number) => string; }; }; needle?: { color?: string; length?: string | number; baseWidth?: number; tipWidth?: number; /** * When true, also render the filled value-arc alongside the needle. * Default false preserves needle-only behavior. */ showValueArc?: boolean; /** * px offset from the geometric arc center on Y. Positive values push * the needle base down (toward the chord midpoint of a ∩-shape * gauge); negative pushes up. The needle rotates around this shifted * point. */ offsetY?: number; animation?: { enabled?: boolean; duration?: number; easing?: string; }; }; hollow?: { margin?: number; size?: string; background?: string; image?: string; imageWidth?: number; imageHeight?: number; imageOffsetX?: number; imageOffsetY?: number; imageClipped?: boolean; position?: 'front' | 'back'; /** * Optional stroke color around the hollow ring. Combined with * `strokeDasharray` this produces a dashed indicator circle around * the value text. */ stroke?: string; strokeWidth?: number; strokeDasharray?: string | number; dropShadow?: XChartDropShadow; }; track?: { show?: boolean; startAngle?: number; endAngle?: number; background?: string | string[]; strokeWidth?: string; opacity?: number; margin?: number; dropShadow?: XChartDropShadow; }; dataLabels?: { show?: boolean; name?: { show?: boolean; fontFamily?: string; fontWeight?: string | number; fontSize?: string; color?: string; offsetY?: number; formatter?(seriesName: string): string; }; value?: { show?: boolean; fontFamily?: string; fontSize?: string; fontWeight?: string | number; color?: string; offsetY?: number; formatter?(val: number): string; }; total?: { show?: boolean; label?: string; color?: string; fontFamily?: string; fontWeight?: string | number; fontSize?: string; formatter?(w: XChartContext): string; }; }; barLabels?: { enabled?: boolean; offsetX?: number; offsetY?: number; useSeriesColors?: boolean; fontFamily?: string; fontWeight?: string | number; fontSize?: string; formatter?: (barName: string, opts?: XChartFormatterOpts) => string; onClick?: (barName: string, opts?: XChartFormatterOpts) => void; }; }; }; export type XChartXAxis = { type?: 'category' | 'datetime' | 'numeric'; /** * X-axis category labels. Pass a flat array for a single row of labels, * or a 2-D array (`[group, label][]`) to render grouped category axes. */ categories?: Array | Array>; overwriteCategories?: number[] | string[] | undefined; offsetX?: number; offsetY?: number; sorted?: boolean; labels?: { show?: boolean; rotate?: number; rotateAlways?: boolean; hideOverlappingLabels?: boolean; showDuplicates?: boolean; trim?: boolean; minHeight?: number; maxHeight?: number; style?: { colors?: string | string[]; fontSize?: string; fontFamily?: string; fontWeight?: string | number; cssClass?: string; }; offsetX?: number; offsetY?: number; format?: string; formatter?( value: string | number, timestamp?: number, opts?: XChartFormatterOpts, ): string | string[]; datetimeUTC?: boolean; datetimeFormatter?: { year?: string; month?: string; day?: string; hour?: string; minute?: string; second?: string; }; }; group?: { groups?: { title: string; cols: number }[]; style?: { colors?: string | string[]; fontSize?: string; fontFamily?: string; fontWeight?: string | number; cssClass?: string; }; }; axisBorder?: { show?: boolean; color?: string; width?: string | number; height?: number; offsetX?: number; offsetY?: number; }; axisTicks?: { show?: boolean; borderType?: 'solid' | 'dotted' | 'dashed'; color?: string; height?: number; offsetX?: number; offsetY?: number; }; tickPlacement?: string; tickAmount?: number | 'dataPoints'; stepSize?: number; min?: number; max?: number; range?: number; floating?: boolean; decimalsInFloat?: number; position?: string; title?: { text?: string; offsetX?: number; offsetY?: number; style?: { color?: string; fontFamily?: string; fontWeight?: string | number; fontSize?: string; cssClass?: string; }; }; crosshairs?: { show?: boolean; width?: number | string; position?: string; opacity?: number; stroke?: { color?: string; width?: number; dashArray?: number; }; fill?: { type?: string; color?: string; gradient?: { colorFrom?: string; colorTo?: string; stops?: number[]; opacityFrom?: number; opacityTo?: number; }; }; dropShadow?: XChartDropShadow; }; tooltip?: { enabled?: boolean; offsetY?: number; formatter?(value: string | number, opts?: XChartFormatterOpts): string; style?: { fontSize?: string; fontFamily?: string; }; }; }; export type XChartYAxis = { show?: boolean; showAlways?: boolean; showForNullSeries?: boolean; seriesName?: string | string[]; opposite?: boolean; reversed?: boolean; logarithmic?: boolean; logBase?: number; tickAmount?: number; stepSize?: number; forceNiceScale?: boolean; alignZero?: boolean; min?: number | ((min: number) => number); max?: number | ((max: number) => number); floating?: boolean; decimalsInFloat?: number; labels?: { show?: boolean; showDuplicates?: boolean; minWidth?: number; maxWidth?: number; offsetX?: number; offsetY?: number; rotate?: number; align?: 'left' | 'center' | 'right'; padding?: number; style?: { colors?: string | string[]; fontSize?: string; fontWeight?: string | number; fontFamily?: string; cssClass?: string; }; formatter?(val: number, opts?: XChartFormatterOpts): string | string[]; }; axisBorder?: { show?: boolean; color?: string; width?: number; offsetX?: number; offsetY?: number; }; axisTicks?: { show?: boolean; color?: string; width?: number; offsetX?: number; offsetY?: number; }; title?: { text?: string; rotate?: number; offsetX?: number; offsetY?: number; style?: { color?: string; fontSize?: string; fontWeight?: string | number; fontFamily?: string; cssClass?: string; }; }; crosshairs?: { show?: boolean; position?: string; stroke?: { color?: string; width?: number; dashArray?: number; }; }; tooltip?: { enabled?: boolean; offsetX?: number; }; }; export type XChartLegendFormatterOpts = { seriesIndex: number; w: XChartContext; }; export type XChartMarkerShapeOptions = | 'circle' | 'square' | 'rect' | 'line' | 'cross' | 'plus' | 'star' | 'sparkle' | 'diamond' | 'triangle'; export type XChartMarkerShape = | XChartMarkerShapeOptions | XChartMarkerShapeOptions[]; export type XChartDiscretePoint = { seriesIndex?: number; dataPointIndex?: number; fillColor?: string; strokeColor?: string; size?: number; shape?: XChartMarkerShape; }; export type XChartMarkers = { size?: number | number[]; colors?: string | string[]; strokeColors?: string | string[]; strokeWidth?: number | number[]; strokeOpacity?: number | number[]; strokeDashArray?: number | number[]; fillOpacity?: number | number[]; discrete?: XChartDiscretePoint[]; shape?: XChartMarkerShape; offsetX?: number; offsetY?: number; showNullDataPoints?: boolean; onClick?(e?: MouseEvent): void; onDblClick?(e?: MouseEvent): void; hover?: { size?: number; sizeOffset?: number; }; }; export type XChartLegend = { show?: boolean; showForSingleSeries?: boolean; showForNullSeries?: boolean; showForZeroSeries?: boolean; floating?: boolean; inverseOrder?: boolean; position?: 'top' | 'right' | 'bottom' | 'left'; horizontalAlign?: 'left' | 'center' | 'right'; fontSize?: string; fontFamily?: string; fontWeight?: string | number; width?: number; height?: number; offsetX?: number; offsetY?: number; formatter?(legendName: string, opts?: XChartLegendFormatterOpts): string; tooltipHoverFormatter?( legendName: string, opts?: XChartLegendFormatterOpts, ): string; customLegendItems?: string[]; clusterGroupedSeries?: boolean; clusterGroupedSeriesOrientation?: 'vertical' | 'horizontal'; labels?: { colors?: string | string[]; useSeriesColors?: boolean; }; markers?: { size?: number; strokeWidth?: number; fillColors?: string[]; shape?: XChartMarkerShape; offsetX?: number; offsetY?: number; customHTML?(): string; onClick?(e: MouseEvent): void; }; itemMargin?: { horizontal?: number; vertical?: number; }; onItemClick?: { toggleDataSeries?: boolean; }; onItemHover?: { highlightDataSeries?: boolean; }; }; export type XChartEasing = | 'linear' | 'easeInSine' | 'easeOutSine' | 'easeInOutSine' | 'easeInQuad' | 'easeOutQuad' | 'easeInOutQuad' | 'easeInCubic' | 'easeOutCubic' | 'easeInOutCubic' | 'easeOutBack' | 'easeInOutBack' | (string & {}) | [number, number, number, number] | ((t: number) => number); export type XChartEventOpts = { seriesIndex: number; dataPointIndex: number; w: XChartContext; [key: string]: any; }; export type XChartLocale = { name?: string; options?: { months?: string[]; shortMonths?: string[]; days?: string[]; shortDays?: string[]; toolbar?: { download?: string; selection?: string; selectionZoom?: string; zoomIn?: string; zoomOut?: string; pan?: string; reset?: string; measure?: string; menu?: string; exportToSVG?: string; exportToPNG?: string; exportToCSV?: string; }; }; }; export interface XChartStoryboardBeatInfo { index: number; key: string | null; el: Element; direction: 'up' | 'down'; } export interface XChartDrilldownSeries { /** Unique id referenced by a data point's `drilldown` field. */ id: string | number; /** Display name used by the breadcrumb and as the (single-series) child series name. */ name?: string; /** Child data points for a single-series level. Use this OR `series`. */ data?: any[]; /** Full multi-series array for a grouped/stacked drilldown level. Use this OR `data`. */ series?: XChartAxisChartSeries; /** Optional chart-type override applied when this level is shown. */ chart?: Pick; plotOptions?: XChartPlotOptions; xaxis?: XChartXAxis; yaxis?: XChartYAxis | XChartYAxis[]; colors?: Array string)>; /** Optional fill override (e.g. a pattern fill to visually distinguish drilled levels). */ fill?: XChartFill; /** Optional legend override (e.g. show a legend when a level is a pie/donut). */ legend?: XChartLegend; } export interface XChartDrilldownEvent { /** The level id navigated away from. */ from: string | number; /** The level id navigated to (`'root'` at the top). */ to: string | number; /** The clicked data point (drill-down only). */ point?: any; seriesIndex?: number; dataPointIndex?: number; } export interface XChartDrilldownContext { /** The requested level id, i.e. the clicked point's `drilldown` value. */ id: string | number | null; point: any; seriesIndex?: number; dataPointIndex?: number; } export interface XChartDrilldown { /** Master switch. When false the feature stays inert even if imported. */ enabled?: boolean; /** Inline child levels referenced by data-point `drilldown` ids. */ series?: XChartDrilldownSeries[]; breadcrumb?: | false | { show?: boolean; position?: 'top-left' | 'top-right'; separator?: string; rootLabel?: string; offsetX?: number; offsetY?: number; formatter?( label: string, opts: { index: number; depth: number }, ): string; }; animation?: { enabled?: boolean; /** * Anchor the drill transition at the clicked point: the child unfolds * outward from it (and settles back on drill-up) instead of the chart * simply re-rendering. A gentle scale layered on the SVG. Opt-in. * Defaults to false. */ zoomFromPoint?: boolean; /** Base transition duration in ms when `zoomFromPoint` is true. Default 260. */ speed?: number; }; /** * The dot marking a drillable point on a line/area chart drawn without * markers. A bar, slice, tile or cell is already a visible, clickable mark; * a line point is not, so without this nothing would show that a point can * be opened. Only drillable points get one. Set `show: false` to supply your * own affordance. Omitted colours inherit the series marker defaults. */ marker?: { /** Default true. */ show?: boolean; /** Radius in px. Default 6. */ size?: number; /** Defaults to the series marker shape. */ shape?: 'circle' | 'square' | 'rect'; /** Defaults to the series colour. */ fillColor?: string; /** Default '#fff'. */ strokeColor?: string; }; /** * Async resolver called when a drillable point has no inline `series` match. * * Failure never changes state: a throw, a rejection, or a resolved value * without a `data` array leaves the chart where it was and fires * `drillDownError`. A second click while one is in flight is ignored rather * than starting a second request. */ onDrillDown?( ctx: XChartDrilldownContext, ): XChartDrilldownSeries | Promise; /** * Overlay shown while an async level resolves. `text` is optional; with * none, the spinner shows alone and carries "Loading" as its accessible * name, so the default ships no user-visible English. */ loading?: | false | { show?: boolean; text?: string; }; /** * Cache levels resolved by `onDrillDown`, keyed by id, so drilling back down * a branch does not re-fetch. Default true. Clear it with the drilldown * module's `clearCache()` when the underlying data changes. */ cache?: boolean; } export type XChartForecastDataPoints = { count?: number; fillOpacity?: number; strokeWidth?: undefined | number; dashArray?: number; }; export type XChartGrid = { show?: boolean; borderColor?: string; strokeDashArray?: number; position?: 'front' | 'back'; xaxis?: { lines?: { show?: boolean; offsetX?: number; offsetY?: number; }; }; yaxis?: { lines?: { show?: boolean; offsetX?: number; offsetY?: number; }; }; row?: { colors?: string[]; opacity?: number; }; column?: { colors?: string[]; opacity?: number; }; padding?: { top?: number; right?: number; bottom?: number; left?: number; }; }; export type XChartNoData = { text?: string; align?: 'left' | 'right' | 'center'; verticalAlign?: 'top' | 'middle' | 'bottom'; offsetX?: number; offsetY?: number; style?: { color?: string; fontSize?: string; fontFamily?: string; }; }; export interface XChartPluginActivation { name: string; options?: Record; order?: number; } export type XChartResponsive = { breakpoint?: number; options?: XChartOptions; }; export type XChartStates = { hover?: { filter?: { type?: 'none' | 'lighten' | 'darken'; /** * Blend strength toward white (lighten) or black (darken), from 0 to 1. * Higher means a stronger effect. The shift is proportional to the base * color's head-room, so already-light colors are lightened only slightly * (and already-dark colors darkened only slightly) and never wash out. * @default 0.15 */ value?: number; }; }; active?: { allowMultipleDataPointsSelection?: boolean; filter?: { type?: 'none' | 'lighten' | 'darken'; /** * Blend strength toward white (lighten) or black (darken), from 0 to 1. * Higher means a stronger effect. * @default 0.35 */ value?: number; }; }; }; export type XChartStroke = { show?: boolean; curve?: | 'smooth' | 'straight' | 'stepline' | 'linestep' | 'monotoneCubic' | ('smooth' | 'straight' | 'stepline' | 'linestep' | 'monotoneCubic')[]; lineCap?: 'butt' | 'square' | 'round'; colors?: string[]; width?: number | number[]; dashArray?: number | number[]; fill?: XChartFill; }; export type XChartTitleSubtitle = { text?: string; align?: 'left' | 'center' | 'right'; margin?: number; offsetX?: number; offsetY?: number; floating?: boolean; style?: { fontSize?: string; fontFamily?: string; fontWeight?: string | number; color?: string; }; }; export type XChartTheme = { /** '' (the default) inherits / auto-resolves; 'light' | 'dark' force a mode. */ mode?: 'light' | 'dark' | ''; palette?: string; /** * Facet (#13): read `--apx-*` CSS design tokens from the cascade * (`--apx-accent`, `--apx-fore`, `--apx-grid`, `--apx-surface`, * `--apx-series-1..N`). They top the resolution chain, below explicit config. * true (default) reads any present (absence is a no-op); false disables. * Tokens are re-read on each render; use `chart.refreshTokens()` after a * runtime CSS change that does not itself trigger a render. */ tokens?: boolean; /** * Facet (#13): 'os' follows the operating system's `prefers-color-scheme` * (light/dark) and `prefers-contrast` reactively, with no JS. SSR-safe. */ follow?: 'os' | false; /** Facet (#13): a theme registered via `ApexCharts.registerTheme(name, def)`. */ name?: string; monochrome?: { enabled?: boolean; color?: string; shadeTo?: 'light' | 'dark'; shadeIntensity?: number; }; accessibility?: { colorBlindMode?: | 'deuteranopia' | 'protanopia' | 'tritanopia' | 'highContrast' | ''; }; }; export type XChartTooltipCustomOpts = { series: number[][]; seriesIndex: number; dataPointIndex: number; y1?: number; y2?: number; w: XChartContext; }; export type XChartTooltipY = { title?: { formatter?(seriesName: string, opts?: XChartFormatterOpts): string; }; formatter?(val: number, opts?: XChartFormatterOpts): string; }; export type XChartTooltip = { enabled?: boolean; enabledOnSeries?: undefined | number[]; shared?: boolean; followCursor?: boolean; intersect?: boolean; inverseOrder?: boolean; arrow?: boolean; custom?: | (( opts: XChartTooltipCustomOpts, ) => string | number | Element | { nodeName: string }) | Array< ( opts: XChartTooltipCustomOpts, ) => string | number | Element | { nodeName: string } >; fillSeriesColor?: boolean; theme?: 'light' | 'dark'; cssClass?: string; hideEmptySeries?: boolean; style?: { fontSize?: string; fontFamily?: string; background?: string; }; onDatasetHover?: { highlightDataSeries?: boolean; }; x?: { show?: boolean; format?: string; formatter?(val: string | number, opts?: XChartFormatterOpts): string; }; y?: XChartTooltipY | XChartTooltipY[]; z?: { title?: string; formatter?(val: number): string; }; marker?: { show?: boolean; fillColors?: string[]; }; items?: { display?: string; }; fixed?: { enabled?: boolean; position?: string; // topRight; topLeft; bottomRight; bottomLeft offsetX?: number; offsetY?: number; }; }; export interface XChartOptions { annotations?: XChartAnnotations; chart?: XChart; /** * Series colors. Each entry is either a CSS color string (hex, rgb, hsl, * named) or a function returning one per-datapoint. The list cycles when * there are more series than colors. */ colors?: Array string)>; dataLabels?: XChartDataLabels; /** Opt-in drilldown navigation. Requires `import 'apexcharts/features/drilldown'`. */ drilldown?: XChartDrilldown; fill?: XChartFill; forecastDataPoints?: XChartForecastDataPoints; grid?: XChartGrid; labels?: string[]; legend?: XChartLegend; markers?: XChartMarkers; noData?: XChartNoData; /** Weave (#1) plugin activation list. Requires `import 'apexcharts/features/weave'`. */ plugins?: XChartPluginActivation[]; plotOptions?: XChartPlotOptions; responsive?: XChartResponsive[]; parsing?: XChartParsing; series?: XChartSeriesType; states?: XChartStates; stroke?: XChartStroke; subtitle?: XChartTitleSubtitle; theme?: XChartTheme; title?: XChartTitleSubtitle; tooltip?: XChartTooltip; xaxis?: XChartXAxis; yaxis?: XChartYAxis | XChartYAxis[]; } export type XChart = { width?: string | number; height?: string | number; type?: | 'line' | 'area' | 'bar' | 'pie' | 'donut' | 'radialBar' | 'scatter' | 'bubble' | 'heatmap' | 'candlestick' | 'boxPlot' | 'violin' | 'histogram' | 'radar' | 'polarArea' | 'rangeBar' | 'rangeArea' | 'treemap' | 'unit' | 'waffle' | 'sunburst' | 'funnel' | 'pyramid' | 'gauge'; /** * Internal — populated when `type` is a first-class alias (`'funnel'`, * `'pyramid'`, `'gauge'`, `'waffle'`, `'histogram'`). The original requested * type is preserved here while `type` is normalized to the underlying * renderer (`'bar'`, `'radialBar'` or `'unit'`). Read-only for consumers. */ requestedType?: 'funnel' | 'pyramid' | 'gauge' | 'waffle' | 'histogram'; foreColor?: string; fontFamily?: string; background?: string; offsetX?: number; offsetY?: number; dropShadow?: XChartDropShadow & { enabledOnSeries?: undefined | number[]; }; nonce?: string; events?: { animationEnd?(chart: ApexCharts, options?: XChartEventOpts): void; beforeMount?(chart: ApexCharts, options?: XChartEventOpts): void; mounted?(chart: ApexCharts, options?: XChartEventOpts): void; updated?(chart: ApexCharts, options?: XChartEventOpts): void; mouseMove?( e: MouseEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; mouseLeave?( e: MouseEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; click?(e: MouseEvent, chart?: ApexCharts, options?: XChartEventOpts): void; xAxisLabelClick?( e: MouseEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; legendClick?( chart: ApexCharts, seriesIndex?: number, options?: XChartEventOpts, ): void; markerClick?( e: MouseEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; selection?( chart: ApexCharts, options?: { xaxis?: { min: number; max: number }; yaxis?: { min: number; max: number }; }, ): void; dataPointSelection?( e: MouseEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; dataPointMouseEnter?( e: MouseEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; dataPointMouseLeave?( e: MouseEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; beforeZoom?( chart: ApexCharts, options?: { xaxis: { min: number; max: number } }, ): boolean | void; beforeResetZoom?( chart: ApexCharts, options?: XChartEventOpts, ): boolean | void; zoomed?( chart: ApexCharts, options?: { xaxis: { min: number; max: number }; yaxis?: { min: number; max: number }[]; }, ): void; scrolled?( chart: ApexCharts, options?: { xaxis: { min: number; max: number } }, ): void; brushScrolled?( chart: ApexCharts, options?: { xaxis: { min: number; max: number }; yaxis?: { min: number; max: number }[]; }, ): void; /** * Linked Views (#4): fired on the source chart when a brush range drives a * crossfilter across the group. */ crossFilter?( chart: ApexCharts, options?: { xaxis: { min: number; max: number }; sourceChartID?: string }, ): void; /** * Linked Views (#4) FILTER mode: fired on the source chart when a click * toggles a crossfilter bucket. `options` carries the coordinator state * (active filters, filtered/total counts), the source chartID, and the key. */ filterChange?( chart: ApexCharts, options?: { filters: Record; filteredCount: number; total: number; sourceChartID?: string; key?: any; }, ): void; /** * Ink Layer (#7): fired after an annotation is dragged or resized. `options` * carries the annotation type ('point' | 'xaxis' | 'yaxis'), id/index, and * the new data coordinates (x/y, plus x2/y2 for range annotations). */ annotationDragged?( chart: ApexCharts, options?: { type?: 'point' | 'xaxis' | 'yaxis'; id?: string; index: number; x: any; y: any; x2?: any; y2?: any; }, ): void; /** * Ink Layer (#7): fired after a point annotation's label is edited inline. * `options` carries the annotation id/index and the new label text. */ annotationEdited?( chart: ApexCharts, options?: { type?: 'point' | 'xaxis' | 'yaxis'; id?: string; index: number; text: string; }, ): void; /** * Ink Layer (#7): fired after an annotation is created by clicking the * plot in create mode or from the context menu (note or dashed line). * `options` carries the new annotation type/id/index and its x and/or y. */ annotationCreated?( chart: ApexCharts, options?: { type?: 'point' | 'xaxis' | 'yaxis'; id?: string; index: number; x?: any; y?: any; }, ): void; /** * Ink Layer (#7): fired after an annotation is restyled from the floating * note editor (accent color, bold, font size, marker size/shape). `options` * carries the annotation type/id/index and its current label + marker config. */ annotationStyled?( chart: ApexCharts, options?: { type?: 'point' | 'xaxis' | 'yaxis'; id?: string; index: number; label?: any; marker?: any; }, ): void; /** * Ink Layer (#7): fired after an annotation is deleted from the floating * note editor. `options` carries the annotation type/id and the index it * occupied before removal. */ annotationDeleted?( chart: ApexCharts, options?: { type?: 'point' | 'xaxis' | 'yaxis'; id?: string; index: number; }, ): void; /** * Measure ruler (#18): fired when a measure ruler is drawn. Requires the * `measure` feature. `options` carries the endpoints and the deltas. */ measured?( chart: ApexCharts, options?: { from: { x: any; y: any }; to: { x: any; y: any }; dx: number; dy: number; percentChange: number; slope: number; }, ): void; /** * Storyboard: fired when scrolling (or goTo) activates a beat. Requires * the `storyboard` feature and an active chart.storyboard.bind(). */ beatChange?(chart: ApexCharts, options?: XChartStoryboardBeatInfo): void; keyDown?( e: KeyboardEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; keyUp?( e: KeyboardEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; /** Fired before a drill-down transition begins. Requires the Drilldown feature. */ drillDownStart?( info: ApexCharts.ApexDrilldownEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; /** Fired after a drill-down transition completes. Requires the Drilldown feature. */ drillDownEnd?( info: ApexCharts.ApexDrilldownEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; /** Fired after navigating back up a drilldown level. Requires the Drilldown feature. */ drillUp?( info: ApexCharts.ApexDrilldownEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; /** Fired when an async onDrillDown resolver throws or rejects. Requires the Drilldown feature. */ drillDownError?( info: { id: string | number | null; error: any }, chart?: ApexCharts, options?: XChartEventOpts, ): void; }; brush?: { enabled?: boolean; autoScaleYaxis?: boolean; target?: string; targets?: string[]; }; /** * Linked Views (#4): crossfilter / linked highlighting. Requires the `link` * feature (`import 'apexcharts/features/link'`). Two modes: * * HIGHLIGHT (P1): `enabled` with no `dimension`. Charts sharing a * `chart.group` form a set; brushing a range (needs `chart.selection.enabled`) * on any member dims every member's marks whose x is outside the range, in * place (no re-render). * * FILTER (P2): set `dimension` (its presence selects this path). Each chart * declares a dimension + reduction over a shared record set registered with * `ApexCharts.crossfilter({ id, records })`; clicking a bucket re-aggregates * every other participating chart over the filtered subset. */ link?: { /** @default false */ enabled?: boolean; /** Highlight mode (P1) label; filter mode is selected by `dimension`. @default 'highlight' */ mode?: 'highlight' | 'filter'; /** Opacity applied to dimmed (unselected / out-of-range) marks. @default 0.2 */ dimOpacity?: number; /** FILTER mode: crossfilter coordinator id (defaults to `chart.group`). */ id?: string; /** * FILTER mode: `(row) => key`. Its presence selects filter mode. For a * heatmap (matrix) dimension it returns `[xKey, yKey]`. */ dimension?: (row: any) => any; /** FILTER mode: reduction over a bucket's rows. @default 'count' */ reduce?: | 'count' | { sum?: string; avg?: string; min?: string; max?: string } | ((rows: any[]) => number); /** * FILTER mode: bucket kind. Else inferred: `bins` present => 'range', a * heatmap chart => 'matrix' (2D), otherwise 'category'. */ type?: 'category' | 'range' | 'matrix'; /** FILTER mode (range dims): binning spec. */ bins?: { width?: number; count?: number; thresholds?: number[] }; /** FILTER mode (category dims): key ordering. @default 'first-seen' */ order?: 'first-seen' | 'asc' | 'desc' | ((a: any, b: any) => number); /** FILTER mode (axis charts): the derived series name. @default 'Count' */ seriesName?: string; }; /** * Ink Layer (#7): direct-manipulation annotations. When enabled, every point * annotation is draggable (unless it sets `draggable:false`); or opt in per * annotation with `annotations.points[].draggable`. Clicking an ink-managed * annotation opens a floating editor card anchored to it: rename inline, * recolor via accent swatches, toggle bold, step the font size, size/reshape * the marker, or delete the note. Axis-line annotations get separate Label * and Line color rows, so restyling the label chip never touches the stroke. * Requires the `ink` feature (`import 'apexcharts/features/ink'`). Fires the * `annotationDragged`, `annotationEdited`, `annotationStyled` and * `annotationDeleted` events. */ ink?: { /** @default false */ enabled?: boolean; /** * Show a minimal "add note" tool palette; clicking it arms create mode (the * next plot click drops an editable, draggable annotation). @default false */ palette?: boolean; /** * Snap a dragged point / axis-line annotation to the nearest gridline * (numeric x + linear y). @default false */ snap?: boolean; /** * Accent swatches offered by the floating note editor. Defaults to a * built-in 6-color palette when omitted. */ noteColors?: string[]; }; /** * Measure ruler (#18): a measure/delta ruler. Requires the `measure` * feature (`import 'apexcharts/features/measure'`). Hold `key` and drag * A->B on the plot, or call `chart.startMeasure()`, to read * dx/dy/%change/slope in data space; on release the ruler pins as a * data-anchored overlay that re-projects on zoom/resize. Fires `measured`. */ measure?: { /** @default false */ enabled?: boolean; /** * 'span': finance-style vertical band between two x-positions with a * change/%/range readout, endpoints snapped to the first series. 'free': * a diagonal ruler between two arbitrary points. @default 'span' */ mode?: 'span' | 'free'; /** Key held to arm a drag when not in sticky mode. @default 'm' */ key?: string; /** Pin the ruler as a data-anchored overlay on release. @default true */ pinOnRelease?: boolean; /** * Semantic colors. Every element also has a stable CSS class and a * direction class (apexcharts-measure-up|down|flat) for stylesheet theming. */ colors?: { up?: string; down?: string; neutral?: string; guide?: string }; /** Span mode: draw the shaded band between the two x-positions. @default true */ band?: boolean; /** Span mode: draw the vertical dashed reference lines. @default true */ guides?: boolean; /** Draw the endpoint dots on the series line. @default true */ markers?: boolean; /** Value formatters for the readout. */ format?: { x?: (x: number) => string; y?: (y: number) => string; percent?: (pct: number) => string; }; /** * Full readout override. Receives the measure info and returns a string or * an array of lines. Overrides the default readout text. */ label?: (info: { from: { x: any; y: any }; to: { x: any; y: any }; dx: number; dy: number; percentChange: number; slope: number; mode: 'span' | 'free'; }) => string | string[]; }; /** * Radial Actions (#chrome): right-click / long-press context menu. Requires * the `contextMenu` feature (`import 'apexcharts/features/context-menu'`). * Each action receives the clicked data coordinates, so verbs act at that * point rather than chart-wide. 'measure' is shown only when the measure tool * is enabled. When the ink feature is bundled, 'annotate' drops an * ink-managed note that opens its floating editor (rename, restyle, delete), * and 'xline' / 'yline' drop ink-managed dashed lines the same way ('xline' * vertical at the clicked x, 'yline' horizontal at the clicked y). */ contextMenu?: { /** @default false */ enabled?: boolean; /** * Ordered menu items: built-in ids and/or custom entries. @default * ['annotate','xline','yline','measure'] */ items?: Array< | 'annotate' | 'xline' | 'yline' | 'measure' | { id?: string; label?: string; icon?: string; onClick?: ( chart: ApexCharts, context: { x: any; y: any; seriesIndex: number | null; dataPointIndex: number | null; clientX: number; clientY: number; }, ) => void; } >; /** Override the built-in item labels. */ labels?: { annotate?: string; xline?: string; yline?: string; measure?: string; }; /** Text of the annotation dropped by the built-in 'annotate' item. @default 'Note' */ noteText?: string; /** * Shared styling for the built-in 'xline' ("Annotate here", vertical at * the clicked x) and 'yline' ("Mark this level", horizontal at the * clicked y) items. Lines only, never a range rectangle. With the ink * feature bundled the line opens the floating editor, whose Label and * Line color rows restyle the chip and the stroke independently, and is * draggable and undoable, like the note. */ line?: { /** Label drawn on the line. @default '' (no label) */ text?: string; /** @default 4 */ strokeDashArray?: number; /** Line color; omit to keep the annotation default. */ color?: string; }; }; id?: string; injectStyleSheet?: boolean; group?: string; /** * Per-chart license key for the gated premium features (storyboard, link / * crossfilter, ink, measure, contextMenu, perspectives, history). Overrides * ApexCharts.setLicense() and window.Apex.license for this chart. Without a * valid key those features still work but show an "APEXCHARTS" trial * watermark. Shared across the ApexCharts family. */ license?: string; locales?: XChartLocale[]; defaultLocale?: string; perspectives?: { serializeOptions?: string[]; }; history?: { enabled?: boolean; maxDepth?: number; coalesceMs?: number; keyboard?: boolean; }; /** Strata (#2) series renderer. Requires `import 'apexcharts/features/renderer-canvas'` for non-SVG. */ renderer?: 'svg' | 'canvas' | 'auto'; rendererThreshold?: number; layers?: { series?: 'svg' | 'canvas' | 'auto'; grid?: 'svg'; annotations?: 'svg'; dataLabels?: 'svg'; }; parentHeightOffset?: number; redrawOnParentResize?: boolean; redrawOnWindowResize?: boolean | ((...args: any[]) => boolean); sparkline?: { enabled?: boolean; }; stacked?: boolean; stackType?: 'normal' | '100%'; stackOnlyBar?: boolean; /** * Real-time streaming mode. When enabled, appendData() bounds memory * automatically: each series is trimmed to `maxPoints` (when set) or to the * visible `xaxis.range` window plus a small off-screen runway. The * constant-velocity scroll animation for windowed updates needs no opt-in. */ streaming?: { enabled?: boolean; /** Maximum points kept per series by appendData(). Unset: derived from * `xaxis.range` when that is set; otherwise no trimming occurs. */ maxPoints?: number; }; toolbar?: { show?: boolean; offsetX?: number; offsetY?: number; tools?: { download?: boolean | string; selection?: boolean | string; zoom?: boolean | string; zoomin?: boolean | string; zoomout?: boolean | string; pan?: boolean | string; reset?: boolean | string; /** * Measure ruler toggle. Shown only when `chart.measure.enabled` is true * and the `measure` feature is bundled. `false` keeps the ruler * key-driven only; a string supplies a custom SVG icon. */ measure?: boolean | string; customIcons?: { icon?: string; title?: string; index?: number; class?: string; click?( chart: ApexCharts, options?: XChartEventOpts, e?: MouseEvent, ): void; }[]; }; export?: { csv?: { filename?: undefined | string; columnDelimiter?: string; headerCategory?: string; headerValue?: string; categoryFormatter?(value?: string | number): string; valueFormatter?(value?: string | number): string; }; svg?: { filename?: undefined | string; }; png?: { filename?: undefined | string; }; width?: number; scale?: number; /** * Inline the `@font-face` rules for the fonts the chart actually uses * into the exported SVG/PNG as base64 data URIs. * * An exported SVG is a standalone document and cannot reach the page's * `@font-face` rules, so without this a custom font is replaced by a * generic fallback in the export. Cross-origin font files that deny CORS * are skipped and fall back as before. * * @default true */ embedFonts?: boolean; }; autoSelected?: 'zoom' | 'selection' | 'pan' | 'measure'; }; zoom?: { enabled?: boolean; type?: 'x' | 'y' | 'xy'; autoScaleYaxis?: boolean; /** * Cursor-anchored zoom on mouse wheel / trackpad. `'auto'` enables it only * when the toolbar's reset button is present, so an unintended scroll-zoom * is always undoable; `true` forces it on even with the toolbar hidden. * Requires `enabled: true`. * @default 'auto' */ allowMouseWheelZoom?: boolean | 'auto'; /** * Momentum: enable two-finger pinch-zoom on touch devices. Zooms the x-axis * around the pinch centroid, frame-by-frame. `'auto'` enables it only when * the toolbar's reset button is present; `true` forces it on even with the * toolbar hidden. Requires `enabled: true`. * @default 'auto' */ pinch?: boolean | 'auto'; zoomedArea?: { fill?: { color?: string; opacity?: number; }; stroke?: { color?: string; opacity?: number; width?: number; }; }; }; /** * Momentum: kinetic panning on touch. A one-finger pan released with velocity * keeps gliding and decelerates, clamping at the data edges. */ pan?: { /** @default true */ inertia?: boolean; /** Velocity decay applied each animation frame (0-1). @default 0.92 */ friction?: number; }; selection?: { enabled?: boolean; type?: string; fill?: { color?: string; opacity?: number; }; stroke?: { width?: number; color?: string; opacity?: number; dashArray?: number; }; xaxis?: { min?: number; max?: number; }; yaxis?: { min?: number; max?: number; }; }; animations?: { /** * Master switch. Each chart type gets a tailored initial-mount animation * by default (line/area pen-stroke draw, bar grow, scatter pop, heatmap * diagonal wave, treemap largest-first cascade, pie/donut/gauge sweep). * Set false to render charts without any animation. */ enabled?: boolean; /** Animation duration in ms (default 800). */ speed?: number; /** * Cadence (#6): easing for the generic tweens. See `ApexEasing` for the * complete built-in curve list and the accepted forms; register custom * names with `ApexCharts.registerEasing`. * @default 'easeInOutSine' */ easing?: XChartEasing; /** * Drives per-element stagger across all chart types. When enabled, bars, * heatmap cells, scatter points, and treemap tiles reveal in sequence; * line/area markers fade in progressively as the line draws. */ animateGradually?: { enabled?: boolean; /** Requested stagger step in ms; auto-capped per chart so total * stagger ≤ ~half the animation speed. */ delay?: number; }; /** Data-change (updateSeries) animation. Independent from initial mount. */ dynamicAnimation?: { enabled?: boolean; speed?: number; /** * Easing for data-change morphs only (same accepted forms as * `animations.easing`; see `ApexEasing`). Unset: inherits the * chart-wide easing, except detected streaming scrolls (appendData or * a shifted fixed-length window under `xaxis.range`) which default to * 'linear' so the window slides at constant velocity. */ easing?: XChartEasing; }; /** * Cross-type morph (updateOptions changing chart.type). Requires the * optional `apexcharts/features/morph` feature to be registered; without * that import these settings have no effect. Supported pairs include * bar ↔ pie/donut/radialBar/polarArea (and the trivial pie↔donut↔polarArea * cases). Falls back to instant snap when types or data shape are * incompatible. */ chartTypeMorph?: { enabled?: boolean; speed?: number; }; /** * When true (default), honors the OS-level prefers-reduced-motion media * query — all initial-mount animations are skipped and the chart renders * instantly. Set to false to override (e.g. for QA / demo screens). */ respectReducedMotion?: boolean; /** * Above this many data points (default 1000), the per-element morph + * stagger — which spins up one JS-driven animation timeline per path — is * replaced by a single GPU-composited opacity fade of the whole series. * Keeps initial render and zoom transitions smooth on large datasets * (e.g. thousands of candlesticks/bars). Set to 0 to always animate * per-element regardless of dataset size. */ largeDatasetThreshold?: number; }; accessibility?: { enabled?: boolean; description?: string; announcements?: { enabled?: boolean; }; keyboard?: { enabled?: boolean; navigation?: { enabled?: boolean; wrapAround?: boolean; }; }; }; dataReducer?: { enabled?: boolean; algorithm?: 'lttb'; targetPoints?: number; threshold?: number; }; }; //#endregion export enum XChartType { Bar = 'bar', Pie = 'pie', Line = 'line', Area = 'area', Unit = 'unit', Gauge = 'gauge', Donut = 'donut', Radar = 'radar', Waffle = 'waffle', Funnel = 'funnel', Violin = 'violin', Bubble = 'bubble', Scatter = 'scatter', Heatmap = 'heatmap', BoxPlot = 'boxPlot', Pyramid = 'pyramid', Treemap = 'treemap', Sunburst = 'sunburst', RangeBar = 'rangeBar', RadialBar = 'radialBar', Histogram = 'histogram', PolarArea = 'polarArea', RangeArea = 'rangeArea', Candlestick = 'candlestick', } export type XChartTypeIdentifier = XChartType | string; export function isChartType(value: string) { return isValueInEnum(value, Object.assign({}, XChartType)); } export enum XChartAction { Refresh = 'refresh', Destroy = 'destroy', UpdateSeries = 'update_series', UpdateOptions = 'update_options', } export type XChartActionIdentifier = XChartAction | string; export interface XChartActionModel extends XBaseActionModel {} export type XChartSeriesType = XChartAxisChartSeries | XChartNonAxisChartSeries; export interface IXChartContainer extends IXComponentCardContainer { // // Commons ... actionProvider: Subject; cssClass: XStandardType>; // // Chart Props ... autoUpdate: XStandardType; options: XStandardType; series: XStandardType; // type: XStandardType; // // Events ... chartRendered: EventEmitter; dataPointSelected: EventEmitter; zoomed: EventEmitter; } @Injectable({ providedIn: 'root', }) export class XChartContainer extends XComponentCardContainer implements Readonly { // readonly options: XStandardType; readonly series: XStandardType; readonly autoUpdate: XStandardType = true; readonly cssClass: XStandardType>; readonly actionProvider = new Subject(); readonly type: XStandardType = XChartType.Line; // readonly zoomed = new EventEmitter(); readonly chartRendered = new EventEmitter(); readonly dataPointSelected = new EventEmitter(); } @Injectable() @Component({ template: `` }) export abstract class XChartContainerComponent extends XComponentCardContainerComponent implements IXChartContainer { // //#region Props ... @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; /** * Specifiy Type of Chart Drawing ... */ @Input() type: XStandardType = this.propertyProvider.type; @Input() options: XStandardType = this.propertyProvider.options; @Input() series: XStandardType = this.propertyProvider.series; @Input() autoUpdate: XStandardType = this.propertyProvider.autoUpdate; // // Events ... @Output() chartRendered: EventEmitter = new EventEmitter(); @Output() dataPointSelected: EventEmitter = new EventEmitter(); @Output() zoomed: EventEmitter = new EventEmitter(); // //#region ComponentCard Props ... @Input() isInPage: XStandardType = this.propertyProvider.isInPage; @Input() wrapWithCard: XStandardType = this.propertyProvider.wrapWithCard; @Input() cardCssClass: XStandardType> = this.propertyProvider.cardCssClass; @Input() cardColor: XStandardType = this.propertyProvider.cardColor; @Input() cardForegroundColor: XStandardType = this.propertyProvider.cardForegroundColor; @Input() cardTitle: XStandardType = this.propertyProvider.cardTitle; @Input() cardSubTitle: XStandardType = this.propertyProvider.cardSubTitle; @Input() cardShowFooter: XStandardType = this.propertyProvider.cardShowFooter; @Input() cardShowActions: XStandardType = this.propertyProvider.cardShowActions; @Input() cardActionProvider: Subject = this.propertyProvider.cardActionProvider; //#endregion //#endregion // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XChartContainer, ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider, ); } //#endregionّ // //#region Abstract ... public extractProps( container?: IXChartContainer, ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // cssClass: this.getArrayValue( container ? container.cssClass : this.cssClass, ), // type: this.getValue(container ? container.type : this.type), options: this.getValue( container ? container.options : this.options, ), series: this.getValue(container ? container.series : this.series), autoUpdate: this.getValue( container ? container.autoUpdate : this.autoUpdate, ), }).pipe( map((data) => { return { superData, data, }; }), ); }), ) .pipe( map((info) => ({ ...info.data, ...info.superData, actionProvider: container ? container.actionProvider : this.actionProvider, chartRendered: this.chartRendered, dataPointSelected: this.dataPointSelected, zoomed: this.zoomed, })), ); } //#endregion }