
A versatile javascript charting library that allows you to create customizable, extensible, and interactive time-series calendar heatmaps similar to Github’s contribution graph.
Features:
- Supports various data types such as JSON, CSV, TSV, and plain text (TXT).
- Dark Mode and Light Mode.
- Allows to customize the calendar language, timezone, and locale-specific settings.
- Allows to set min/max/start dates.
- Useful legend and tooltip plugins.
- Lots of API methods and events.
- Written in Typescript and ES6, and fully tested on real browsers
- And much more.
How to use it:
1. Load the required d3.js library and cal-heatmap’s files in the document.
<!-- d3.js is required --> <script src="https://d3js.org/d3.v7.min.js"></script> <!-- cal-heatmap --> <script src="cal-heatmap.min.js"></script> <link rel="stylesheet" href="cal-heatmap.css" /> <!-- cal-heatmap legend plugin --> <script src="plugins/Legend.min.js"></script> <!-- cal-heatmap legendLite plugin --> <script src="plugins/LegendLite.min.js"></script> <!-- cal-heatmap tooltip plugin --> <script src="https://unpkg.com/@popperjs/core@2"></script> <script src="plugins/Tooltip.min.js"></script>
2. Create a DIV container to hold the calendar heatmap.
<div id="cal-heatmap"></div>
3. Initialize the library to create an empty calendar heatmap.
const cal = new CalHeatmap();
cal.paint({
// options
});4. Add your time series data to the calendar heatmap.
cal.paint(
{
data: {
source: 'data.csv',
type: 'csv', // 'json' | 'csv' | 'tsv' | 'txt',
x: 'date',
y: 'wind',
groupY: 'max', // 'sum' | 'count' | 'min' | 'max' | 'median'
requestInit: {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
// 'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
}
},
},
);5. Available options to customize the calendar heatmap.
cal.paint(
{
date: {
start: Date;
min?: Date;
max?: Date;
highlight?: Date[];
locale: string | Partial<ILocale>;
timezone?: string
},
range: 12,
scale: {
opacity?: {
baseColor: string,
domain: number[],
type: string,
},
color?: {
scheme: string,
range: string[] | d3-scale-chromatic,
interpolate: string | d3-interpolator,
domain: number[],
type: string,
},
},
domain: {
type: string; // year, month, week, day, hour
gutter: number;
padding: [number, number, number, number];
dynamicDimension: boolean;
label: {
text?: string | null | ((timestamp: number, element: SVGElement) => string);
position: 'top' | 'right' | 'bottom' | 'left',
textAlign: 'start' | 'middle' | 'end',
offset: {
x: number,
y: number,
},
rotate: null | 'left' | 'right',
width: number,
height: number,
};
subLabel: {
text: () => string[],
radius?: number,
width?: number,
height?: number,
gutter?: number,
textAlign?: 'start' | 'middle' | 'end',
};
sort: 'asc' | 'desc';
},
subDomain: {
type: string,
gutter: number,
width: number,
height: number,
radius: number,
label:
| string
| null
| ((timestamp: number, value: number, element: SVGElement) => string);
color?:
| string
| ((timestamp: number, value: number, backgroundColor: string) => string);
},
itemSelector: '#cal-heatmap',
verticalOrientation: false,
animationDurationL: 200,
theme: 'light', // or 'dark'
},
);6. Config the Legend and Tooltip plugins.
cal.paint(
{
// options here
},
[
[
Tooltip, // tooltip plugin
{
text: function (date, value, dayjsDate) {
return (
(value ? value + 'km/h' : 'No data') +
' on ' +
dayjsDate.format('LL')
);
},
},
],
[
Legend, // legend plugin
{
tickSize: 0,
width: 100,
itemSelector: '#ex-wind-legend',
label: 'Seattle wind (km/h)',
},
],
[
LegendLite, // LegendLite plugin
{
width: 25,
itemSelector: '#legend-width',
gutter: 10,
radius: 3,
includeBlank: true,
},
],
]
);7. API methods.
// Paint the calendar using the given Options and Plugins cal.paint() // Update the calendar's data set cal.fill() // Destroy the calendar cal.destroy() // Add a new subDomain template cal.addTemplates() // Extend the dayjs library with plugins cal.extendDayjs() // Return the calendar's dimensions cal.dimensions() // Shift the calendar by the given number of domains forward cal.next(steps?: number): Promise<unknown> // Shift the calendar by the given number of domains backward cal.previous(steps?: number): Promise<unknown> // Scroll the calendar to the given date cal.jumpTo(date: Date, reset: boolean): Promise<unknown>
8. Events.
// Resize
cal.on('resize', (newW, newH, oldW, oldH) => {
console.log(
`Calendar has been resized from ${oldW}x${oldH} to ${newW}x${newH}`
);
});
// Fill
cal.on('fill', () => {
console.log('New data have been loaded!');
});
// Click
cal.on('click', (event, timestamp, value) => {
console.log(
'On <b>' +
new Date(timestamp).toLocaleDateString() +
'</b>, the max temperature was ' +
value +
'°C'
);
});
// Mouseover
cal.on('mouseover', (event, timestamp, value) => {
console.log(
'On <b>' +
new Date(timestamp).toLocaleDateString() +
'</b>, the max temperature was ' +
value +
'°C'
);
});
// Mouseout
cal.on('mouseout', (event, timestamp, value) => {
console.log(
'On <b>' +
new Date(timestamp).toLocaleDateString() +
'</b>, the max temperature was ' +
value +
'°C'
);
});
// minDateReached
cal.on('minDateReached', () => {
// Do something to disable the navigation PREVIOUS button
});
// maxDateReached
cal.on('maxDateReached', () => {
// Do something to disable the navigation NEXT button
});
// minDateNotReached
cal.on('minDateNotReached', () => {
// Do something to enable back the PREVIOUS button,
// after disabling it with the minDateReached event
});
// maxDateNotReached
cal.on('maxDateNotReached', () => {
// Do something to enable back the NEXT button,
// after disabling it with the maxDateReached event
});
// destroy
cal.on('destroy', () => {
// Calendar has started destroying
// Do something
});Changelog:
12/29/2023
- v4.2.4







