通过 socket.io 更新实时 d3 图表

Posted

技术标签:

【中文标题】通过 socket.io 更新实时 d3 图表【英文标题】:Update real time d3 chart by socket.io 【发布时间】:2015-10-20 17:30:18 【问题描述】:

我正在编写一个基于 d3.js 的实时图表指令。结构如下:

myDirective.js

app.directive('myDirective', function(socketio) 

  return 
    restrict: 'EA',
    templateUrl: '../../views/partials/chart.html',
    controller: DataController,

    link: function(scope, elem, attrs, ctrl) 

      scope.Watch = scope.$watch(function() 
        return ctrl.data;
      , function(newVal) 
        // d3 code part
      );

      socketio.on(event, function(newdata) 
        ctrl.data.push(newdata);
        // redraw chart
      );
    
  ;
);

在上面的d3代码部分,我参考了http://bl.ocks.org/gniemetz/4618602。主要代码几乎相同,图表显示良好。

现在我想使用socket.io通过代码更新图表

socketio.on(event, function(newdata) 
  ctrl.data.push(newdata);
  // redraw chart
);

但不知道如何使用更新后的“ctrl.data”有效地重绘图表。我知道在 Morris.js 中,我们可以通过 '.setData(ctrl.data)' 方法做到这一点,但不知道如何在 d3 中更新。有什么想法吗?

ps:我尝试将上面的d3代码复制/粘贴到这个地方,但是总是报错:“TypeError: t.slice is not a function”

谢谢,

【问题讨论】:

我认为调用 myD3Selection.data(newdata) 会触发 d3 的插入/更新/删除处理程序 想知道什么是 myD3Selection?谢谢@Plato 一个 d3 选择是零个或多个 DOM 元素,通常用 li.myDataBoundItems 之类的 css 标识。 d3 将数据数组中的一项映射到选择中的每个元素。这可以让您的 DOM 在您更改数据时进行响应式更新。 @mbostock 这里有详细解释bost.ocks.org/mike/selection @Plato,虽然这是正确的,但这只是需要的一部分。有关更多信息,请参阅我的答案中的小提琴。 @Plato 是的,该网站有帮助。我认为这也是一个有前途的解决方案,让我稍后尝试。谢谢你的帮助,柏拉图。 【参考方案1】:

快速而肮脏的方式:每次有更新时,清空<div>并重新绘制整个图表。

更优雅的方式:编写自己的update 函数来添加新数据。这是迄今为止最具视觉吸引力的方式,因为图形实际上是动画的。 D3 是为这类事情精心打造的,因此它绝不是其功能的延伸。这将花费更长的时间,但通常会提供更令人愉悦的体验,如 D3 画廊中的一些图表所示(例如:http://square.github.io/crossfilter/、http://bl.ocks.org/NPashaP/96447623ef4d342ee09b)以下是我将如何使用您想要的图表来做到这一点:

保持代码不变 添加一个更新函数,比如名为 Update(),它在您评论 // redraw chartsocketio.on(...) 部分中调用 然后Update() 将重新定义所有 D3 变量并为更改设置动画

Update() 基本上将通过执行从头开始创建图表所用步骤的子集来完成上述项目符号。以下是它所做的概述:重新缩放 x 和 y 轴,以图形方式更新轴,将原始点和线转换到新轴上的新位置,添加新点,并添加可能需要完成的任何线图表

我正在为您开发一个 jsFiddle,并使用一个有效的 Update 来演示上述内容,希望在您的代码中实现它会很简单。完成后我会编辑这篇文章,但我想在我处理它的同时给你一个“快速”的答案,同时试图帮助你。如果您想同时阅读,请查看 http://blog.visual.ly/creating-animations-and-transitions-with-d3-js/


更新

https://jsfiddle.net/npzjLng9/2/。我以您提供的示例为例,必须将要加载的数据修改为本地数据,而不是来自文本文件;但是,它的格式相同,并且为了便于阅读,条目也少了很多。除此之外,我没有对示例进行任何更改。这是我添加的内容:向下滚动并找到最后一个函数Update。这是更新和动画发生的地方。注意函数的流程:

    “更新”数据,就好像您的 socket.io 是接收数据的人,然后将其附加到数据集。 重新定义坐标区 重新定义点和路径 指定过渡持续时间(随意选择适合您的数字) 在情节上实际更新和动画变化

我添加了一个按钮来模拟socket.io 接收事件。

对于您的应用程序,忽略Update() 函数中的data.pushconsole.log,我认为这就是您所需要的——除了将数据指向您的ctrl.data 数组并运行Update()当然,在您的socketio.on(...) 中起作用。

相同的基本大纲适用于大多数图表的动画/更新。

希望对你有帮助!

【讨论】:

非常感谢@mjdiaz89 我也在努力按照你的指导,期待你的jsFiddle 我上传了小提琴(上面编辑过的帖子)。看看,如果您有任何问题,请告诉我。享受吧! 很好的回复,很有帮助。但我认为我仍然需要更多时间来消化你的代码。无论如何,感谢您的大力帮助。 @mjdiaz89 我想用socketio来更新数据,所以我复制粘贴你的更新函数体,并把它放到socketio.on这样的回调函数中,jsfiddle.net/lszhou/zLeyv0q2但是我得到了错误“错误:无效值对于 属性”,我猜它与变量范围有关,请指教。 @Manuel J.迪亚兹 这行得通吗?我想你会有一个变量范围的问题,不是吗?我提供的 Fiddle 有效,因为脚本根目录中的所有变量声明也在 Update() 函数的范围内,因此 D3 能够重新定义它们并相应地更新图表。

以上是关于通过 socket.io 更新实时 d3 图表的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Socket.io 实时更新大量数据

D3.JS 具有实时数据、平移和缩放的时间序列折线图

socket.io vs swr 用于更新实时内容

如何使用 mysql 数据库中的 nodejs 和 socket.io 在网页上获得实时更新?

单击geojson多边形到传单地图时添加的更新d3图表

通过 socket.io 流式传输实时音频