How to reduce lag while moving elements in canvas using d3.js

Viewed 105

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>

0 Answers
Related