Example demonstrates our Angular Chart's feature that synchronizes tooltip, crosshair, zooming & panning across multiple charts. i.e. When you move mouse over one chart, it automatically updates tooltip / crosshair across all other charts. This feature is commonly used in dashboards to visualize related data.
/* app.component.ts */ import { Component } from '@angular/core'; import * as data from '../assets/server-metrics.json'; /* Tutorial: https://www.javatpoint.com/display-data-from-json-file-in-angular */ interface JsonData { "read": number, "time": number, "used": number, "user": number, "wait": number, "cache": number, "write": number, "system": number, "buffers": number, "inbound": number, "outbound": number } @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent{ dps1: any = []; dps2: any = []; dps3: any = []; charts: any = []; toolTip = { shared: true }; legend = { cursor: "pointer", itemclick: function (e: any) { if (typeof (e.dataSeries.visible) === "undefined" || e.dataSeries.visible) { e.dataSeries.visible = false; } else { e.dataSeries.visible = true; } e.chart.render(); } }; systemDps: any = []; userDps: any = []; waitDps: any = []; buffersDps: any = []; cacheDps: any = []; usedDps: any = []; inboundDps: any = []; outboundDps: any = []; writeDps: any= []; readDps: any = []; onToolTipUpdated: any; onToolTipHidden: any; onCrosshairUpdated: any; onCrosshairHidden: any; onRangeChanged: any; cpuChartOptions = { animationEnabled: true, theme: "light2", // "light1", "light2", "dark1", "dark2" title:{ text: "CPU Utilization" }, toolTip: this.toolTip, axisY: { valueFormatString: "#0.#%", }, legend: this.legend, data: [{ type: "splineArea", showInLegend: "true", name: "User", yValueFormatString: "#0.#%", color: "#64b5f6", xValueType: "dateTime", xValueFormatString: "DD MMM YY HH:mm", legendMarkerType: "square", dataPoints: this.userDps },{ type: "splineArea", showInLegend: "true", name: "System", yValueFormatString: "#0.#%", color: "#2196f3", xValueType: "dateTime", xValueFormatString: "DD MMM YY HH:mm", legendMarkerType: "square", dataPoints: this.systemDps },{ type: "splineArea", showInLegend: "true", name: "Wait", yValueFormatString: "#0.#%", color: "#1976d2", xValueType: "dateTime", xValueFormatString: "DD MMM YY HH:mm", legendMarkerType: "square", dataPoints: this.waitDps }] }; memoryChartOptions = { animationEnabled: true, theme: "light2", title:{ text: "Memory Usage" }, axisY: { suffix: " GB" }, toolTip: this.toolTip, legend: this.legend, data: [{ type: "splineArea", showInLegend: "true", name: "Cache", color: "#e57373", xValueType: "dateTime", xValueFormatString: "DD MMM YY HH:mm", yValueFormatString: "#.## GB", legendMarkerType: "square", dataPoints: this.cacheDps },{ type: "splineArea", showInLegend: "true", name: "Buffers", color: "#f44336", xValueType: "dateTime", xValueFormatString: "DD MMM YY HH:mm", yValueFormatString: "#.## GB", legendMarkerType: "square", dataPoints: this.buffersDps },{ type: "splineArea", showInLegend: "true", name: "Used", color: "#d32f2f", xValueType: "dateTime", xValueFormatString: "DD MMM YY HH:mm", yValueFormatString: "#.## GB", legendMarkerType: "square", dataPoints: this.usedDps }] } networkChartOptions = { animationEnabled: true, theme: "light2", title:{ text: "Network Traffic" }, axisY: { suffix: " Kb/s" }, toolTip: this.toolTip, legend: this.legend, data: [{ type: "splineArea", showInLegend: "true", name: "Outbound", color: "#81c784", xValueType: "dateTime", xValueFormatString: "DD MMM YY HH:mm", yValueFormatString: "#.## Kb/s", legendMarkerType: "square", dataPoints: this.outboundDps },{ type: "splineArea", showInLegend: "true", name: "Inbound", color: "#388e3c", xValueType: "dateTime", xValueFormatString: "DD MMM YY HH:mm", yValueFormatString: "#.## Kb/s", legendMarkerType: "square", dataPoints: this.inboundDps }] } diskChartOptions = { animationEnabled: true, theme: "light2", title:{ text: "Disk I/O (IOPS)" }, axisY: {}, toolTip: this.toolTip, legend: this.legend, data: [{ type: "splineArea", showInLegend: "true", name: "Write", color: "#ffb74d", xValueType: "dateTime", xValueFormatString: "DD MMM YY HH:mm", yValueFormatString: "#.## ops/second", legendMarkerType: "square", dataPoints: this.writeDps },{ type: "splineArea", showInLegend: "true", name: "Read", color: "#f57c00", xValueType: "dateTime", xValueFormatString: "DD MMM YY HH:mm", yValueFormatString: "#.## ops/second", legendMarkerType: "square", dataPoints: this.readDps }] } getChartInstance = (chart: any) => { this.charts.push(chart); } jsonData: JsonData[] = (data as any).default; ngOnInit(){ for(var i = 0; i < this.jsonData.length; i++) { this.systemDps.push({x: Number(this.jsonData[i].time), y: Number(this.jsonData[i].system)}); this.userDps.push({x: Number(this.jsonData[i].time), y: Number(this.jsonData[i].user)}); this.waitDps.push({x: Number(this.jsonData[i].time), y: Number(this.jsonData[i].wait)}); this.buffersDps.push({x: Number(this.jsonData[i].time), y: Number(this.jsonData[i].buffers)}); this.cacheDps.push({x: Number(this.jsonData[i].time), y: Number(this.jsonData[i].cache)}); this.usedDps.push({x: Number(this.jsonData[i].time), y: Number(this.jsonData[i].used)}); this.inboundDps.push({x: Number(this.jsonData[i].time), y: Number(this.jsonData[i].inbound)}); this.outboundDps.push({x: Number(this.jsonData[i].time), y: Number(this.jsonData[i].outbound)}); this.writeDps.push({x: Number(this.jsonData[i].time), y: Number(this.jsonData[i].write)}); this.readDps.push({x: Number(this.jsonData[i].time), y: Number(this.jsonData[i].read)}); } } ngAfterViewInit() { this.syncCharts(this.charts, true, true, true); } syncCharts = (charts: any, syncToolTip: any, syncCrosshair: any, syncAxisXRange: any) => { if(!this.onToolTipUpdated){ this.onToolTipUpdated = function(e: any) { for (var j = 0; j < charts.length; j++) { if (charts[j] != e.chart) charts[j].toolTip.showAtX(e.entries[0].xValue); } } } if(!this.onToolTipHidden){ this.onToolTipHidden = function(e: any) { for( var j = 0; j < charts.length; j++){ if(charts[j] != e.chart) charts[j].toolTip.hide(); } } } if(!this.onCrosshairUpdated){ this.onCrosshairUpdated = function(e: any) { for(var j = 0; j < charts.length; j++){ if(charts[j] != e.chart) charts[j].axisX[0].crosshair.showAt(e.value); } } } if(!this.onCrosshairHidden){ this.onCrosshairHidden = function(e: any) { for( var j = 0; j < charts.length; j++){ if(charts[j] != e.chart) charts[j].axisX[0].crosshair.hide(); } } } if(!this.onRangeChanged){ this.onRangeChanged = function(e: any) { for (var j = 0; j < charts.length; j++) { if (e.trigger === "reset") { charts[j].options.axisX.viewportMinimum = charts[j].options.axisX.viewportMaximum = null; charts[j].options.axisY.viewportMinimum = charts[j].options.axisY.viewportMaximum = null; charts[j].render(); } else if (charts[j] !== e.chart) { charts[j].options.axisX.viewportMinimum = e.axisX[0].viewportMinimum; charts[j].options.axisX.viewportMaximum = e.axisX[0].viewportMaximum; charts[j].render(); } } } } for(var i = 0; i < charts.length; i++) { //Sync ToolTip if(syncToolTip) { if(!charts[i].options.toolTip) charts[i].options.toolTip = {}; charts[i].options.toolTip.updated = this.onToolTipUpdated; charts[i].options.toolTip.hidden = this.onToolTipHidden; } //Sync Crosshair if(syncCrosshair) { if(!charts[i].options.axisX) charts[i].options.axisX = { labelAngle: 0, crosshair: { enabled: true, snapToDataPoint: true, valueFormatString: "HH:mm" }}; charts[i].options.axisX.crosshair.updated = this.onCrosshairUpdated; charts[i].options.axisX.crosshair.hidden = this.onCrosshairHidden; } //Sync Zoom / Pan if(syncAxisXRange) { charts[i].options.zoomEnabled = true; charts[i].options.rangeChanged = this.onRangeChanged; } charts[i].render(); } } }
/* app.module.ts */ import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; import { CanvasJSAngularChartsModule } from '@canvasjs/angular-charts'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, CanvasJSAngularChartsModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
/* app.component.html */ <div> <canvasjs-chart [options]="cpuChartOptions" (chartInstance)="getChartInstance($event)" [styles]="{width: '50%', height: '300px', 'float': 'left' }"></canvasjs-chart> <canvasjs-chart [options]="memoryChartOptions" (chartInstance)="getChartInstance($event)" [styles]="{width: '50%', height: '300px', 'float': 'left'}"></canvasjs-chart> <canvasjs-chart [options]="networkChartOptions" (chartInstance)="getChartInstance($event)" [styles]="{width: '50%', height: '300px', 'float': 'left'}"></canvasjs-chart> <canvasjs-chart [options]="diskChartOptions" (chartInstance)="getChartInstance($event)" [styles]="{width: '50%', height: '300px', 'float': 'left'}"></canvasjs-chart> </div>
In the above example, we are using the below listed events and methods.
Chart - rangeChanging, rangeChanged
ToolTip - updated, hidden, showAtX, hide
Crosshair - updated, hidden, showAt, hide