Chartist provides a comprehensive event system built on the EventEmitter class that allows developers to hook into chart lifecycle events, drawing operations, and user interactions. This enables custom animations, styling, and behavior modifications.
Core event system class providing event registration, removal, and emission capabilities.
/**
* Event emitter class for handling chart events
*/
class EventEmitter {
/** Register event listener for specific event */
on(event: string, listener: EventListener): EventEmitter;
/** Register catch-all event listener for any event */
on(event: '*', listener: AllEventsListener): EventEmitter;
/** Remove event listener */
off(event: string, listener?: EventListener): EventEmitter;
/** Emit event with optional data */
emit<T>(event: string, data: T): void;
}
type EventListener<T = any> = (data: T) => void;
type AllEventsListener<T = any> = (data: T) => void;Events that occur during chart creation and updates.
interface ChartCreatedEvent {
type: 'created';
svg: Svg;
options: any;
responsiveOptions: ResponsiveOptions[];
}
interface ChartDataEvent {
type: 'data';
data: ChartData;
}
interface ChartOptionsChangedEvent {
type: 'optionsChanged';
previousOptions: any;
currentOptions: any;
}
interface ChartResponsiveEvent {
type: 'responsiveOptionsChanged';
previousResponsiveOptions: ResponsiveOptions[];
currentResponsiveOptions: ResponsiveOptions[];
}Usage Examples:
import { LineChart } from "chartist";
const chart = new LineChart('.chart-container', data, options);
// Handle chart creation
chart.on('created', (data: ChartCreatedEvent) => {
console.log('Chart created with SVG:', data.svg);
console.log('Chart options:', data.options);
// Add custom elements after creation
data.svg.elem('text', {
x: 10,
y: 20,
'font-size': '14px'
}).text('Custom Title');
});
// Handle data updates
chart.on('data', (data: ChartDataEvent) => {
console.log('Chart data updated:', data.data);
});
// Handle responsive changes
chart.on('responsiveOptionsChanged', (data: ChartResponsiveEvent) => {
console.log('Responsive options changed');
console.log('Previous:', data.previousResponsiveOptions);
console.log('Current:', data.currentResponsiveOptions);
});Events fired during the drawing process for each chart element.
interface DrawEvent {
type: 'draw';
element: Svg;
group: Svg;
series: SeriesObject;
seriesIndex: number;
meta: any;
}
interface GridDrawEvent extends DrawEvent {
axis: Axis;
index: number;
position: { x1: number; y1: number; x2: number; y2: number };
}
interface LabelDrawEvent extends DrawEvent {
text: string;
width: number;
height: number;
x: number;
y: number;
index: number;
axis: Axis;
}Usage Examples:
// Customize grid lines
chart.on('draw', (data: GridDrawEvent) => {
if (data.type === 'grid') {
// Style major grid lines differently
if (data.index % 2 === 0) {
data.element.attr({
'stroke-width': '2px',
'stroke': '#333'
});
} else {
data.element.attr({
'stroke-width': '1px',
'stroke': '#ccc',
'stroke-dasharray': '2,2'
});
}
}
});
// Customize labels
chart.on('draw', (data: LabelDrawEvent) => {
if (data.type === 'label') {
// Rotate X-axis labels
if (data.axis.axisUnit === axisUnits.x) {
data.element.attr({
'transform': `rotate(-45 ${data.x} ${data.y})`
});
}
// Format Y-axis labels
if (data.axis.axisUnit === axisUnits.y) {
data.element.text(`$${data.text}`);
}
}
});Events related to chart animations and transitions.
interface AnimationBeginEvent {
type: 'animationBegin';
element: Svg;
animate: any;
easing: string | Function;
from: any;
to: any;
duration: number;
}
interface AnimationEndEvent {
type: 'animationEnd';
element: Svg;
}Usage Examples:
// Handle animation lifecycle
chart.on('animationBegin', (data: AnimationBeginEvent) => {
console.log('Animation started on:', data.element);
console.log('Duration:', data.duration);
console.log('Easing:', data.easing);
});
chart.on('animationEnd', (data: AnimationEndEvent) => {
console.log('Animation completed on:', data.element);
// Chain additional animations
data.element.animate({
'stroke-width': '3px'
}, 200, 'easeOutQuart');
});Each chart type has specific draw events for its elements.
interface LineDrawEvent extends DrawEvent {
path: SvgPath;
chartRect: ChartRect;
values: number[];
}
interface AreaDrawEvent extends DrawEvent {
path: SvgPath;
chartRect: ChartRect;
values: number[];
}
interface PointDrawEvent extends DrawEvent {
x: number;
y: number;
value: number;
chartRect: ChartRect;
index: number;
}interface BarDrawEvent extends DrawEvent {
x1: number;
y1: number;
x2: number;
y2: number;
chartRect: ChartRect;
value: number;
index: number;
}interface SliceDrawEvent extends DrawEvent {
path: SvgPath;
center: { x: number; y: number };
radius: number;
startAngle: number;
endAngle: number;
totalAngle: number;
value: number;
index: number;
}Create sophisticated animations using draw events:
const chart = new LineChart('.chart-container', data, options);
// Animate line drawing
chart.on('draw', (data) => {
if (data.type === 'line' || data.type === 'area') {
const pathLength = data.element._node.getTotalLength();
data.element.attr({
'stroke-dasharray': pathLength + 'px ' + pathLength + 'px',
'stroke-dashoffset': pathLength + 'px'
});
data.element.animate({
'stroke-dashoffset': '0px'
}, 1000, 'easeOutQuint');
}
});
// Animate points with staggered timing
chart.on('draw', (data) => {
if (data.type === 'point') {
const seq = data.index;
const delays = 80;
data.element.attr({
'stroke-width': '10px',
'stroke-opacity': 0
});
setTimeout(() => {
data.element.animate({
'stroke-width': '3px',
'stroke-opacity': 1
}, 300, 'easeOutQuart');
}, seq * delays);
}
});Create custom event handlers for specific interactions:
class CustomChart extends LineChart {
constructor(query, data, options, responsiveOptions) {
super(query, data, options, responsiveOptions);
// Add custom event
this.on('pointHover', this.handlePointHover.bind(this));
}
handlePointHover(data) {
// Custom hover logic
console.log('Point hovered:', data);
// Emit custom event
this.emit('customPointHover', {
value: data.value,
index: data.index,
timestamp: Date.now()
});
}
}
const customChart = new CustomChart('.chart-container', data, options);
customChart.on('customPointHover', (data) => {
console.log('Custom point hover event:', data);
});Properly remove event listeners to prevent memory leaks:
const chart = new LineChart('.chart-container', data, options);
// Store reference to listener
const drawListener = (data) => {
console.log('Draw event:', data.type);
};
// Add listener
chart.on('draw', drawListener);
// Remove specific listener
chart.off('draw', drawListener);
// Remove all listeners for an event
chart.off('draw');
// Clean up when chart is destroyed
function destroyChart() {
chart.off(); // Remove all listeners
chart.detach(); // Clean up chart
}Debug events and their data:
const chart = new LineChart('.chart-container', data, options);
// Log all events
['created', 'draw', 'animationBegin', 'animationEnd'].forEach(eventType => {
chart.on(eventType, (data) => {
console.log(`Event: ${eventType}`, data);
});
});
// Conditional event handling
chart.on('draw', (data) => {
if (data.type === 'point' && data.value > 100) {
console.log('High value point:', data);
data.element.addClass('high-value');
}
});