在本文中,将探讨如何使用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);
            }
        });