Friday, March 23, 2018

D3 js background tab freeze while rendering to canvas

Leave a Comment

I'm facing an issue with D3.js. When rendering data to canvas the tab freezes when it being inactive. It easily become noticeable after several minutes of tab being in a background.

I've created an example JSFiddle to reproduce the issue, it can be easily be done on local environment as well, source code follows.

(() => {    // data container script    $(() => {      let $dataContainer = $('.data');      setInterval(() => {        $dataContainer.empty();        let numbers = [];        for (let i = 0; i < 10; i++) {          let randNumber = Math.floor(Math.random() * 100);          numbers.push(randNumber);          $dataContainer.append(`<p>${randNumber}</p>`);        }        $(document).trigger('data:updated', [numbers])      }, 1000);    });      // actual canvas render    $(() => {      // boring stuff      let base = d3.select(".viz");      let chart = base.append("canvas")        .attr("width", 400)        .attr("height", 300);        let context = chart.node().getContext("2d");        let detachedContainer = document.createElement("custom");      let dataContainer = d3.select(detachedContainer);          // d3 stuff and data binding      let drawCustom = (data) => {        let scale = d3.scale.linear()          .domain(d3.extent(data))          .range([10, 280]);          let dataBinding = dataContainer.selectAll("custom.rect")        	.data(data, (d) => { return d; });          dataBinding.enter()          .append("custom")          .classed("rect", true)          .attr("size", 0)          .attr("x", 11)          .attr("y", scale)          .transition()          .duration(500)          .attr("size", 8)          .attr("fillStyle", "red");          dataBinding.exit()          .transition()          .duration(500)          .attr("size", 0)          .remove()      }          let drawCanvas = () => {        // clear canvas        context.fillStyle = "#fff";        context.rect(0,0,chart.attr("width"),chart.attr("height"));        context.fill();          let elements = dataContainer.selectAll("custom.rect");        elements.each(function(d) {          let node = d3.select(this);            context.beginPath();          context.fillStyle = node.attr("fillStyle");          context.rect(node.attr("x"), node.attr("y"), node.attr("size"), node.attr("size"));          context.fill();          context.closePath();          });      }          $(document).on('data:updated', (e, numbers) => {        drawCustom(numbers);      });            d3.timer(drawCanvas);    });  })();
.data {    outline: 1px solid #777777;    min-width: 10px;    height: 300px;    background-color: rgb(238, 238, 238);    display: inline-block;    vertical-align: top;      }    p {    margin: 0.7em;  }    .viz {    display: inline-block;  }    canvas {    outline: 1px solid #777777;  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>  <div class="data"></div>  <div class="viz"></div>

I want the rendering be seamless. What can be done in this case? I believe it may be something to do with d3.timer function, but may be wrong.

0 Answers

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment