Element Framework

Heatmap

  • HTML
  • JS
  • CSS
  <ef-heatmap style="width: 80%;"></ef-heatmap>
var el = document.querySelector('ef-heatmap');
var generateData = function(r, c) {
  var rows = Array(r);
  for (var i = 0; i < rows.length; i++) {
    var columns = Array(c);
    for (var ii = 0; ii < columns.length; ii++) {
      var shift = (i * ii) / (c * r);
      var value = -1 + shift + (Math.random() / 2 + 0.5 * shift) * (2 - shift) * 1;
      columns[ii] = {
        value: value
      };
    }
    rows[i] = columns;
  }
  return rows;
};
el.config = {
  data: generateData(12, 12),
  yAxis: {
    labels: ['2019', '2018', '2017', '2016', '2015', '2014', '2013', '2012', '2011', '2010', '2009', '2008', '2007']
  },
  xAxis: {
    labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
    shortLabels: ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC']
  }
};

                  

ef-heatmap is a graphical representation of data where the individual values contained in a matrix are represented as colors.

Basic Usage

To initialize the heatmap, pass a configuration object to the config property. Heatmap uses mid-point and a cell's value to determine the colors of cells.

The default values of min, mid and max points are -1, 0 and 1, respectively.

var el = document.querySelector("ef-heatmap");
el.config = {
  data: [
    [{ value: 0.1 }, { value: 0.2 }, { value: 0.3 }],
    [{ value: 0.4 }, { value: 0.5 }, { value: 0.6 }],
    [{ value: 0.7 }, { value: 0.8 }, { value: 0.9 }],
    [{ value: 1.0 }, { value: 1.1 }, { value: 1.2 }],
  ],
};

Config

Properties Type Required Description
data Cell[][] rows[ columns[Cell] ]
yAxis YAxis Configuration for Y-Axis
xAxis XAxis Configuration for X-Axis

Min, max and mid data point

You can configure min, mid and max points to match your data format using the min-point, mid-point and max-point attributes.

The example below shows how to configure the heatmap when data is ranged between 250 and 800 and the mid point is 600.

  • HTML
  • JS
  • CSS
  <ef-heatmap min-point="250" mid-point="600" max-point="800" axis-hidden></ef-heatmap>
var el = document.querySelector('ef-heatmap');
var generateSequentialData = function(start, count, step) {
  var rows = [];
  var columns = [];
  for (var i = 0; i < count; i++) {
    columns.push({ value: start + step * i });
  }
  rows.push(columns);
  return rows;
};
el.config = {
  data: generateSequentialData(250, 15, 39.286),
};
ef-heatmap {
  height: 35px;
}
<ef-heatmap
  min-point="250"
  mid-point="600"
  max-point="800"
></ef-heatmap>

Cell appearances

A Heatmap cell's appearance derives from data in config. However, a certain degree of customization and features addition is allowed for each individual cell.

Cell header

Besides a cell's label, there is also a cell header property which is bolder and always positioned on top of the label.

  • HTML
  • JS
  • CSS
  <ef-heatmap></ef-heatmap>
var el = document.querySelector('ef-heatmap');
el.config = {
  data: [
    [
      { header: "IBM", value: 0.4 },
      { header: "APPL", value: 0.52 },
      { header: "AMZN", value: -0.3 }
    ],
    [
      { header: "T", value: -0.4 },
      { header: "NFLX", value: 0.5 },
      { header: "GM", value: -1.6 }
    ],
    [
      { header: "FB", value: 0.17 },
      { header: "VXUS", value: -2.8 },
      { header: "GOOGL", value: 3.9 }
    ]
  ]
};

                  
var el = document.querySelector("ef-heatmap");
el.config = {
  data: [
    [
      { header: "IBM", value: 0.4 },
      { header: "APPL", value: 0.52 },
      { header: "AMZN", value: -0.3 },
    ],
    [
      { header: "T", value: -0.4 },
      { header: "NFLX", value: 0.5 },
      { header: "GM", value: -1.6 },
    ],
    [
      { header: "FB", value: 0.17 },
      { header: "VXUS", value: -2.8 },
      { header: "GOOGL", value: 3.9 },
    ],
  ],
};

Cell color blending

Color blending mode mixes the max and min colors with the canvas's background color, resulting in more natural, gradient-like cell colors.

  • HTML
  • JS
  • CSS
  <ef-heatmap axis-hidden blend></ef-heatmap>
var el = document.querySelector('ef-heatmap');
var generateSequentialData = function(start, count, step) {
  var rows = [];
  var columns = [];
  for (var i = 0; i < count; i++) {
    columns.push({ value: start + step * i });
  }
  rows.push(columns);
  return rows;
};
el.config = {
  data: generateSequentialData(-1, 21, 0.1),
};
el.renderCallback = function(cell) {
  return { foregroundColor: '#f0f0f0' }
};
ef-heatmap {
  height: 35px;
}
<ef-heatmap blend></ef-heatmap>

Apply custom cell's font color to improve contrast.

const el = document.querySelector("ef-heatmap");
el.renderCallback = function (cell) {
  return { foregroundColor: "#f0f0f0" };
};

Custom cell colors

Default colors are provided by the theme but they can be overridden using CSS.

  • HTML
  • JS
  • CSS
  <ef-heatmap axis-hidden></ef-heatmap>
var el = document.querySelector('ef-heatmap');
var generateSequentialData = function(start, count, step) {
  var rows = [];
  var columns = [];
  for (var i = 0; i < count; i++) {
    columns.push({ value: start + step * i });
  }
  rows.push(columns);
  return rows;
};
el.config = {
  data: generateSequentialData(-1, 21, 0.1),
};
ef-heatmap {
  height: 35px;
  --above-point-color: #3399ff;
  --below-point-color: #ff3399;
}
<style>
  ef-heatmap {
    --above-point-color: #3399ff;
    --below-point-color: #ff3399;
  }
</style>
<ef-heatmap></ef-heatmap>

CSS variables

CSS Variable Names Description
--spacing Margin around a cell in pixels
--above-point-color Color at the maximum point
--below-point-color Color at the minimum point

Custom cell rendering

Heatmap accepts a custom rendering function via the renderCallback property to override label, backgroundColor and foregroundColor for each cell.

The following cell information is also available:

  • x : x coordinates of the cell on canvas
  • y : y coordinates of the cell on canvas
  • colIndex : column position of the cell (index starts at 0)
  • rowIndex : row position of the cell (index starts at 0)
  • HTML
  • JS
  • CSS
  <ef-heatmap></ef-heatmap>
var el = document.querySelector('ef-heatmap');
var generateData = function(r, c) {
  var rows = Array(r);
  for (var i = 0; i < rows.length; i++) {
    var columns = Array(c);
    for (var ii = 0; ii < columns.length; ii++) {
      var shift = (i * ii) / (c * r);
      var value = -1 + shift + (Math.random() / 2 + 0.5 * shift) * (2 - shift);

      columns[ii] = {
        value: value
      };
    }
    rows[i] = columns;
  }
  return rows;
};
el.config = {
  data: generateData(12, 12),
  yAxis: {
    labels: ['2019', '2018', '2017', '2016', '2015', '2014', '2013', '2012', '2011', '2010', '2009', '2008', '2007', '2006', '2005']
  },
  xAxis: {
    labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
    shortLabels: ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC']
  }
};
el.renderCallback = function(cell) {
  var isDiagonalLine = cell.colIndex === cell.rowIndex;
  if (isDiagonalLine) {
    return {
      label: '',
      backgroundColor: 'transparent'
    }
  }
};

                  
var el = document.querySelector("ef-heatmap");
el.renderCallback = function (cell) {
  var isDiagonalLine = cell.colIndex === cell.rowIndex;

  if (isDiagonalLine) {
    return {
      label: "",
      backgroundColor: "transparent",
    };
  }
};

Cell's configuration

Properties Type Description
value number Cell's value
header string Cell's header
label string Cell's label
foregroundColor string of valid color (hex, rgb) Cell's label color
backgroundColor string of valid color (hex, rgb) Cell's background color

Axes position

Each axis has 2 different positioning options. X-axis can be at top or bottom and Y-axis can be at left or right.

  • HTML
  • JS
  • CSS
  <ef-heatmap></ef-heatmap>
var el = document.querySelector('ef-heatmap');
var generateData = function(r, c) {
  var rows = Array(r);
  for (var i = 0; i < rows.length; i++) {
    var columns = Array(c);
    for (var ii = 0; ii < columns.length; ii++) {
      var shift = (i * ii) / (c * r);
      var value = -1 + shift + (Math.random() / 2 + 0.5 * shift) * (2 - shift);

      columns[ii] = {
        value: value
      };
    }
    rows[i] = columns;
  }
  return rows;
};
el.config = {
  data: generateData(12, 12),
  yAxis: {
    position: 'right',
    labels: ['2019', '2018', '2017', '2016', '2015', '2014', '2013', '2012', '2011', '2010', '2009', '2008', '2007', '2006', '2005']
  },
  xAxis: {
    position: 'bottom',
    labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
    shortLabels: ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC']
  }
};

                  
  var el = document.querySelector("ef-heatmap");
  el.config = {
    yAxis: {
      position: "right",
      labels: [...]
    },
    xAxis: {
      position: "bottom",
      labels: [...],
    }
  };

Y-Axis's configuration

Properties Type Description
labels string[] Y-axis labels
position left or right Y-axis orientation relative to the heatmap

X-Axis's configuration

Properties Type Description
labels string[] X-axis labels
shortLabels string[] X-axis short labels for smaller screens
position top or bottom X-axis orientation relative to the heatmap

Using tooltip

To render a tooltip on cell hover, pass a tooltip render function that returns HTML elements using the tooltipCallback property.

  • HTML
  • JS
  • CSS
  <ef-heatmap></ef-heatmap>
var el = document.querySelector('ef-heatmap');
var generateData = function(r, c) {
  var rows = Array(r);
  for (var i = 0; i < rows.length; i++) {
    var columns = Array(c);
    for (var ii = 0; ii < columns.length; ii++) {
      var shift = (i * ii) / (c * r);
      var value = -1 + shift + (Math.random() / 2 + 0.5 * shift) * (2 - shift);

      columns[ii] = {
        value: value
      };
    }
    rows[i] = columns;
  }
  return rows;
};
el.tooltipCallback = function(cell) {
  var tooltip = document.createElement('div');
  var template = "<div style='font-weight: bold'>Actual value:</div><div style='color:" + cell.color + "'>" + cell.value + "</div>";
  tooltip.innerHTML = template;
  return tooltip;
};
el.config = {
  data: generateData(12, 12),
  yAxis: {
    labels: ['2019', '2018', '2017', '2016', '2015', '2014', '2013', '2012', '2011', '2010', '2009', '2008', '2007', '2006', '2005']
  },
  xAxis: {
    labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
    shortLabels: ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC']
  }
};

                  
  var el = document.querySelector("ef-heatmap");
  el.tooltipCallback = function(cell) {
    var tooltip = document.createElement("div");
    var template = `
          <div style="font-weight: bold">Actual value:</div>
          <div style="color:${cell.color}">${cell.value}</div>
        `;
    tooltip.innerHTML = template;
    return tooltip;
  };
  el.config = {...};

Handling click events

ef-heatmap provides an API to allow user to get cell's information form a native mouse events such as click, dblclick, contextmenu, etc. Calling getCellDataAtEvent and passing an event to the method will return a data of interactive cell.

  • HTML
  • JS
  • CSS
<ef-heatmap></ef-heatmap>
<ef-overlay-menu id="menu">
  <ef-item value="menu1">Menu 1</ef-item>
  <ef-item value="menu2" disabled>Menu 2</ef-item>
  <ef-item type="divider"></ef-item>
  <ef-item value="show-cell-data">Show Cell Data</ef-item>
</ef-overlay-menu>
<ef-dialog id="dlg" header="Heatmap Cell"></ef-dialog>
const isIE = (/Trident/g).test(navigator.userAgent);
var el = document.querySelector('ef-heatmap');
var menu = document.getElementById('menu');
var dlg = document.getElementById('dlg');
let popupTemplate;
var generateData = function(row, col) {
  var rows = Array(row);
  for (var i = 0; i < rows.length; i++) {
    var columns = Array(col);
    for (var ii = 0; ii < columns.length; ii++) {
      var shift = (i * ii) / (col * row);
      var value = -1 + shift + (Math.random() / 2 + 0.5 * shift) * (2 - shift);

      columns[ii] = {
        value: value
      };
    }
    rows[i] = columns;
  }
  return rows;
};
el.config = {
  data: generateData(12, 12),
  yAxis: {
    labels: ['2019', '2018', '2017', '2016', '2015', '2014', '2013', '2012', '2011', '2010', '2009', '2008', '2007', '2006', '2005']
  },
  xAxis: {
    labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
    shortLabels: ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC']
  }
};

const handleContextMenu = function(event) {
  const cell = el.getCellDataAtEvent(event);
  if (cell) {
    event.preventDefault();
    popupTemplate = "<span>Value: " + cell.value + "</span><br><span>Row index: " + cell.rowIndex + "</span><br><span>Column index: " + cell.colIndex + "</span>";
    menu.opened = true;
    menu.x = event.clientX;
    menu.y = event.clientY;
  }
};

if (!isIE) {
  el.addEventListener('contextmenu', handleContextMenu);
} else {
  document.oncontextmenu = handleContextMenu;
}

menu.addEventListener('item-trigger', function(event) {
  var value = event.detail.value;
  if (value === 'show-cell-data') {
    dlg.innerHTML = popupTemplate;
    dlg.opened = true;
    menu.opened = false;
  }
});

                  
<ef-heatmap></ef-heatmap>
<ef-overlay-menu id="menu">
  <ef-item value="menu1">Menu 1</ef-item>
  <ef-item value="menu2" disabled>Menu 2</ef-item>
  <ef-item type="divider"></ef-item>
  <ef-item value="show-cell-data" >Show Cell Data</ef-item>      
</ef-overlay-menu>
<ef-dialog id="dlg" header="Heatmap Cell"></ef-dialog>
var el = document.querySelector("ef-heatmap");
var menu = document.getElementById('menu');
var dlg = document.getElementById('dlg');
let popupTemplate;        
el.addEventListener('contextmenu', function (event) {
    const cell = el.getCellDataAtEvent(event);
    if (cell) {
      event.preventDefault();
      popupTemplate = `
          <span>Value: ${cell.value}</span><br>
          <span>Row index: ${cell.rowIndex}</span><br>
          <span>Column index: ${cell.colIndex}</span>
      `;
      menu.opened = true;
      menu.x = event.clientX;
      menu.y = event.clientY;
    }
});

menu.addEventListener('item-trigger', function (event) {
    var value = event.detail.value;
    if (value === 'show-cell-data') {
      dlg.innerHTML = popupTemplate;
      dlg.opened = true;
      menu.opened = false;
    }
});

el.config = {...};

Note: On IE11 or legacy browsers, contextmenu event via addEventListener is not support on Web components: https://github.com/webcomponents/polyfills/issues/176. As a workaround, you can use document.oncontextmenu to handle the event.

API Reference

Attributes

HeatmapConfig
config
Heatmap configuration options.
number
label-width
Number of maximum label width that cell can paint in pixel. e.g. label-width: 30px; cell label hides when text length reaches 30px.
boolean
label-hidden
Hide all labels in the cells
boolean
axis-hidden
Hide all axes
number
min-point
Minimum point of the cell coloring
number
mid-point
Middle point of the cell coloring
number
max-point
Maximum point of the cell coloring
boolean
blend
Enable cell color blending
number
saturation
Cell minimum color saturation, value can be from 0 - 1

Properties

HeatmapConfig
config
Heatmap configuration options.
number
labelWidth
Number of maximum label width that cell can paint in pixel. e.g. label-width: 30px; cell label hides when text length reaches 30px.
0
boolean
labelHidden
Hide all labels in the cells
false
boolean
axisHidden
Hide all axes
false
number
minPoint
Minimum point of the cell coloring
-1
number
midPoint
Middle point of the cell coloring
0
number
maxPoint
Maximum point of the cell coloring
1
boolean
blend
Enable cell color blending
false
number
saturation
Cell minimum color saturation, value can be from 0 - 1
0.4
HeatmapTooltipCallback
tooltipCallback
A callback function that allows tooltip rendering on cell hover
HeatmapRenderCallback
renderCallback
Render callback function use for custom cell properties. Accepts custom label, foreground and background color

Methods

getCellDataAtEvent(event)
Returns data of interactive cell
event
MouseEvent
an event that occur while the user interacting with element