简体   繁体   English

如何使用d3 + socket.io进行平滑过渡

[英]how to make smooth transitions with d3 + socket.io

I have a d3.js treemap that is getting pinged every time the server emits an update. 我有一个d3.js树形图,每次服务器发出更新时都会对其执行ping操作。 The updates are coming off the twitter stream; 更新来自Twitter流。 there are many updates. 有很多更新。 The treemap is thus very jerky in its animations because it has already updated multiple times before the 1500 ms transition can finish. 因此,树形图的动画非常生涩,因为在1500毫秒过渡完成之前,树形图已多次更新。

Is it possible to separate the code which updates node values from the code which updates the view? 是否可以将更新节点值的代码与更新视图的代码分开? I hope to find a solution that will update the values of the treemap continuously, but only update the view every 1500 - 2000ms. 我希望找到一个解决方案,该解决方案将不断更新树形图的值,但仅每1500-2000ms更新一次视图。

Please see my full d3 script : 请查看我完整的d3脚本

var socket = io.connect();

var margin = {top: 40, right: 10, bottom: 10, left: 10},
    width = 1000 - margin.left - margin.right,
    height = 650 - margin.top - margin.bottom;

var color = d3.scale.category20c();

var treemap = d3.layout.treemap()
    .size([width, height])
    .sticky(false)
    .value(function(d) { return d.size; });

var div = d3.select("body").append("div")
    .style("position", "relative")
    .style("width", (width + margin.left + margin.right) + "px")
    .style("height", (height + margin.top + margin.bottom) + "px")
    .style("left", margin.left + "px")
    .style("top", margin.top + "px");

var root;

socket.on('update', function(stream) {
  console.log('tweets')

  div.datum(root).selectAll(".node").remove();

  root = stream.masterlist;

  var node = div.datum(root).selectAll(".node")
      .data(treemap.nodes)
    .enter().append("div")
      .attr("class", "node")
      .call(position)
      .style("background", function(d) { return d.children ? color(d.name) : null; })
      .text(function(d) { return d.children ? null : d.name; });

  d3.selectAll("input").on("change", function change() {
    var value = this.value === "count"
        ? function() { return 1; }
        : function(d) { return d.size; };

    node
        .data(treemap.value(value).nodes)
      .transition()
        .duration(1500)
        .call(position);
  });
});

function position() {
  this.style("left", function(d) { return d.x + "px"; })
      .style("top", function(d) { return d.y + "px"; })
      .style("width", function(d) { return Math.max(0, d.dx - 1) + "px"; })
      .style("height", function(d) { return Math.max(0, d.dy - 1) + "px"; });
}

This code was taken from the treemap example on the excellent bl.ocks.org website, with minor changes (my data comes from a callback rather than a json). 这段代码取自出色的bl.ocks.org网站上的树图示例 ,仅作了细微的更改(我的数据来自回调而不是json)。 I have tried to split value logic from view logic with a setInterval() outside of socket.on() , but my attempts either fail to slow down transitions or they break the treemap completely. 我试图在socket.on() setInterval()外部使用setInterval()从视图逻辑中拆分值逻辑,但是我的尝试要么无法减慢转换速度,要么就完全破坏了树形图。

  d3.selectAll("input").on("change", function change() {
    var value = this.value === "count"
        ? function() { return 1; }
        : function(d) { return d.size; };

  });
}); // end socket.on();

setInterval(function() {
  node
      .data(treemap.value(value).nodes)
    .transition()
      .duration(1500)
      .call(position);
  }, 2000);

Many thanks for any insight! 非常感谢您的见解!

What you are wanting to do is called debounce. 您要执行的操作称为反跳。 There are several javascript libraries that have one you could use (I use underscore). 有几个javascript库可供您使用(我使用下划线)。 You could also write one yourself. 您也可以自己写一个。 I found this one in a blog post : 我在博客文章中找到了这个:

function debounce(fn, delay) {
  var timer = null;
  return function () {
    var context = this, args = arguments;
    clearTimeout(timer);
    timer = setTimeout(function () {
      fn.apply(context, args);
    }, delay);
  };
} 

Once you have a debounce function that you implemented or stole, the rest is easy: you just wrap the function that handles you on update with debounce: 一旦实现或窃取了防抖动功能,其余的操作就很容易了:您只需用防抖动来包装处理更新的函数:

socket.on('update', debounce(function(stream) {
  console.log('tweets')
  ...
}));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM