function drawHeatMap(selection, dimensions, margin, scales, linearMap) {
const
width = dimensions.width - margin.left - margin.right,
height = dimensions.height - margin.top - margin.bottom,
nx = model.N,
ny = nx * (height / width),
x_begin = scales.x.domain()[0],
x_end = scales.x.domain()[1],
y_begin = scales.y.domain()[0],
y_end = scales.y.domain()[1],
dx = (x_begin + x_end) / nx,
dy = (y_begin + y_end) / ny,
x_borders = d3.range(x_begin, x_end, dx),
y_borders = d3.range(y_end, y_begin, -dy);
let foreignObject = selection
.append("g")
.style("transform", "translate(0, 0)")
.append("foreignObject")
.attr("x", margin.left)
.attr("y", margin.top)
.attr("width", width)
.attr("height", height);
let foBody = foreignObject
.append("xhtml:body")
.style("margin", "0px")
.style("padding", "0px")
.style("background-color", "none")
.style("width", width + "px")
.style("height", height + "px");
let canvas = foBody
.append("canvas")
.attr("width", nx)
.attr("height", ny)
.style("width", "100%")
.style("height", "100%");
let context = canvas.node().getContext("2d");
let image = context.createImageData(nx, ny);
let pointer = -1;
y_borders.forEach(function(y) {
x_borders.forEach(function(x) {
let color = d3.rgb(scales.color(linearMap(x, y)));
image.data[++pointer] = color.r;
image.data[++pointer] = color.g;
image.data[++pointer] = color.b;
image.data[++pointer] = (color.opacity * 255) / 2;
});
});
context.putImageData(image, 0, 0);
}