在本文中,将探讨如何使用HTML5和Spike-Engine库来创建一个实时数据流的图表。这种图表可以动态地从应用程序服务器流式传输数据,并在客户端实时更新。目标是展示数据的模式,而不仅仅是单个值。
继之前关于实时仪表盘的文章之后,希望能够创建一个流式图表,以流线图的形式展示相同的信息(每秒数据包速率)。这种方法的优势在于,它不仅能够展示一个值,还能展示整个数据模式。
为了收集数据,使用了滚动窗口方法,就像之前的文章中提到的那样。这次,创建了一个更优雅的算法封装,创建了一个RollingQueue,它保持其大小并自动移动采样窗口。代码相当直接:
public class RollingQueue<T> : Queue<T>
{
public RollingQueue(int size)
{
this.Size = size;
}
public int Size { get; set; }
new public void Enqueue(T item)
{
base.Enqueue(item);
if (this.Count > this.Size)
{
this.Dequeue();
}
}
}
首先,创建并使服务在任何可用的IPAddress上监听:
Service.Listen(new TcpBinding(IPAddress.Any, 8002));
接下来,创建一个PubHub实例,它充当发布-订阅通道。这实现了发布-订阅模型。在发布-订阅模型中,消息的发送者(称为发布者)并不直接将消息编程发送给特定的接收者(称为订阅者)。相反,发布的消息被归类为类别,而不知道是否有任何订阅者。同样,订阅者对一个或多个类别表示兴趣,并且只接收他们感兴趣的消息,而不知道是否有任何发布者。
现在,让看看客户端是如何制作的。使用了Joe Walnes的Smoothie Charting库,它在Canvas2D元素中渲染图表,使其非常平滑。Canvas2D元素在大多数现代浏览器中都是硬件加速的,因此可以期待一个良好的帧率,即使是在移动设备上。
这个图表库非常容易使用,他们甚至提供了一个在线构建器,允许生成代码并调整图表的外观和感觉。
首先向HTML页面添加一些依赖项:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="spike-sdk.min.js"></script>
<script src="http://smoothiecharts.org/smoothie.js"></script>
接下来,在HTML DOM中添加Canvas2D元素,该元素将包含图表本身。定义了600像素的宽度,将有1像素代表50毫秒的数据。由于每200毫秒采样一次,这意味着将有每4像素一个数据点,最终在图表中同时渲染150个数据点。换句话说,图表将能够容纳30秒的数据。
<canvas id="smoothie-chart" width="600" height="125"></canvas>
下一步是,在JavaScript中创建图表和一个时间序列,代表数据的时间序列。注意设置的millisPerPixel值为50,如上所述。
var chart = new SmoothieChart({
millisPerPixel: 50,
grid: {
fillStyle: 'transparent',
strokeStyle: 'rgba(166,197,103,0.20)',
sharpLines: true,
millisPerLine: 4000,
verticalSections: 8,
borderVisible: false
},
labels: { fillStyle: '#000000' }
});
var canvas = document.getElementById('smoothie-chart');
var series = new TimeSeries();
chart.addTimeSeries(series, { lineWidth: 2, strokeStyle: '#A6C567', fillStyle: 'rgba(166,197,103,0.20)' });
chart.streamTo(canvas, 500);
接下来,使用Spike-Engine库的ServerChannel连接到远程服务器。一旦连接,它就订阅PubHub,并且能够接收消息。
var server = new spike.ServerChannel("127.0.0.1:8002");
server.on('connect', function() {
server.hubSubscribe('PacketWatch', null);
});
最后,需要钩住hubEventInform事件,它将处理从服务器接收到的消息。在这种情况下,有两种情况:第一种情况,如果得到的值是一个数组。这意味着收到了历史记录,需要填充图表。通过将数据追加到TimeSeries来填充图表。然而,还需要提供数据点的时间。为了做到这一点:
server.on('hubEventInform', function(p) {
var value = JSON.parse(p.message);
if ($.isArray(value)) {
var time = new Date().getTime();
var length = value.length;
var element = null;
for (var i = 0; i < length; i++) {
element = value[i];
series.append(time - 30000 + (i * 200), element);
}
} else {
var count = $('#packetCounter');
count.text(value);
series.append(new Date().getTime(), value);
}
});