Skip to content

Commit 9ddf5f5

Browse files
authored
Merge pull request #63 from oslabs-beta/ms/RealTimeLineChart
Finished integrating initial collection of real-time line charts
2 parents 2732e77 + eaabcad commit 9ddf5f5

File tree

3 files changed

+203
-7
lines changed

3 files changed

+203
-7
lines changed

ksqLight/public/main.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ function createWindow () {
1010
enableRemoteModule: true,
1111
}
1212
})
13-
win.loadURL("http://localhost:3000")
13+
14+
// open dev tools
15+
win.webContents.openDevTools();
16+
17+
win.loadURL("http://localhost:3000");
1418
}
1519

1620
app.on('ready', createWindow);

ksqLight/src/components/Homepage.js

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,39 @@ import React from "react";
22
import { useState } from "react";
33
import { Typography, Grid, Toolbar } from "@mui/material";
44
import { Chart } from "./Chart.js";
5+
import LineChart from "./LineChart.js";
56

67
export const Homepage = () => {
78
const [content, setContent] = useState('Chart placeholder');
9+
10+
const queryTypes = [
11+
["runningQueries", "Number of Running Queries"],
12+
["rebalancingQueries", "Number of Rebalancing Queries"],
13+
["pendingShutdownQueries", "Number of Pending Shutdown Queries"],
14+
["pendingErrorQueries", "Number of Pending Error Queries"],
15+
["numPersistentQueries", "Number of Persistent Queries"],
16+
["numIdleQueries", "Number of Idle Queries"],
17+
["numActiveQueries", "Number of Active Queries"],
18+
["notRunningQueries", "Number of Not Running Queries"],
19+
["messagesProducedPerSec", "Number of Messages Produced Per Second"],
20+
["messagesConsumedTotal", "Number of Messages Consumed"],
21+
["messagesConsumedPerSec", "Number of Messages Consumed Per Second"],
22+
["messagesConsumedMin", "Number of Messages Consumed Min"],
23+
["messagesConsumedMax", "Number of Messages Consumed Max"],
24+
["messagesConsumedAvg", "Number of Messages Consumed Average"],
25+
["livenessIndicator", "Liveness Indicator"],
26+
["errorRate", "Error Rate"],
27+
["errorQueries", "Number of Error Queries"],
28+
["createdQueries", "Number of Created Queries"],
29+
["bytesConsumedTotal", "Number of Bytes Consumed Total"],
30+
];
31+
832
return (
933
<div>
1034
<Toolbar></Toolbar>
1135
<Typography color="primary">Homepage</Typography>
1236
<Grid container spacing={2} justifyContent="flex-start" alignItems="flex-start" sx={{ pl: 28 }}>
13-
<Chart content={content}></Chart>
14-
<Chart content={content}></Chart>
15-
<Chart content={content}></Chart>
16-
<Chart content={content}></Chart>
17-
<Chart content={content}></Chart>
18-
<Chart content={content}></Chart>
37+
{queryTypes.map(([query, description], index) => <LineChart description={description} metric={query} key={index}/>)}
1938
</Grid>
2039
</div>
2140

ksqLight/src/components/LineChart.js

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
import React, { useEffect, useState } from "react";
2+
import { Grid, Typography } from "@mui/material";
3+
import {
4+
ApolloClient,
5+
InMemoryCache,
6+
ApolloProvider,
7+
gql,
8+
} from "@apollo/client";
9+
import Chart from "chart.js/auto";
10+
import ChartStreaming from "chartjs-plugin-streaming";
11+
import 'chartjs-adapter-moment';
12+
13+
// import config from './chartConfig.js';
14+
15+
16+
Chart.register(ChartStreaming);
17+
18+
const client = new ApolloClient({
19+
uri: "http://localhost:5000/graphql",
20+
cache: new InMemoryCache(),
21+
});
22+
23+
// console.log('test: ', Math.round(new Date().getTime() / 1000));
24+
25+
export default function LineChart({ metric, description }) {
26+
useEffect(() => {
27+
let delayed;
28+
// define chart context
29+
const ctx = document.getElementById(metric).getContext("2d");
30+
31+
// define gradient for background
32+
const gradient = ctx.createLinearGradient(0, 0, 0, 400);
33+
gradient.addColorStop(0, 'rgba(58, 123, 213, 1)');
34+
gradient.addColorStop(1, 'rgba(0, 210, 255, 0.3)')
35+
36+
// define chart configuration
37+
const config = {
38+
type: 'line',
39+
data: {
40+
datasets: [{
41+
data: [], // empty at the beginning,
42+
borderColor: 'rgba(58, 123, 213, 1)',
43+
pointRadius: 0,
44+
hitRadius: 30,
45+
hoverRadius: 5,
46+
fill: true,
47+
backgroundColor: gradient,
48+
}]
49+
},
50+
options: {
51+
responsive: true,
52+
animation: {
53+
onComplete: () => {
54+
delayed = true;
55+
},
56+
// delay: (context) => {
57+
// let delay = 0;
58+
// if (context.type === "data" && context.mode === "default" && !delayed) {
59+
// delay = context.dataIndex * 300 + context.datasetIndex * 100;
60+
// }
61+
// return delay;
62+
// }
63+
delay: 3,
64+
},
65+
elements: {
66+
line: {
67+
tension: .4
68+
}
69+
},
70+
scales: {
71+
x: {
72+
type: 'realtime', // x axis will auto-scroll from right to left
73+
realtime: { // per-axis options
74+
duration: 200000, // data in the past 20000 ms will be displayed
75+
refresh: 2000, // onRefresh callback will be called every 1000 ms
76+
delay: 2000, // delay of 1000 ms, so upcoming values are known before plotting a line
77+
pause: false, // chart is not paused
78+
ttl: undefined, // data will be automatically deleted as it disappears off the chart
79+
frameRate: 30, // data points are drawn 30 times every second
80+
81+
// a callback to update datasets
82+
onRefresh: chart => {
83+
84+
// query your data source and get the array of {x: timestamp, y: value} objects
85+
client.query({
86+
query: gql`
87+
query testQuery {
88+
ksqlDBMetrics(metric: "${metric}", resolution: 2, start: ${Math.round(new Date().getTime() / 1000) - 500}, end: ${Math.round(new Date().getTime() / 1000)}) {
89+
x,
90+
y
91+
}
92+
}
93+
`
94+
})
95+
.then(res => {
96+
// chart.data.datasets[0].data.push(...[{x: new Date(), y: 1}]);
97+
const data = res.data.ksqlDBMetrics.map((queryObj) => {
98+
return {
99+
x: new Date(queryObj.x * 1000),
100+
y: queryObj.y
101+
}
102+
});
103+
chart.data.datasets[0].data = data;
104+
})
105+
.catch(error => console.log(error));
106+
}
107+
}
108+
},
109+
y: {
110+
beginAtZero: true,
111+
ticks: {
112+
// display: false,
113+
color: "#999",
114+
stepSize: 5
115+
}
116+
}
117+
},
118+
plugins: {
119+
legend: {
120+
display: false,
121+
// position: "top",
122+
},
123+
title: {
124+
fontFamily: 'Raleway',
125+
color: '#666',
126+
display: true,
127+
text: description,
128+
},
129+
},
130+
}
131+
};
132+
133+
// instantiate new instance of a chart
134+
const realTimeChart = new Chart(ctx, config);
135+
136+
// populate initial data to avoid having to wait for first refresh
137+
// client.query({
138+
// query: gql`
139+
// query testQuery {
140+
// ksqlDBMetrics(metric: "numActiveQueries", resolution: 1, start: ${Math.round(new Date().getTime() / 1000) - 500}, end: ${Math.round(new Date().getTime() / 1000)}) {
141+
// x,
142+
// y
143+
// }
144+
// }
145+
// `
146+
// })
147+
// .then(res => {
148+
// // chart.data.datasets[0].data.push(...[{x: new Date(), y: 1}]);
149+
// const data = res.data.ksqlDBMetrics.map((queryObj) => {
150+
// return {
151+
// x: new Date(queryObj.x * 1000),
152+
// y: queryObj.y
153+
// }
154+
// });
155+
// console.log('this is a test');
156+
// realTimeChart.data.datasets[0].data = data;
157+
// realTimeChart.update();
158+
// })
159+
// .catch(error => console.log(error));
160+
161+
162+
// chart teardown on unmount
163+
return () => {
164+
realTimeChart.destroy();
165+
}
166+
}, []);
167+
168+
return (
169+
<Grid item xs={2}>
170+
<canvas id={metric} width="100%" height="100%"></canvas>
171+
</Grid>
172+
);
173+
}

0 commit comments

Comments
 (0)