Customizable And Extensible Calendar Heatmap Library – cal-heatmap

Category: Chart & Graph , Javascript | December 29, 2023
Author:wa0x6e
Views Total:278 views
Official Page:Go to website
Last Update:December 29, 2023
License:MIT

Preview:

Customizable And Extensible Calendar Heatmap Library – cal-heatmap

Description:

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

You Might Be Interested In:


Leave a Reply