Creating simple heat map in React

Using scalable vector graphics inside your React application

Anton Matrenin
4 min readFeb 12, 2018

Development of interesting visualizations is always small feast for frontend-developers. Most of projects has a lot of common and boring forms in our workdays. As we all know, routine tasks have a bad influence on our productivity and ability to continue working.

One fine day I needed to create visualization of air pollution for one of my projects. The viz should have been seen like a flat heat map with a pointer which depends on the percentage value from API. However this project doesn’t contain complex charts and using powerful libraries like as D3.js can be superfluous for our team. I made a decision to create SVG shapes for this task. It doesn’t take long time but gives a lot of manual control and space for creativity.

You can play around with demo here: https://react--flat-heatmap.herokuapp.com/.

Step 1. Initializing SVG and introducing to base shapes

First of all we need to create a place where we can draw our SVG-shapes. For this purpose we have <svg> element:

The svg element can be used to embed an SVG fragment inside the current document (for example, an HTML document). This SVG fragment has its own viewport and coordinate system.

We need an empty place with 350px width, 35px height and we can do it immediately:

// heatmapWidth = 350
// heatmapHeight = 35
<svg
width=
{heatmapWidth}
height={heatmapHeight}
>
...
</svg>

W3-specification has a bunch of SVG-shapes. We can list some of them:

  • Rectangle
  • Polygon
  • Circle

Lets use an element <rect> to create a base of our heat map:

// heatmapWidth = 350
// heatmapHeight = 35
<rect
width={heatmapWidth}
height={heatmapHeight}
/>

By default rectangle drawn in point [0,0] with specified width, height and black color:

Step 2. Adding gradient to scene

SVG allows graphical objects to be defined for later reuse. It is recommended, wherever possible, referenced elements be defined inside of a <defs> element. We can put here element <linearGradient> and define stop points which defines the ramp of colors to use on a gradient.

We’ll use 3 points: lime (5%)=> orange(50%) => red (95%).

<defs>
<linearGradient id="gradient">
<stop offset="5%" stopColor="lime" />
<stop offset="50%" stopColor="orange" />
<stop offset="95%" stopColor="red" />
</linearGradient>
</defs>

For adding relation between gradient and element we can fill it through property “fill”:

<rect
fill="url(#gradient)"
width=
{heatmapWidth}
height={heatmapHeight}
/>

On the output:

Step 3. Adding pointer

Pointer is a straight vertical line with a small triangle on the end. This is a good opportunity to use svg-polygon.

Let’s set next settings:

  • value indicated by pointer: pointerPercent (0.25)
  • width of pointer triangle: pointerWidth (10px)
  • height of pointer triangle: pointerHeight (5px)
  • line thickness: pointerLineWidth (0.5px)

What we need to take account:

  • the lowest coordinate on Y: heatmapHeight + pointerHeight
  • the highest coordinate on Y: 0
  • base coordinate on X: pointerPercent * heatmapWidth

Each point on the polygon contains two coordinate [x, y]. List of points can be listed through a space. Final polygon code:

const pointerXBase = 
pointerWidth / 2 + pointerPercent * heatmapWidth;
const polygon = `
${pointerXBase - pointerWidth / 2},${heatmapHeight + pointerHeight}
${pointerXBase + pointerWidth / 2},${heatmapHeight + pointerHeight}
${pointerXBase + pointerLineWidth},${heatmapHeight}
${pointerXBase + pointerLineWidth},0
${pointerXBase - pointerLineWidth},0
${pointerXBase - pointerLineWidth},${heatmapHeight}
`;
...<polygon points={polygon} />

On the output:

Step 4. Adding GUI for debugging

I want to recommend a good library — dat.gui — for adding GUI settings to make your scene more interactive. Here you can set a list of variables and create relations between interface and variables in your code.

I used this connector for integration with React:

At the moment react-dat-gui library supports next types of custom variables:

Example of usage (see more complex example inside my repository):

import '../node_modules/react-dat-gui/build/react-dat-gui.css';
import React, { Component } from 'react';

import DatGui, { DatBoolean, DatButton, DatNumber, DatString } from 'react-dat-gui';

class App extends Component {
state = {
data: {
package: 'react-dat-gui',
}
}

update = data => this.setState({ data })

render() {
const { data } = this.state;

return (
<DatGui data={data} onUpdate={this.update}>
<DatString path='package' label='Package' />
</DatGui>
)
}

Results

That’s what we have:

Remind, you can play around with this demo here: https://react--flat-heatmap.herokuapp.com/.

Full source code in this tutorial keeps inside repo:

--

--