diff --git a/Documents/GeneratedContext/xDashboard-x-chart-20260821_211240.txt b/Documents/GeneratedContext/xDashboard-x-chart-20260821_211240.txt
new file mode 100644
index 0000000..8e30fa6
--- /dev/null
+++ b/Documents/GeneratedContext/xDashboard-x-chart-20260821_211240.txt
@@ -0,0 +1,3879 @@
+
+### 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
+}
diff --git a/Modules/xFrameworkComponentsHolder b/Modules/xFrameworkComponentsHolder
index 0f37e94..e768ba2 160000
--- a/Modules/xFrameworkComponentsHolder
+++ b/Modules/xFrameworkComponentsHolder
@@ -1 +1 @@
-Subproject commit 0f37e94ac9c5b3dbab4f77b726a5e84b1c5da7da
+Subproject commit e768ba219c783bdb81d222d14c5fd03dac67957d