cats-charts
v0.0.88
Published
   
Readme
CATS4U Charts
CATS4U Charts is a reusable Angular chart library built on Apache ECharts and ngx-echarts. It provides easy-to-use components for rendering interactive charts such as Bar, Line, Area, Pie, Doughnut, Sankey, Timeline, and more.
✨ Features
- 📊 Multiple chart types
- ⚡ Powered by Apache ECharts
- 🔌 Angular Standalone Components
- 🎨 Built-in theme support
- 🖱 Click & drill-down events
- 🧩 Easy integration
- 📦 Lightweight and reusable
📦 Installation
Install the package along with required dependencies:
npm install cats-charts
🚀 Usage
Import Library
import { ChartsLib } from 'cats-charts';TS Syntax
import {
BarChart,
CustomChartComponent,
DoughnutChart,
LinesChart,
PieChart,
SankeyChart
} from 'cats-charts';
@Component({
...,
imports: [
BarChart,
CustomChartComponent,
DoughnutChart,
LinesChart,
PieChart,
SankeyChart
],
})
export class App {}⚙️ Inputs
| Input | Type | Description | | ------------------ | ------------------------------------------------- | -------------------------------------------------------------- | | config | | Configuration options to customize chart and pass dynamic data | | theme | string | default | dark | vintage | essos | chalk | roma | | contextMenuOptions | { label: string; value: string; icon?: string }[] | Context menu options | | events | string[] | ['click', 'contextmenu', 'dblclick'] |
📤 Outputs
| Output | Description | | ---------------- | ---------------------- | | contextMenuClick | ( event: any ) => void | | chartEvent | ( event: any ) => void |
Bar chart config
BarChartConfig {
series: {
name: string;
data: number[];
[key: string]: any;
}[];
xAxisData: string[];
colors?: string[];
backgroundColor?: string;
// --------------- Title configs ---------------
title?: string;
titlePosition?: string;
showTitle?: boolean;
// --------------- Tooltip configs ---------------
showTooltip?: boolean;
tooltipFormatter?: (params: any) => void;
// --------------- Grid configs ---------------
gridLeft?: string | number;
gridRight?: string | number;
gridBottom?: string | number;
gridTop?: string | number;
// --------------- Zoom Slider configs ---------------
showZoomSlider?: boolean;
zoomStart?: number;
zoomEnd?: number;
zoomControlButtonStyle?: any;
yAxis?: any;
xAxis?: any;
stacked?: boolean;
barWidth?: string | number;
borderRadius?: number;
showLabel?: boolean;
labelPosition?: string;
showXAxisLine?: boolean;
showYAxisLine?: boolean;
// Legend
hideLegend?: boolean;
legendPosition?: 'top' | 'bottom' | 'left' | 'right' | string;
legendAlign?: 'left' | 'center' | 'right' | string;
legendDirection?: 'horizontal' | 'vertical' | string;
legendTextColor?: string;
legendFontSize?: number;
legendContainerWidth?: number; // 0-1
legendIndicatorHeight?: number; // number value is in px
}Line and Area Chart config
LineChartConfig {
isTrendChart?: boolean;
title?: string;
showTitle?: boolean;
titlePosition?: string;
xAxisData: string[];
tooltipFormatter?: (params: any) => void;
colors?: string[];
series: {
name: string;
data: number[];
areaColor?: string;
smooth?: boolean;
area?: boolean;
[key: string]: any;
}[];
// --------------- Grid configs ---------------
gridLeft?: string | number;
gridRight?: string | number;
gridBottom?: string | number;
gridTop?: string | number;
borderRadius?: number;
showLabel?: boolean;
labelPosition?: string;
yAxis?: any;
xAxis?: any;
showXAxisLine?: boolean;
showYAxisLine?: boolean;
showTooltip?: boolean;
backgroundColor?: string;
// Legend
hideLegend?: boolean;
legendPosition?: 'top' | 'bottom' | 'left' | 'right' | string;
legendAlign?: 'left' | 'center' | 'right' | string;
legendDirection?: 'horizontal' | 'vertical' | string;
legendTextColor?: string;
legendFontSize?: number;
legendContainerWidth?: number; // 0-1
legendIndicatorHeight?: number; // number value is in px
customLegend?: ChartLegendConfig<LineChartConfig['series'][number]>;
}CustomLegend
type customLegend = {
enabled?: boolean;
// layout/positioning
layout?: 'horizontal' | 'vertical';
position?: 'top' | 'bottom' | 'left' | 'right';
align?: 'start' | 'center' | 'end';
// selection behavior
selectionMode?: 'multiple' | 'single' | 'exclusive';
// scrolling / pagination
scrollable?: boolean;
maxHeight?: string;
maxWidth?: string;
pageSize?: number;
showPagination?: boolean;
// disabling items
disabled?: boolean;
disabledNames?: string[];
// accessibility / styling
className?: string;
ariaLabel?: string;
legendTextColor?: string;
legendFontSize?: number;
// icon rendering
icon?: ChartLegendIcon | ((series: TSeries, index: number) => ChartLegendIcon);
icons?: Record<string, ChartLegendIcon>;
// label formatting
formatter?: (name: string, item: ChartLegendItem) => string;
tooltipFormatter?: (item: ChartLegendItem) => string;
// grouping
groupBy?: (item: ChartLegendItem) => string | undefined;
// custom Angular template
itemTemplate?: TemplateRef<ChartLegendTemplateContext>;
// virtualization (advanced)
virtualize?: boolean;
virtualItemHeight?: number;
// hover behavior linking
hoverLink?: boolean;
};CustomLegend Example
customLegend?: {
// enable/disable legend UI
enabled?: boolean;
// layout
layout?: 'horizontal' | 'vertical';
position?: 'top' | 'bottom' | 'left' | 'right';
align?: 'start' | 'center' | 'end';
// selection behavior
selectionMode?: 'multiple' | 'single' | 'exclusive';
// scrolling/pagination
scrollable?: boolean;
maxHeight?: string;
maxWidth?: string;
pageSize?: number;
showPagination?: boolean;
// disabling items
disabled?: boolean;
disabledNames?: string[];
// styling & accessibility
className?: string;
ariaLabel?: string;
legendTextColor?: string;
legendFontSize?: number;
// icon configuration
// - either a static icon
// - or a function that returns an icon per series/index
icon?:
| ChartLegendIcon
| ((series: TSeries, index: number) => ChartLegendIcon);
// mapping of icon names -> icon types
icons?: Record<string, ChartLegendIcon>;
// text formatting
formatter?: (name: string, item: ChartLegendItem) => string;
// tooltip formatting
tooltipFormatter?: (item: ChartLegendItem) => string;
// grouping
groupBy?: (item: ChartLegendItem) => string | undefined;
// custom Angular template (advanced)
itemTemplate?: TemplateRef<ChartLegendTemplateContext>;
// virtualization (advanced)
virtualize?: boolean;
virtualItemHeight?: number;
// hover linking (advanced)
hoverLink?: boolean;
};
Pie and Donut chart config
DoughnutChartConfig {
title?: string;
showTitle?: boolean;
titlePosition?: 'left' | 'center' | 'right';
top?: any;
bottom?: any;
backgroundColor?: string;
series?: any;
data: {
name: string;
value: number;
[key: string]: any;
}[];
colors?: string[];
// Doughnut
innerRadius?: string;
outerRadius?: string;
center?: string[];
// Center Text
showCenterText?: boolean;
centerLabel?: any;
centerValue?: string;
centerValueFromTotal?: boolean;
// Tooltip
showTooltip?: boolean;
showTooltipPercent?: boolean;
tooltipFormatter?: (params: any, config: DoughnutChartConfig) => void;
valueFormatter?: (value: number) => string;
// Legend
hideLegend?: boolean;
legendBottom?: number;
legendPosition?: 'top' | 'bottom' | 'left' | 'right' | string;
legendAlign?: 'left' | 'center' | 'right' | string;
legendDirection?: 'horizontal' | 'vertical' | string;
legendTextColor?: string;
legendFontSize?: number;
legendContainerWidth?: number; // 0-1
// Labels
showLabel?: boolean;
labelPosition?: 'inside' | 'outside' | 'center';
showLabelValue?: boolean;
showLabelPercentage?: boolean;
// Emphasis
emphasisScale?: boolean;
// Style
borderRadius?: number;
borderColor?: string;
borderWidth?: number;
enableHoverEffect?: boolean;
}Custom chart config
CustomChartConfig {
startHour?: string;
endHour?: string;
shiftColor?: string;
chartMode: 'weekly' | 'daily' | string;
yAxisData: string[];
categories: string[];
legends: TimeLineLegends;
barHeight?: number;
shiftHeight?: number;
data: TimelineData[];
hideLegendCategory?: boolean;
}Scatter Chart config
ScatterChartConfig {
title?: string;
showTitle?: boolean;
titlePosition?: string;
tooltipFormatter?: (params: any) => void;
colors?: string[];
series: {
name: string;
data: number[];
[key: string]: any;
}[];
// --------------- Grid configs ---------------
gridLeft?: string | number;
gridRight?: string | number;
gridBottom?: string | number;
gridTop?: string | number;
labelPosition?: string;
yAxis?: any;
xAxis?: any;
showXAxisLine?: boolean;
showYAxisLine?: boolean;
showTooltip?: boolean;
backgroundColor?: string;
// Legend
hideLegend?: boolean;
legendPosition?: 'top' | 'bottom' | 'left' | 'right' | string;
legendAlign?: 'left' | 'center' | 'right' | string;
legendDirection?: 'horizontal' | 'vertical' | string;
legendTextColor?: string;
legendFontSize?: number;
legendContainerWidth?: number; // 0-1
legendIndicatorHeight?: number; // number value is in px
xAxisName?: string;
yAxisName?: string;
}Sankey Chart config
SankeyChartConfig {
title?: string;
showTitle?: boolean;
backgroundColor?: string;
colors?: string[];
showTooltip?: boolean;
tooltipFormatter?: (params: any) => string;
nodes: SankeyNode[];
links: SankeyLink[];
seriesOption?: SankeySeriesOption;
lineCurveness?: number;
}For SankeySeriesOption refer echarts Sankey series documentation
https://echarts.apache.org/en/option.html#series-sankey
📊 Supported Charts
- Bar Chart
- Line Chart
- Area Chart
- Pie Chart
- Doughnut Chart
- Stacked Area Chart
- Sankey Chart
- Heatmap Chart
- Custom Charts
- Bar Chart
- Line Chart
- Area Chart
- Pie Chart
- Doughnut Chart
- Stacked Area Chart
- Sankey Chart
- Custom Charts
Heatmap Chart
The heatmap component renders category-based intensity data using Apache ECharts.
Use [xIndex, yIndex, value] tuples, where xIndex points to xAxisData and yIndex points to yAxisData.
Import
import { Heatmap } from 'cats-charts';
@Component({
selector: 'app-root',
standalone: true,
imports: [Heatmap],
templateUrl: './app.html',
})
export class App {}HTML
<div style="width: 100%; height: 340px">
<lib-heatmap
[config]="heatmapConfig"
[theme]="selectedTheme"
[events]="['click', 'contextmenu']"
(chartEvent)="handleChartEvent($event)"
></lib-heatmap>
</div>TypeScript
heatmapConfig = {
xAxisData: ['00:00', '01:00', '02:00', '03:00', '04:00', '05:00'],
yAxisData: ['eth0', 'eth1', 'wlan0', 'vlan10', 'vlan20'],
data: [
[0, 0, 20],
[1, 0, 60],
[2, 0, 0],
[3, 0, 40],
[4, 0, 80],
[5, 0, 100],
[0, 1, 40],
[1, 1, 0],
[2, 1, 20],
[3, 1, 60],
[4, 1, 100],
[5, 1, 80],
] as [number, number, number][],
min: 0,
max: 100,
showTooltip: true,
grid: {
left: 58,
right: 18,
top: 20,
bottom: 46,
containLabel: false,
},
xAxis: {
axisLabel: { color: '#6b7280' },
axisLine: { lineStyle: { color: '#9ca3af' } },
axisTick: { show: true },
},
yAxis: {
inverse: true,
axisLabel: { color: '#6b7280' },
axisLine: { show: false },
axisTick: { show: true },
},
visualMap: {
type: 'piecewise',
pieces: [
{ min: 0, max: 20, label: '20%', color: '#fde6bd' },
{ min: 21, max: 40, label: '40%', color: '#ffd85a' },
{ min: 41, max: 60, label: '60%', color: '#ffb247' },
{ min: 61, max: 80, label: '80%', color: '#ff0b1f' },
{ min: 81, max: 100, label: '100%', color: '#a51d29' },
],
},
series: {
itemStyle: {
borderWidth: 0,
},
},
};Heatmap Config Options
| Option | Type | Description |
| ---------------- | -------------------------- | ----------------------------------------------------------------------- |
| xAxisData | string[] | Labels for the x-axis |
| yAxisData | string[] | Labels for the y-axis |
| data | [number, number, number][] | Heatmap cells as [xIndex, yIndex, value] |
| min | number | Minimum value for color mapping |
| max | number | Maximum value for color mapping |
| colors | string[] | Continuous color range when visualMap.pieces is not used |
| visualMap | any | ECharts visual map config. pieces also drives the custom legend pills |
| grid | object | ECharts grid config |
| xAxis | any | Extra ECharts x-axis config |
| yAxis | any | Extra ECharts y-axis config |
| showTooltip | boolean | Enables or disables tooltip |
| tooltipFormatter | function | Custom tooltip formatter |
| showLabel | boolean | Shows value labels inside cells |
| labelFormatter | string | function | Cell label formatter |
| series | any | any[] | Extra ECharts heatmap series config |
🎨 Themes
Available chart themes:
- default
- dark
- vintage
- essos
- chalk
- roma
📚 Documentation
Apache ECharts documentation:
https://echarts.apache.org/en/api.html#echarts
🤝 Contributing
Contributions, issues, and feature requests are welcome. Feel free to submit a pull request.
📄 License
MIT License
Status Timeline
StatusTimelineComponent renders generic categorical intervals in chronological order. Segment
widths are proportional to duration, and dense datasets scroll horizontally without aggregation.
Import and usage
import { StatusTimelineComponent, type StatusTimelineConfig } from 'cats-charts';
@Component({
standalone: true,
imports: [StatusTimelineComponent],
template: `
<lib-status-timeline
[config]="timelineConfig"
(chartEvent)="onTimelineEvent($event)"
/>
`,
})
export class ExampleComponent {
timelineConfig: StatusTimelineConfig = {
startLabel: 'Monday',
endLabel: 'Today',
statuses: [
{ value: 'ready', label: 'Ready', color: '#2f8f3a' },
{ value: 'deploying', label: 'Deploying', color: '#d0a020' },
{ value: 'blocked', label: 'Blocked', color: '#a43b35' },
],
data: [
{ start: '2026-08-24T00:00:00Z', end: '2026-08-25T00:00:00Z', status: 'ready' },
{
start: '2026-08-25T00:00:00Z',
end: '2026-08-25T06:00:00Z',
status: 'deploying',
label: 'Release deployment',
},
{ start: '2026-08-25T06:00:00Z', end: '2026-08-26T00:00:00Z', status: 'ready' },
],
};
}Configuration
| Option | Description |
| --- | --- |
| data | Dynamic intervals with start, end, status, and optional label/metadata |
| statuses | Text and optional color for each status value |
| showLegend, showTooltip | Toggle supporting UI (both default to true) |
| legendPosition | Places the legend at top, bottom, left, or right |
| legendLayout | Arranges legend items horizontal or vertical |
| legendAlign | Aligns the legend at start/left, center, end/right, or space-between |
| legendLabelAlign | Aligns text within vertical legend items to left, center, or right |
| legendInteractive | Enables clicking legend labels to dim/restore matching intervals; defaults to true |
| legendDimmedOpacity | Opacity used for inactive legend items and intervals; defaults to 0.3 |
| legendScrollable | Enables bounded legend overflow scrolling; defaults to true |
| legendMaxWidth, legendMaxHeight | Optional scroll viewport limits |
| legendNote | Optional explanatory text displayed beside the legend |
| startLabel, endLabel | Endpoint text; dates are derived when omitted |
| showEndpointLabels | Shows or hides the endpoint-label row; defaults to true |
| endpointLabelsAlign | Aligns endpoint labels at start/left, center, end/right, or space-between |
| loading, loadingLabel, emptyLabel, error | Timeline state presentation |
| minSegmentWidth, segmentGap | Dense-data and spacing controls in pixels |
| dateFormatter, durationFormatter, tooltipFormatter | Display customization hooks |
| unknownStatus | Fallback label/color for unconfigured status values |
| ariaLabel | Accessible name for the timeline |
The component emits chartEvent with { type: 'itemClick', item, index }. Its appearance can be
themed with the --status-timeline-* CSS custom properties defined in the component stylesheet.
