@licharts/core
v1.0.2
Published
LiCharts core — essential chart types, zero dependencies
Downloads
38
Maintainers
Readme
@licharts/core
Free, MIT-licensed SVG charting library. Zero dependencies. Works in any framework or plain HTML.
Table of Contents
- Installation
- Quick Start
- Chart Types
- XYChart — Line, Area, Column, Bar, Scatter, StepLine
- PieChart — Pie and Donut
- RadarChart — Radar / Spider
- Axes
- Series
- Themes
- Chart Options Reference
- Data Point Shapes
- Stacking
- Animations
- Export Menu
- Responsive Charts
- Destroying a Chart
Installation
npm install @licharts/core// Import styles once — usually in your app's entry file
import '@licharts/core/dist/licharts.css';Angular: add the CSS in angular.json instead of importing it in JS:
"styles": ["node_modules/@licharts/core/dist/licharts.css"]import { XYChart } from '@licharts/core';Quick Start
<!-- index.html -->
<div id="chart" style="width: 600px; height: 400px;"></div>import { XYChart, LineSeries, CategoryAxis, ValueAxis } from '@licharts/core';
// 1. Create the chart
const chart = new XYChart('#chart', { title: 'Monthly Sales' });
// 2. Add axes
chart.xAxes.push(new CategoryAxis({ position: 'bottom' }));
chart.yAxes.push(new ValueAxis({ position: 'left' }));
// 3. Create a series and set its data
const sales = new LineSeries({ name: 'Sales', color: '#4285f4' });
sales.data = [
{ category: 'Jan', y: 120 },
{ category: 'Feb', y: 180 },
{ category: 'Mar', y: 150 },
{ category: 'Apr', y: 210 },
{ category: 'May', y: 190 },
];
// 4. Add the series to the chart
chart.series.push(sales);
// 5. Render
chart.render();That's it — a fully animated, responsive line chart with tooltip and legend.
Chart Types
XYChart
The main chart for all X/Y based series: Line, Area, Column, Bar, Scatter, StepLine.
import { XYChart } from '@licharts/core';
const chart = new XYChart('#container', {
title: 'Revenue', // Chart title
subtitle: 'Q1–Q4 2024', // Smaller text below title
width: 800, // px (default: container width)
height: 450, // px (default: container height)
padding: { top: 20, right: 20, bottom: 50, left: 60 },
background: '#ffffff',
responsive: true, // auto-resize with container (default: true)
animationsEnabled: true, // default: true
defaultAnimationDuration: 600, // ms
contextMenu: true, // shows ≡ button for CSV/XLS export
});Key properties you can set after construction:
chart.showLegend = true; // show/hide the legend
chart.showTooltip = true; // show/hide the hover tooltip
chart.title = 'New Title';Add/remove series dynamically:
chart.series.push(mySeries);
chart.series.remove(mySeries);
chart.render(); // always call render() after changesPieChart
import { PieChart, PieSeries } from '@licharts/core';
const chart = new PieChart('#container', {
title: 'Market Share',
width: 500,
height: 400,
});
const series = new PieSeries({
innerRadius: 0, // 0 = full pie; '40%' or 80 = donut hole
outerRadius: '85%', // size of the pie (default: fills chart)
labels: true, // show % labels on slices (default: true)
cornerRadius: 4, // rounded slice corners
padAngle: 0.01, // gap between slices (radians)
explodeDistance: 8, // how far exploded slices pop out (px)
});
series.data = [
{ category: 'Chrome', value: 65, color: '#4285f4' },
{ category: 'Safari', value: 19 },
{ category: 'Firefox', value: 9 },
{ category: 'Other', value: 7 },
];
chart.series.push(series);
chart.render();Make a donut chart — just set innerRadius:
const donut = new PieSeries({ innerRadius: '50%' });Explode a specific slice (pop it out):
series.data = [
{ category: 'Featured', value: 40, explode: true, explodeOffset: 15 },
{ category: 'Other', value: 60 },
];RadarChart
Useful for showing multi-dimensional comparisons (skills, attributes, stats).
import { RadarChart, RadarSeries } from '@licharts/core';
const chart = new RadarChart('#container', {
title: 'Developer Skills',
width: 500,
height: 450,
});
// Each series is one "player". Data points map to the radar axes.
const dev1 = new RadarSeries({
name: 'Alice',
color: '#4285f4',
fillOpacity: 0.25, // fill transparency (default: 0.25)
strokeWidth: 2,
closed: true, // connect last point back to first (default: true)
});
dev1.data = [
{ category: 'TypeScript', y: 90 },
{ category: 'React', y: 85 },
{ category: 'Node.js', y: 70 },
{ category: 'CSS', y: 60 },
{ category: 'Testing', y: 75 },
];
const dev2 = new RadarSeries({ name: 'Bob', color: '#ea4335' });
dev2.data = [
{ category: 'TypeScript', y: 70 },
{ category: 'React', y: 95 },
{ category: 'Node.js', y: 50 },
{ category: 'CSS', y: 90 },
{ category: 'Testing', y: 65 },
];
chart.series.push(dev1, dev2);
chart.render();Rule: Every series in a RadarChart must have the same
categoryvalues in the same order.
Axes
CategoryAxis
Use when X values are strings (months, names, labels).
import { CategoryAxis } from '@licharts/core';
const xAxis = new CategoryAxis({
position: 'bottom', // 'top' | 'bottom' | 'left' | 'right'
title: 'Month',
gridLines: true, // show vertical grid lines
gridColor: 'rgba(0,0,0,0.07)',
labelRotation: -45, // rotate labels (degrees)
labelColor: '#666',
labelFontSize: 12,
visible: true,
});
chart.xAxes.push(xAxis);ValueAxis
Use for numeric axes (usually Y).
import { ValueAxis } from '@licharts/core';
const yAxis = new ValueAxis({
position: 'left',
title: 'Revenue ($)',
min: 0, // force minimum value
max: 1000, // force maximum value
tickCount: 6, // approximate number of ticks
tickFormat: (v) => `$${v}`, // custom label formatter
gridLines: true,
logarithmic: false, // set true for log scale
opposite: false, // set true to put on the right side
});
chart.yAxes.push(yAxis);Second Y-axis on the right (e.g., for a different unit):
const rightAxis = new ValueAxis({ position: 'right', title: 'Volume' });
chart.yAxes.push(rightAxis);
// Tell a series to use the second Y-axis (index 1)
series2.options.yAxisIndex = 1;DateAxis
Use when X values are dates or timestamps.
import { DateAxis } from '@licharts/core';
const xAxis = new DateAxis({
position: 'bottom',
tickFormat: (d) => new Date(d).toLocaleDateString('en', { month: 'short' }),
});
chart.xAxes.push(xAxis);Data points for a DateAxis use date or x as a Date/string/timestamp:
series.data = [
{ date: '2024-01-01', y: 120 },
{ date: '2024-02-01', y: 180 },
{ date: new Date('2024-03-01'), y: 150 },
];Series
LineSeries
import { LineSeries } from '@licharts/core';
const line = new LineSeries({
name: 'Revenue',
color: '#4285f4',
strokeWidth: 2,
strokeDash: '', // e.g. '4,2' for dashed line
smooth: false, // curved line (default: false)
fill: false, // area fill color, or false to disable
fillOpacity: 0.15, // area fill opacity
showLabels: false, // show value label on each point
negativeColor: '#ea4335', // color for negative-value segments
animate: true,
animationDuration: 600,
// Bullet (dot) on each data point:
bullet: {
type: 'circle', // 'circle' | 'square' | 'diamond' | 'triangle' | 'star'
radius: 4,
fill: '#4285f4',
stroke: '#fff',
strokeWidth: 2,
},
// Animated pulsing dot at the last point:
endBullet: { radius: 6, fill: '#4285f4' },
});
line.data = [
{ category: 'Jan', y: 100 },
{ category: 'Feb', y: -20 }, // negative values go below zero line
{ category: 'Mar', y: 150 },
];Disable bullets entirely:
const line = new LineSeries({ bullet: false });AreaSeries
AreaSeries is a LineSeries with a fill. Use it exactly like LineSeries but set fill:
import { AreaSeries } from '@licharts/core';
const area = new AreaSeries({
name: 'Visitors',
color: '#34a853',
fill: 'rgba(52,168,83,0.2)', // or just set to true to auto-color
smooth: true,
bullet: false,
});ColumnSeries
Vertical bars. Categories on X, values on Y.
import { ColumnSeries } from '@licharts/core';
const cols = new ColumnSeries({
name: 'Sales',
cornerRadius: 4, // rounded top corners
maxWidth: 60, // max column width in px
// Per-column colors (overrides single color):
palette: ['#4285f4', '#ea4335', '#fbbc04', '#34a853'],
grainy: false, // texture effect on bars
stacked: false,
stacked100: false,
});
cols.data = [
{ category: 'Jan', y: 120 },
{ category: 'Feb', y: 180 },
{ category: 'Mar', y: 150, color: '#ff6d00' }, // override one bar's color
];Column with image above bar (avatar / player card style):
cols.data = [
{ category: 'Alice', y: 95, imageUrl: 'https://example.com/alice.jpg' },
{ category: 'Bob', y: 78, imageUrl: 'https://example.com/bob.jpg' },
];Moving bullet (image follows hover):
const cols = new ColumnSeries({ movingBullet: true });
cols.data = [
{ category: 'Alice', y: 95, imageUrl: '/alice.jpg', bulletColor: '#4285f4' },
];BarSeries
Horizontal bars. Categories on Y, values on X. Same options as ColumnSeries.
import { BarSeries } from '@licharts/core';
const bars = new BarSeries({ name: 'Population', cornerRadius: 3 });
bars.data = [
{ category: 'USA', y: 331 },
{ category: 'India', y: 1380 },
{ category: 'China', y: 1441 },
];
// For BarSeries, use ValueAxis on X and CategoryAxis on Y:
chart.xAxes.push(new ValueAxis({ position: 'bottom' }));
chart.yAxes.push(new CategoryAxis({ position: 'left' }));ScatterSeries
import { ScatterSeries } from '@licharts/core';
const scatter = new ScatterSeries({
name: 'Readings',
color: '#7b1fa2',
});
scatter.data = [
{ x: 10, y: 55 },
{ x: 25, y: 72 },
{ x: 40, y: 38 },
{ x: 60, y: 91 },
];
// Both axes are ValueAxis for scatter:
chart.xAxes.push(new ValueAxis({ position: 'bottom', title: 'Temperature' }));
chart.yAxes.push(new ValueAxis({ position: 'left', title: 'Pressure' }));StepLineSeries
Like LineSeries but draws horizontal-then-vertical steps instead of a diagonal line.
import { StepLineSeries } from '@licharts/core';
const steps = new StepLineSeries({
name: 'Stock Price',
color: '#00bcd4',
});
steps.data = [
{ date: '2024-01-01', y: 150 },
{ date: '2024-01-08', y: 162 },
{ date: '2024-01-15', y: 158 },
];PieSeries
See PieChart above. PieSeries options:
| Option | Type | Default | Description |
|---|---|---|---|
| innerRadius | number \| string | 0 | 0 = pie, '40%' = donut hole |
| outerRadius | number \| string | '85%' | Outer size |
| startAngle | number | -Math.PI/2 | Start angle in radians |
| endAngle | number | startAngle + 2π | End angle in radians |
| padAngle | number | 0.01 | Gap between slices |
| cornerRadius | number | 4 | Rounded corners on slices |
| explodeDistance | number | 8 | Distance exploded slices pop out |
| labels | boolean | true | Show % labels on slices |
| labelRadius | number \| string | '70%' | Where labels are placed |
PieDataPoint fields:
series.data = [
{
category: 'Chrome', // required — used as legend label
value: 65, // required — determines slice size
color: '#4285f4', // optional — override auto color
label: 'Chrome', // optional — custom label text (default: percentage)
explode: false, // optional — pop this slice outward
explodeOffset: 15, // optional — custom explode distance
outerRadius: '100%', // optional — this slice's outer radius
tooltipLabel: 'Chrome Browser', // optional — tooltip text
},
];RadarSeries
See RadarChart above.
| Option | Type | Default |
|---|---|---|
| closed | boolean | true |
| fillOpacity | number | 0.25 |
| strokeWidth | number | 2 |
Data points use category (the radar axis name) and y (the value):
series.data = [
{ category: 'Speed', y: 80 },
{ category: 'Power', y: 65 },
{ category: 'Stamina', y: 90 },
];Themes
LiCharts ships three built-in themes. Apply a theme in ChartOptions:
import { DefaultTheme, DarkTheme, MaterialTheme } from '@licharts/core';
// Light theme (default)
const chart = new XYChart('#chart', { theme: DefaultTheme });
// Dark theme
const chart = new XYChart('#chart', { theme: DarkTheme });
// Material design
const chart = new XYChart('#chart', { theme: MaterialTheme });Custom theme — override any property:
import type { Theme } from '@licharts/core';
const MyTheme: Theme = {
name: 'my-brand',
colors: {
palette: ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4'],
background: '#1a1a2e',
plotBackground: 'transparent',
text: '#eee',
axis: '#aaa',
grid: 'rgba(255,255,255,0.05)',
tooltip: { background: '#16213e', border: '#0f3460', text: '#e0e0e0' },
legend: { background: 'transparent', text: '#ccc' },
scrollbar: { background: '#16213e', thumb: '#0f3460' },
},
fonts: {
family: 'Roboto, sans-serif',
size: 12,
titleSize: 16,
},
};
const chart = new XYChart('#chart', { theme: MyTheme });Chart Options Reference
Every chart accepts these options in its constructor:
{
// Content
title?: string; // large title at top
subtitle?: string; // smaller text below title
// Size
width?: number | string; // px
height?: number | string; // px
padding?: {
top?: number; right?: number; bottom?: number; left?: number;
};
// Appearance
theme?: Theme; // DefaultTheme | DarkTheme | MaterialTheme | custom
background?: string; // CSS color string
// Behavior
responsive?: boolean; // auto-resize (default: true)
animationsEnabled?: boolean; // default: true
defaultAnimationDuration?: number; // ms, default: 600
contextMenu?: boolean; // ≡ export button (default: false)
}Data Point Shapes
XYDataPoint (for line, column, bar, scatter, etc.)
{
// XY coordinates (pick what matches your axis type)
x?: number | string | Date; // for value/date X axes
y?: number; // Y value
category?: string; // for CategoryAxis X
date?: Date | string; // for DateAxis X
value?: number; // alias for y
// Candlestick / OHLC
open?: number;
high?: number;
low?: number;
close?: number;
// Bubble chart
radius?: number;
// Per-point overrides
color?: string;
label?: string;
tooltipLabel?: string;
// Column with image
imageUrl?: string;
bulletColor?: string;
// Any extra fields you need
[key: string]: unknown;
}Stacking
Stacked Columns
import { ColumnSeries, XYChart, CategoryAxis, ValueAxis } from '@licharts/core';
const chart = new XYChart('#chart', { title: 'Stacked Sales' });
chart.xAxes.push(new CategoryAxis({ position: 'bottom' }));
chart.yAxes.push(new ValueAxis({ position: 'left' }));
const online = new ColumnSeries({ name: 'Online', color: '#4285f4', stacked: true });
const inStore = new ColumnSeries({ name: 'In-Store', color: '#ea4335', stacked: true });
online.data = [{ category: 'Q1', y: 40 }, { category: 'Q2', y: 55 }];
inStore.data = [{ category: 'Q1', y: 60 }, { category: 'Q2', y: 45 }];
chart.series.push(online, inStore);
chart.render();100% Stacked Columns
const s1 = new ColumnSeries({ stacked100: true });
const s2 = new ColumnSeries({ stacked100: true });
// Y axis automatically becomes 0–100%Stacked Lines / Areas
const line1 = new LineSeries({ name: 'A', stacked: true, fill: 'rgba(66,133,244,0.3)' });
const line2 = new LineSeries({ name: 'B', stacked: true, fill: 'rgba(234,67,53,0.3)' });Animations
Animations are on by default. Control them per-series:
const line = new LineSeries({
animate: true, // default: true
animationDuration: 1000, // ms
});Disable for all series in a chart:
const chart = new XYChart('#chart', { animationsEnabled: false });Export Menu
Enable the ≡ button in the top-right corner that lets users export the chart as CSV, XLS, or view as table:
const chart = new XYChart('#chart', { contextMenu: true });Responsive Charts
Charts resize automatically when their container changes size (responsive: true is the default). To opt out:
const chart = new XYChart('#chart', { responsive: false });Destroying a Chart
Always call dispose() when removing a chart from the page. This cleans up event listeners and DOM elements.
// In React:
useEffect(() => {
const chart = new XYChart('#chart', { ... });
chart.render();
return () => chart.dispose(); // cleanup on unmount
}, []);
// In Vue:
onUnmounted(() => chart.dispose());
// In Angular:
ngOnDestroy() { this.chart.dispose(); }Complete Examples
Multi-Series Line Chart with Date Axis
import { XYChart, LineSeries, DateAxis, ValueAxis, DarkTheme } from '@licharts/core';
const chart = new XYChart('#chart', {
title: 'Website Traffic',
subtitle: 'Unique visitors per day',
theme: DarkTheme,
height: 400,
});
chart.xAxes.push(new DateAxis({ position: 'bottom' }));
chart.yAxes.push(new ValueAxis({ position: 'left', title: 'Visitors', tickFormat: v => `${(v/1000).toFixed(0)}k` }));
const visits = new LineSeries({ name: 'Visits', color: '#4285f4', smooth: true });
const unique = new LineSeries({ name: 'Unique', color: '#34a853', smooth: true });
visits.data = [
{ date: '2024-01-01', y: 12400 },
{ date: '2024-01-08', y: 18200 },
{ date: '2024-01-15', y: 15600 },
{ date: '2024-01-22', y: 22100 },
];
unique.data = [
{ date: '2024-01-01', y: 9400 },
{ date: '2024-01-08', y: 13200 },
{ date: '2024-01-15', y: 11600 },
{ date: '2024-01-22', y: 17100 },
];
chart.series.push(visits, unique);
chart.render();Donut Chart
import { PieChart, PieSeries, DefaultTheme } from '@licharts/core';
const chart = new PieChart('#chart', { title: 'Budget Breakdown', theme: DefaultTheme });
const series = new PieSeries({
innerRadius: '55%', // donut hole
labels: true,
cornerRadius: 6,
});
series.data = [
{ category: 'Marketing', value: 35, color: '#4285f4' },
{ category: 'Engineering', value: 40, color: '#34a853' },
{ category: 'Operations', value: 15, color: '#fbbc04' },
{ category: 'HR', value: 10, color: '#ea4335' },
];
chart.series.push(series);
chart.render();