使用JavaScript在HTML5画布上绘制大量点。

6
我正在尝试在HTML5画布上绘制巨大(60k)数量的(x,y)点,并使用D3.js在Chrome和Firefox中模拟流数据点,但发现浏览器在约10秒后会冻结和崩溃。
我是通过以下方式生成随机值的数据集:
var data = d3.range(60000).map(function() { return Math.random() * 500; });

将数据生成分成多个部分是否有帮助?我觉得这可能是因为尝试一次性存储如此大的数据集所导致的,就像我展示的那样。

有没有办法可以防止这种情况发生?例如绘制和保存较小的部分作为平铺图像?

添加的代码:

var margin = {top: 20, right: 20, bottom: 20, left: 40},
    w = 100 - margin.left - margin.right,
    h = 100 - margin.top - margin.bottom;

    var canvas = d3.select("canvas")
      .node();

    var context = canvas.getContext('2d');

    var scale = d3.scale.linear()
    . range([0,w])
    .domain([0,h]);


    data = d3.range(60000).map(function(){return Math.random()*500});
    data.forEach(function(d,i) {
      context.strokeStyle="red";
      context.lineWidth="1";
      context.lineTo(scale(++k),scale(d));
      context.stroke();
    });

这个问题有点不太对,你是在使用d3制作canvas还是svg? - Cyril Cherian
我正在使用画布。 - Bob R
我的担忧是,有60K个(x,y)坐标流进来可能会导致相同的崩溃。 - Bob R
数据 = d3.range(60000).map(function(){return Math.random()*500}); 这几乎只需要毫秒级的时间。嗯...如果你正在使用画布(canvas),那么它会在绘制60k个点的时间内冻结...并不总是像你所说的那样,原因可能是其他的...你能不能创建一个fiddle(jsfiddle.net)呢?一旦画布被绘制出来,它就不应该再冻结了... - Cyril Cherian
这里有一个 JSFiddle,它甚至无法为我加载 http://jsfiddle.net/Q5Jag/1494/ - Bob R
显示剩余3条评论
2个回答

1
问题在这里:

data.forEach(function(d,i) {
      context.strokeStyle="red";
      context.lineWidth="1";
      context.lineTo(scale(++k),scale(d));
      context.stroke();//this should be out of the for loop you should be doing it once not everytime
    });

像这样的东西:
data.forEach(function(d,i) {
  context.strokeStyle="red";
  context.lineWidth="1";
  var j = scale(d);
  var m = scale(d++);
  context.lineTo(j,m);
});
context.stroke();

工作代码 在这里

希望这能帮到你!


Cyril有没有办法在canvas上表现为路径动画,而不是在SVG上,使其看起来类似于http://bl.ocks.org/duopixel/4063326? - Bob R
1
Bob,如果我已经在上面的回答中解决了您的问题,请将其标记为已接受。对于您的第二个查询,请提出另一个SO问题,我可以将我的其他答案复制到那里。这样对于其他遇到类似问题的人会有帮助。 - Cyril Cherian

1

既然您在评论区提出了完全不同的问题,我想另外回答一下。

Comments and working code inline.

var margin = {top: 20, right: 20, bottom: 20, left: 40},
    w = 100 - margin.left - margin.right,
    h = 100 - margin.top - margin.bottom;

    var canvas = d3.select("canvas")
      .node();

    var context = canvas.getContext('2d');

 var data = d3.range(11).map(function(){return Math.random()*10})
    var x = d3.scale.linear().domain([0, 10]).range([0, 700]);
    var y = d3.scale.linear().domain([0, 10]).range([10, 290]);
    var line = d3.svg.line()
      .interpolate("cardinal")
      .x(function(d,i) {console.log(x(i));return x(i);})
      .y(function(d) {return y(d);})
    //making a dummy SVG
    var path = d3.select("body").append("svg").append("path")
      .attr("d", line(data))
      .attr("stroke", "steelblue")
      .attr("stroke-width", "2")
      .attr("fill", "none").remove();
   d3.select("body svg").remove();

    //going from 0 to the paths total length and storing all the points
    var points = [];
    for(var i =0; i < path.node().getTotalLength(); i++){
        points.push(path.node().getPointAtLength(i));//store point @ that length
    }
    var id = window.setInterval(function(){
      console.log("Doing")
      var point = points.shift();//take each point
      context.strokeStyle="red";
      context.lineWidth="1";
      context.lineTo(point.x,point.y);
      context.stroke();
      if(points.length <= 0){
        console.log("Finished")
        window.clearInterval(id);//clear the interval since the drawing is complete
      }
    }, 10)
    
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<!DOCTYPE html>
<html>

  <head>
    <link rel="stylesheet" href="style.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.10/d3.js"></script>
    
  </head>

  <body>
    <canvas id="myCanvas" width="500" height="500" style="border:1px solid #000000;">
</canvas>
  <script src="script.js"></script>
  </body>

</html>

Plunker上有可运行的代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接