Implementing Real-Time Charts with WebSockets
Environment
Product | Progress® Kendo UI® for Angular Charts |
Description
How can I display real-time data which comes from a WebSocket server in the Kendo UI for Angular Chart?
Solution
Apart from displaying real-time data which comes from a WebSocket, the Chart provides options for setting a bidirectional (full-duplex) type of communication and allows 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 (°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];
}
});
}