Heat map

author(s): Torstein Hønsi

by fujigoko

HTML

<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/heatmap.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<script src="https://code.highcharts.com/modules/export-data.js"></script>
<script src="https://code.highcharts.com/modules/accessibility.js"></script>

<figure class="highcharts-figure">
    <div id="container"></div>
</figure>

JavaScript

Highcharts.chart('container', {
  chart: {
    type: 'heatmap',
    marginTop: 40,
    marginBottom: 80,
    plotBorderWidth: 1,
    events: {
      load() {
        const chart = this;
        let annotationTimeout;

        const removeAnnotation = () => {
          if (chart.annotationTooltip) {
            chart.annotationTooltip.destroy();
            chart.annotationTooltip = null;
          }
        };

        chart.container.addEventListener('mousemove', function(event) {
          clearTimeout(annotationTimeout);

          const mouseX = event.clientX - chart.plotLeft,
            mouseY = event.clientY - chart.plotTop,
            xAxisValue = chart.xAxis[0].toValue(mouseX);
          let tickIndex = -1;

          chart.xAxis[0].tickPositions.some((tick, i) => {
            if (
              xAxisValue >= tick - chart.xAxis[0].pointRange / 2 &&
              xAxisValue <= tick + chart.xAxis[0].pointRange / 2

            ) {
              tickIndex = i;
              return true;
            }
          });

          const tickPosition = chart.xAxis[0].tickPositions[tickIndex];
          if (tickPosition) {
            const point = chart.series[0].points.find(point => point.x === tickPosition);
            if (point) {
              const date = new Date(tickPosition);
              removeAnnotation();

              chart.annotationTooltip = chart.renderer
                .label(date, chart.xAxis[0].toPixels(tickPosition) - 100, mouseY - 25, 'callout')
                .attr({
                  fill: '#ffffffd9',
                  padding: 5,
                  zIndex: 10,
                  r: 5,
                })
                .add();
            }
          }
        });

        chart.container.addEventListener('mouseout', function() {
          clearTimeout(annotationTimeout);
          annotationTimeout = setTimeout(removeAnnotation, 500);
        });
      },

    },
  },

  xAxis: {
    type: 'datetime',
    min: Date.UTC(2023, 9, 1),
  ...