EN
JavaScript - color points based distribution model (heatmap color model)
6 points
In this short article, we would like to show how in JavaScript, we create color points distribution model.
That model is built using middle color points that are used to compute middle points when needed.
e.g. it can be used to color 3D chart values.

Practical example:
xxxxxxxxxx
1
const findMultiple = (base, value) => {
2
return base * Math.ceil(value / base);
3
};
4
5
const findStep = (space, count) => {
6
return space / count;
7
};
8
9
const keepRange = (min, max, value) => {
10
if (value < min) {
11
return min;
12
}
13
if (value > max) {
14
return max;
15
}
16
return value;
17
};
18
19
const createDenormalizer = (min, max, size) => {
20
const range = max - min;
21
return (versor) => {
22
return min + versor * range;
23
};
24
};
25
26
// Creates color points based distribution model that provides smooth color transition.
27
// Arguments:
28
// points indicates middle color points
29
// resolution indicates smooth transition quantization
30
// Result: retuns function that returns calculated RGB color for indicated versor (from 0 to 1)
31
//
32
const createPointsDistribution = (points, resolution) => {
33
if (resolution < 1) {
34
throw new Error('It is required to use positive resolution.');
35
}
36
const space = points.length - 1;
37
if (space < 1) {
38
throw new Error('It is required to provide at least 2 points.');
39
}
40
const count = findMultiple(space, resolution);
41
const step = findStep(space, count);
42
let p1 = points[0];
43
let p2;
44
const colors = new Array(count);
45
for (let i = 1, k = 0; i < points.length; ++i) {
46
p2 = points[i];
47
const calculateRed = createDenormalizer(p1.red, p2.red);
48
const calculateGreen = createDenormalizer(p1.green, p2.green);
49
const calculateBlue = createDenormalizer(p1.blue, p2.blue);
50
for (let t = 0; t < 1.0; t += step, k += 1) {
51
colors[k] = {
52
red: Math.round(calculateRed(t)),
53
green: Math.round(calculateGreen(t)),
54
blue: Math.round(calculateBlue(t))
55
};
56
}
57
p1 = p2;
58
}
59
const limit = count - 1;
60
return (versor) => {
61
const value = Math.floor(versor * count);
62
const index = keepRange(0, limit, value);
63
return colors[index];
64
};
65
};
66
67
68
// Helpers:
69
70
const drawPixel = (data, width, x, y, rgb) => {
71
const roundedX = Math.round(x);
72
const roundedY = Math.round(y);
73
const index = 4 * (width * roundedY + roundedX);
74
data[index + 0] = rgb.red;
75
data[index + 1] = rgb.green;
76
data[index + 2] = rgb.blue;
77
data[index + 3] = 255;
78
};
79
80
const drawDistribution = (canvas, distribution) => {
81
const context = canvas.getContext('2d');
82
const image = context.createImageData(canvas.width, canvas.height);
83
for (let y = 0; y < canvas.height; ++y) {
84
for (let x = 0; x < canvas.width; ++x) {
85
const versor = 1.0 - y / canvas.height; // scales y value to versor value (from 0 to 1)
86
const color = distribution.call(null, versor); // returns pixel color
87
drawPixel(image.data, canvas.width, x, y, color);
88
}
89
}
90
context.putImageData(image, 0, 0);
91
};
92
93
94
// Usage example:
95
96
const points = [
97
{red: 23, green: 23, blue: 230},
98
{red: 23, green: 230, blue: 229},
99
{red: 23, green: 230, blue: 27},
100
{red: 229, green: 230, blue: 23},
101
{red: 230, green: 23, blue: 23}
102
];
103
104
const distribution = createPointsDistribution(points, 200);
105
106
// To get pixel color just use:
107
//
108
// const versor = 0.0; // versor should be from 0.0 to 1.0
109
// const color = distribution.call(null, versor); // color has RGB format
110
111
const canvas = document.createElement('canvas');
112
113
canvas.width = 50;
114
canvas.height = 400;
115
116
drawDistribution(canvas, distribution);
117
118
document.body.appendChild(canvas);
Example colors:
xxxxxxxxxx 1 const points = [ 2 {red: 0x31, green: 0x36, blue: 0x95}, 3 {red: 0x45, green: 0x75, blue: 0xb4}, 4 {red: 0x74, green: 0xad, blue: 0xd1}, 5 {red: 0xab, green: 0xd9, blue: 0xe9}, 6 {red: 0xe0, green: 0xf3, blue: 0xf8}, 7 {red: 0xff, green: 0xff, blue: 0xbf}, 8 {red: 0xfe, green: 0xe0, blue: 0x90}, 9 {red: 0xfd, green: 0xae, blue: 0x61}, 10 {red: 0xf4, green: 0x6d, blue: 0x43}, 11 {red: 0xd7, green: 0x30, blue: 0x27}, 12 {red: 0xa5, green: 0x00, blue: 0x26} 13 ]; Example: Surface Wave - Apache ECharts | ![]() |
xxxxxxxxxx 1 const points = [ 2 {red: 23, green: 23, blue: 230}, 3 {red: 23, green: 230, blue: 229}, 4 {red: 23, green: 230, blue: 27}, 5 {red: 229, green: 230, blue: 23}, 6 {red: 230, green: 23, blue: 23} 7 ]; | ![]() |
xxxxxxxxxx 1 const points = [ 2 {red: 0, green: 230, blue: 27}, 3 {red: 250, green: 0, blue: 23} 4 ]; | ![]() |