My task is to load relatively large number of elements in canvas and then draw/move other elements on top of them. I have made the following sample as a POC. I have drawn the graph in the background and also drawn some rectangles to represent the elements on top. I want to move the rectangles on top. this sample code executes relatively successfully, but I notice there is a lag in moving the mouse and corresponding movement of the rectangle. How can I improve this behavior?
var width = 1250,
height = 100;
var base = d3.select("#container");
var chart = base.append("canvas")
.attr("width", 1400)
.attr("height", 750);
var context = chart.node().getContext("2d");
var dataContainer = base.append("custom");
var colourScale;
var groupSpacing = 4;
var cellSpacing = 2;
var cellSize = Math.floor((width - 11 * groupSpacing) / 100) - cellSpacing;
function drawBackground(data) {
colourScale = d3.scaleSequential(d3.interpolateSpectral).domain(d3.extent(data, function(d) {
return d.value;
}));
join = dataContainer.selectAll('custom1.rect')
.data(data);
var enterSel = join.enter()
.append('custom1')
.attr('class', 'rect')
.attr('x', function(d, i) {
var x0 = Math.floor(i / 100) % 10,
x1 = Math.floor(i % 10);
return groupSpacing * x0 + (cellSpacing + cellSize) * (x1 + x0 * 10);
})
.attr('y', function(d, i) {
var y0 = Math.floor(i / 1000),
y1 = Math.floor(i % 100 / 10);
return groupSpacing * y0 + (cellSpacing + cellSize) * (y1 + y0 * 10);
})
.attr('width', 0)
.attr('height', 0);
join
.merge(enterSel)
.transition()
.attr('width', cellSize)
.attr('height', cellSize)
.attr('fillStyle', function(d) {
return colourScale(d.value);
});
}
function drawAnno(data) {
var dataBinding = dataContainer.selectAll("custom.rect")
.data(data, function(d) {
return d;
});
dataBinding.enter()
.append("custom")
.attr('class', "rect")
.attr("x", function(d) {
return d.x;
})
.attr("y", function(d) {
return d.y;
})
.attr("size", 57)
.attr("fillStyle", "red");
dataBinding.exit().remove();
}
function drawCanvas() {
// clear canvas
context.fillStyle = "#fff";
context.rect(0, 0, chart.attr("width"), chart.attr("height"));
context.fill();
var elements1 = dataContainer.selectAll('custom1.rect');
elements1.each(function(d, i) {
var node = d3.select(this);
context.fillStyle = node.attr('fillStyle');
context.fillRect(node.attr('x'), node.attr('y'), node.attr('width'), node.attr('height'))
});
var elements = dataContainer.selectAll("custom.rect");
elements.each(function(d) {
var node = d3.select(this);
context.beginPath();
context.lineWidth = 5;
context.rect(node.attr("x"), node.attr("y"), node.attr("size"), node.attr("size"));
context.stroke();
context.closePath();
})
}
var value = 43000;
var v = 700;
var data = [];
var data1 = [];
var x = 5;
var y = 8;
var xx = 5;
var yy = 8;
d3.range(value).forEach(function(el) {
data.push({
value: el
});
});
d3.range(v).forEach(function(l) {
xx = xx + 20;
yy = yy + 10;
data1.push({
x: xx,
y: yy
});
});
drawBackground(data);
drawAnno(data1);
drawCanvas();
var move_flag = false;
var x1, y1;
function f(event) {
drawCanvas();
if (move_flag == true) {
var tt1 = document.getElementById("t1").value;
if (tt1 < 1)
tt1 = 1;
else
tt1 = tt1 - 1;
var x = event.clientX;
var y = event.clientY;
data1[tt1]['x'] = x;
data1[tt1]['y'] = y;
drawAnno(data1);
drawCanvas();
}
}
var x_val = 0;
var x;
var y;
function click_event() {
if (move_flag == true) {
move_flag = false;
} else {
move_flag = true;
}
}
var c = document.getElementById('container');
c.addEventListener("mousemove", f);
body {
font-family: 'Open Sans', sans-serif;
}
canvas {
border: 1px dotted #ccc;
}
#text-explain {
display: inline-block;
font-size: 0.75em;
margin-bottom: 1em;
}
.alert {
color: tomato;
}
<button onclick="click_event()" type="button">Move Annotation!</button>
<input type="text" placeholder="which rectangle want to move" id="t1">
<div id="container"></div>
<script src="https://d3js.org/d3.v4.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>