Files
xSaherelmWorkspace/Documents/GeneratedContext/xDashboard-x-chart-20260821_211240.txt
2026-08-22 00:08:06 +03:30

3880 lines
115 KiB
Plaintext

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-chart\x-chart.component.html
<!-- Component Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentsRef">
<x-card
class="x-card"
[showActions]="true"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[subTitle]="getResourceValue(cardSubTitle)"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="componentsRef"></ng-container>
<!-- Actions -->
<div class="x-actions" [ngClass]="getValue(cssClass) | async" actions>
<ng-content select="[actions]"></ng-content>
</div>
<!-- Footer -->
<div footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Component's itSelf Template -->
<ng-template #componentsRef>
<!-- Component Box ... -->
<div
class="x-chart x-wrapper"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
>
<div #chartContainer class="x-chart-container"></div>
</div>
</ng-template>
### 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<XChartComponent>('autoUpdate'),
);
if (isAutoUpdateChanged) {
//
if (isNullOrUndefined(this.autoUpdate)) {
this.autoUpdate = this.propertyProvider.autoUpdate;
}
}
//
// Action Provider Changed ...
const isActionProviderChanged = changeKeys.includes(
nameof<XChartComponent>('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<XChartComponent>('options'),
);
if (isOptionsChanged) {
//
if (isNullOrUndefined(this.options)) {
this.options = this.propertyProvider.options;
}
//
await this.handleChartUpdate();
}
//
// Chart Type ...
const isTypeChanged = changeKeys.includes(
nameof<XChartComponent>('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<XChartComponent>('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<string, any>`.
| XChartHierarchyNode[]
| Record<string, any>[];
}[];
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
* `"<seriesIndex>:<dataPointIndex>"`.
*/
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: '<id>'` 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 `"#<dataPointIndex+1> of <count>"`.
*/
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<string | number> | Array<Array<string | number>>;
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<XChart, 'type' | 'stacked' | 'stackType'>;
plotOptions?: XChartPlotOptions;
xaxis?: XChartXAxis;
yaxis?: XChartYAxis | XChartYAxis[];
colors?: Array<string | ((opts: XChartColorFormatterOpts) => 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<XChartDrilldownSeries>;
/**
* 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<string, any>;
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 | ((opts: XChartColorFormatterOpts) => 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<string, any>;
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<XChartActionIdentifier> {}
export type XChartSeriesType = XChartAxisChartSeries | XChartNonAxisChartSeries;
export interface IXChartContainer extends IXComponentCardContainer {
//
// Commons ...
actionProvider: Subject<XChartActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
// Chart Props ...
autoUpdate: XStandardType<boolean>;
options: XStandardType<XChartOptions>;
series: XStandardType<XChartSeriesType>;
//
type: XStandardType<XChartTypeIdentifier>;
//
// Events ...
chartRendered: EventEmitter<void>;
dataPointSelected: EventEmitter<any>;
zoomed: EventEmitter<any>;
}
@Injectable({
providedIn: 'root',
})
export class XChartContainer
extends XComponentCardContainer
implements Readonly<IXChartContainer>
{
//
readonly options: XStandardType<XChartOptions>;
readonly series: XStandardType<XChartSeriesType>;
readonly autoUpdate: XStandardType<boolean> = true;
readonly cssClass: XStandardType<XOneOrManyType<string>>;
readonly actionProvider = new Subject<XChartActionModel>();
readonly type: XStandardType<XChartTypeIdentifier> = XChartType.Line;
//
readonly zoomed = new EventEmitter<any>();
readonly chartRendered = new EventEmitter<void>();
readonly dataPointSelected = new EventEmitter<any>();
}
@Injectable()
@Component({ template: `` })
export abstract class XChartContainerComponent
extends XComponentCardContainerComponent
implements IXChartContainer
{
//
//#region Props ...
@Input()
actionProvider: Subject<XChartActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
/**
* Specifiy Type of Chart Drawing ...
*/
@Input()
type: XStandardType<XChartTypeIdentifier> = this.propertyProvider.type;
@Input()
options: XStandardType<XChartOptions> = this.propertyProvider.options;
@Input()
series: XStandardType<XChartSeriesType> = this.propertyProvider.series;
@Input()
autoUpdate: XStandardType<boolean> = this.propertyProvider.autoUpdate;
//
// Events ...
@Output()
chartRendered: EventEmitter<void> = new EventEmitter();
@Output()
dataPointSelected: EventEmitter<any> = new EventEmitter();
@Output()
zoomed: EventEmitter<any> = new EventEmitter();
//
//#region ComponentCard Props ...
@Input()
isInPage: XStandardType<boolean> = this.propertyProvider.isInPage;
@Input()
wrapWithCard: XStandardType<boolean> = this.propertyProvider.wrapWithCard;
@Input()
cardCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cardCssClass;
@Input()
cardColor: XStandardType<XColorIdentifier> = this.propertyProvider.cardColor;
@Input()
cardForegroundColor: XStandardType<boolean> =
this.propertyProvider.cardForegroundColor;
@Input()
cardTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardTitle;
@Input()
cardSubTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardSubTitle;
@Input()
cardShowFooter: XStandardType<boolean> = this.propertyProvider.cardShowFooter;
@Input()
cardShowActions: XStandardType<boolean> =
this.propertyProvider.cardShowActions;
@Input()
cardActionProvider: Subject<XCardActionModel> =
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<IXChartContainer> {
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
}