From 8ef6c4becc458974bb821e7748cfebfaee465ca7 Mon Sep 17 00:00:00 2001 From: Tunir Wabhitkar Date: Thu, 29 Aug 2024 00:44:48 +0530 Subject: [PATCH 1/3] Update App.tsx --- src/App.tsx | 47 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 0728518c0d8..ddedc3dffaf 100755 --- a/src/App.tsx +++ b/src/App.tsx @@ -8,6 +8,7 @@ import './App.css'; */ interface IState { data: ServerRespond[], + showGraph: boolean, // Add showGraph property } /** @@ -15,13 +16,14 @@ interface IState { * It renders title, button and Graph react element. */ class App extends Component<{}, IState> { + private interval: NodeJS.Timeout | null = null; // Add interval property + constructor(props: {}) { super(props); this.state = { - // data saves the server responds. - // We use this state to parse data down to the child element (Graph) as element property data: [], + showGraph: false, // Initialize showGraph to false }; } @@ -29,18 +31,35 @@ class App extends Component<{}, IState> { * Render Graph react component with state.data parse as property data */ renderGraph() { - return () + if (this.state.showGraph) { + return ; + } + return null; } /** * Get new data from server and update the state with the new data */ getDataFromServer() { - DataStreamer.getData((serverResponds: ServerRespond[]) => { - // Update the state by creating a new array of data that consists of - // Previous data in the state and the new data from server - this.setState({ data: [...this.state.data, ...serverResponds] }); - }); + if (this.interval) { + clearInterval(this.interval); // Clear existing interval if any + } + + this.interval = setInterval(() => { + DataStreamer.getData((serverResponds: ServerRespond[]) => { + // Update the state by creating a new array of data that consists of + // Previous data in the state and the new data from server + this.setState((prevState) => ({ + data: [...prevState.data, ...serverResponds] + })); + }); + }, 1000); // Fetch data every second + } + + componentWillUnmount() { + if (this.interval) { + clearInterval(this.interval); // Clean up interval on unmount + } } /** @@ -54,12 +73,10 @@ class App extends Component<{}, IState> {
@@ -67,7 +84,7 @@ class App extends Component<{}, IState> {
- ) + ); } } From 409de1f6ecc56cf8e7a683ab04ce2b2d841a1399 Mon Sep 17 00:00:00 2001 From: Tunir Wabhitkar Date: Thu, 29 Aug 2024 00:45:03 +0530 Subject: [PATCH 2/3] Update Graph.tsx --- src/Graph.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Graph.tsx b/src/Graph.tsx index 3b2a7da1a38..2c6aa75e933 100644 --- a/src/Graph.tsx +++ b/src/Graph.tsx @@ -14,7 +14,7 @@ interface IProps { * Perspective library adds load to HTMLElement prototype. * This interface acts as a wrapper for Typescript compiler. */ -interface PerspectiveViewerElement { +interface PerspectiveViewerElement extends HTMLElement { load: (table: Table) => void, } @@ -32,7 +32,7 @@ class Graph extends Component { componentDidMount() { // Get element to attach the table from the DOM. - const elem: PerspectiveViewerElement = document.getElementsByTagName('perspective-viewer')[0] as unknown as PerspectiveViewerElement; + const elem = document.getElementsByTagName('perspective-viewer')[0] as unknown as PerspectiveViewerElement; const schema = { stock: 'string', @@ -47,8 +47,14 @@ class Graph extends Component { if (this.table) { // Load the `table` in the `` DOM reference. - // Add more Perspective configurations here. elem.load(this.table); + elem.setAttribute("view", "y_line"); + elem.setAttribute("column-pivots", '["stock"]'); + elem.setAttribute("row-pivots", '["timestamp"]'); + elem.setAttribute("columns", '["top_ask_price"]'); + elem.setAttribute("aggregates", + '{"stock":"distinct count", "top_ask_price":"avg", "top_bid_price":"avg", "timestamp":"distinct count"}' + ); } } From 132817486d0fd1f21c9fce4ccda0065c90fcc432 Mon Sep 17 00:00:00 2001 From: Tunir Wabhitkar Date: Thu, 29 Aug 2024 00:47:40 +0530 Subject: [PATCH 3/3] Update DataStreamer.ts --- src/DataStreamer.ts | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/src/DataStreamer.ts b/src/DataStreamer.ts index 78583cb56d7..5cb188e6c78 100644 --- a/src/DataStreamer.ts +++ b/src/DataStreamer.ts @@ -1,20 +1,21 @@ export interface Order { - price: Number, - size: Number, + price: number; // Change from Number to number for consistency + size: number; // Change from Number to number for consistency } + /** * The datafeed server returns an array of ServerRespond with 2 stocks. * We do not have to manipulate the ServerRespond for the purpose of this task. */ export interface ServerRespond { - stock: string, - top_bid: Order, - top_ask: Order, - timestamp: Date, + stock: string; + top_bid: Order; + top_ask: Order; + timestamp: Date; } class DataStreamer { - // The url where datafeed server is listening + // The URL where datafeed server is listening static API_URL: string = 'http://localhost:8080/query?id=1'; /** @@ -23,18 +24,30 @@ class DataStreamer { */ static getData(callback: (data: ServerRespond[]) => void): void { const request = new XMLHttpRequest(); - request.open('GET', DataStreamer.API_URL, false); + request.open('GET', DataStreamer.API_URL, true); // Use asynchronous request request.onload = () => { if (request.status === 200) { - callback(JSON.parse(request.responseText)); + try { + const data = JSON.parse(request.responseText); + callback(data); + } catch (e) { + console.error('Error parsing response data:', e); + alert('Failed to parse server response.'); + } } else { - alert ('Request failed'); + console.error('Request failed with status:', request.status); + alert('Request failed with status ' + request.status); } - } + }; + + request.onerror = () => { + console.error('Network error occurred'); + alert('Network error occurred. Please try again later.'); + }; request.send(); } } -export default DataStreamer; \ No newline at end of file +export default DataStreamer;