Implement Real-Time Charts with WebSockets

The Kendo UI for Charts for Angular provide options for displaying real-time data which comes from a WebSocket server.

You can also set a bidirectional (full-duplex) type of communication and allow multiple clients to push messages to the server which will be received from all connected clients. For the full implementation of the approach, refer to the sample GitHub project.

Configuring the Server

The sample project features a Node.js Express server which serves the Angular application and provides the data feed for the Chart through a WebSocket stream.

The following example demonstrates how to set the HTTP server.

app.use(express.static(path.join(__dirname, '../../dist/websocket-charts')));

   app.get('*', (req, res) => {
       res.sendFile(path.join(__dirname, '../../dist/websocket-charts/index.html'));
   });

   const port = process.env.PORT || 8000;
   const server = http.createServer(app);

   server.listen(port, () => {
       console.log(`HTTP server running on port ${port}...`);
   });

The following example demonstrates how to set the WebSocket server.

const wsPort = 8088;
   const wsServer = new ws.Server({port: wsPort});

   console.log(`WebSocket server is running on port ${wsPort}...`);

   wsServer.on('connection',
           websocket => {
                   setInterval(() => {
                   // Broadcasting to all clients
                   wsServer.clients.forEach(
                       client => client.send(JSON.stringify({
                       value: Math.random() * 50,
                       time: new Date()
                       })));
                   }, 1000);

                   // Broadcasting messages from any client to all clients
                   websocket.on('message', message => {
                   const now = new Date();
                   wsServer.clients.forEach(
                       client => client.send(JSON.stringify({
                       text: message,
                       time: now })));
                   });
           });

Configuring the Client

The following example demonstrates how to configure the WebSocket service.

import { Injectable } from '@angular/core';
   import { Observable } from 'rxjs';

   @Injectable()
   export class WebSocketService {
       public ws: WebSocket;

       public createObservableSocket(url: string): Observable<string> {
           this.ws = new WebSocket(url);

           return Observable.create(observer => {
                   this.ws.onmessage = event => observer.next(event.data);
                   this.ws.onerror = event => observer.error(event);
                   this.ws.onclose = event => observer.complete();
               });
           }

       public sendMessage(message: any): void {
           this.ws.send(message);
       }
   }

Configuring the Chart

The following example demonstrates how to configure the Chart.

<kendo-chart [transitions]="false">
       <kendo-chart-series>
           <kendo-chart-title text="Current temp (&deg;C)"></kendo-chart-title>
           <kendo-chart-series-item
               type="scatterLine"
               [data]="chartValues"
               yField="value" xField="time">
           </kendo-chart-series-item>
       </kendo-chart-series>
       <kendo-chart-x-axis>
           <kendo-chart-x-axis-item
               baseUnit="seconds"
               baseUnitSteps="seconds"
               [min]="min"
               [max]="max">
           </kendo-chart-x-axis-item>
       </kendo-chart-x-axis>
   </kendo-chart>
public chartValues = [];
   public messages = [];
   public min: Date = new Date();
   public max: Date = new Date(this.min.getTime() + 20000);
   private url = 'ws://localhost:8088';

   constructor(private wsService: WebSocketService) {
       wsService.createObservableSocket(this.url)
       .subscribe(m => {
           const item: any = JSON.parse(m);
           item.time = new Date(item.time);
           if (item.value) {
           this.chartValues = [...this.chartValues, item];
           if (this.chartValues.length > 20) {
               this.min = this.chartValues[this.chartValues.length - 20].time;
               this.max = item.time;
           }
           } else {
           this.messages = [...this.messages, item];
           }
       });
   }

In this article