/ node / bft / examples / assets / index.html
index.html
  1  <!DOCTYPE html>
  2  <html>
  3  <head>
  4      <style>
  5          html,
  6          body {
  7              width: 100%;
  8              height: 100%;
  9              margin: 0;
 10              padding: 0;
 11              overflow: hidden;
 12          }
 13      </style>
 14  </head>
 15  <body>
 16  <script src="https://d3js.org/d3.v6.min.js"></script>
 17  <script>
 18      // Size of the SVG canvas
 19      const width = window.innerWidth;
 20      const height = window.innerHeight / 2;
 21      const radius = 5; // radius of nodes
 22      const columns = 10; // Updated value to show the number of rounds
 23      const rows = 4; // Update value to show the number of nodes
 24      const cellWidth = width / columns;
 25      const cellHeight = height / rows;
 26  
 27      // Create the SVG canvas
 28      const svg = d3.select("body")
 29          .append("svg")
 30          .attr("width", width)
 31          .attr("height", height);
 32  
 33      function exampleResponse() {
 34          const nodes = [];
 35          for (let column = 0; column < 10; column++) { // loop for rounds
 36              for (let row = 0; row < 4; row++) { // loop for nodes
 37                  nodes.push({
 38                      "id": `node${row}-${column}`,
 39                      "column": column,
 40                      "row": row
 41                  });
 42              }
 43          }
 44  
 45          const links = [];
 46          for (let column = 1; column < 10; column++) {
 47              for (let row = 0; row < 4; row++) {
 48                  // choose randomly 3 or 4 nodes from the previous round
 49                  const prevNodes = [...Array(4).keys()];
 50                  const numLinks = Math.floor(Math.random() * 2) + 3; // random number either 3 or 4
 51                  for (let i = 0; i < numLinks; i++) {
 52                      const randIndex = Math.floor(Math.random() * prevNodes.length);
 53                      const targetRow = prevNodes.splice(randIndex, 1)[0];
 54                      links.push({
 55                          "source": `node${row}-${column}`,
 56                          "target": `node${targetRow}-${column - 1}`,
 57                          "color": "black"
 58                      });
 59                  }
 60              }
 61          }
 62  
 63          return {
 64              "nodes": nodes,
 65              "links": links
 66          };
 67      }
 68  
 69      // Fetch data from the server
 70      async function fetchData() {
 71          // const response = await d3.json("http://127.0.0.1:3000/dag");
 72          // const response = {
 73          //     "nodes": [
 74          //         {"id": "node0-0", "column": 0, "row": 0},
 75          //         {"id": "node1-0", "column": 0, "row": 1},
 76          //         {"id": "node2-0", "column": 0, "row": 2},
 77          //         {"id": "node3-0", "column": 0, "row": 3},
 78          //         {"id": "node0-1", "column": 1, "row": 0},
 79          //         {"id": "node1-1", "column": 1, "row": 1},
 80          //         {"id": "node2-1", "column": 1, "row": 2},
 81          //         {"id": "node3-1", "column": 1, "row": 3},
 82          //         // More nodes...
 83          //     ],
 84          //     "links": [
 85          //         {"source": "node0-0", "target": "node0-1", "color": "black"},
 86          //         {"source": "node0-0", "target": "node1-1", "color": "black"},
 87          //         {"source": "node0-0", "target": "node3-1", "color": "black"},
 88          //         {"source": "node1-0", "target": "node0-1", "color": "black"},
 89          //         {"source": "node1-0", "target": "node1-1", "color": "black"},
 90          //         {"source": "node1-0", "target": "node2-1", "color": "black"},
 91          //         {"source": "node2-0", "target": "node1-1", "color": "black"},
 92          //         {"source": "node2-0", "target": "node2-1", "color": "black"},
 93          //         {"source": "node3-0", "target": "node2-1", "color": "black"},
 94          //         {"source": "node3-0", "target": "node3-1", "color": "black"},
 95          //         // More links...
 96          //     ]
 97          // };
 98          const response = exampleResponse();
 99  
100          // Map node ids to node objects for easier lookup
101          const nodeById = new Map(response.nodes.map(node => [node.id, node]));
102  
103          // Replace source and target ids in links with the actual objects
104          response.links.forEach(link => {
105              link.source = nodeById.get(link.source);
106              link.target = nodeById.get(link.target);
107          });
108  
109          const nodes = response.nodes;
110          const links = response.links;
111  
112          updateGraph(nodes, links);
113      }
114  
115      function updateGraph(nodes, links) {
116          // Update nodes
117          const node = svg.selectAll("circle")
118              .data(nodes, d => d.id)
119              .join("circle")
120              .attr("r", radius)
121              .attr("cx", d => d.column * cellWidth + cellWidth / 2) // position nodes in the middle of their cell
122              .attr("cy", d => d.row * cellHeight + cellHeight / 2);
123  
124          // Update links
125          svg.selectAll("line")
126              .data(links, d => `${d.source.id}-${d.target.id}`)
127              .join("line")
128              .style("stroke", d => d.color)
129              .attr("x1", d => d.source.column * cellWidth + cellWidth / 2)
130              .attr("y1", d => d.source.row * cellHeight + cellHeight / 2)
131              .attr("x2", d => d.target.column * cellWidth + cellWidth / 2)
132              .attr("y2", d => d.target.row * cellHeight + cellHeight / 2);
133  
134          // Update row labels
135          svg.selectAll("rowLabel")
136              .data([...new Set(nodes.map(n => n.row))]) // unique rows
137              .join("text")
138              .attr("x", 0)
139              .attr("y", d => d * cellHeight + cellHeight / 2)
140              .text(d => `Node ${d}`);
141  
142          // Update column labels
143          svg.selectAll("columnLabel")
144              .data([...new Set(nodes.map(n => n.column))]) // unique columns
145              .join("text")
146              .attr("x", d => d * cellWidth + cellWidth / 2)
147              .attr("y", 20) // set y coordinate so that labels are on top
148              .style("text-anchor", "middle") // centering the text
149              .text(d => `Round ${d}`);
150      }
151  
152      // Fetch new data every second
153      d3.interval(fetchData, 1000);
154  
155      // Initial fetch
156      fetchData();
157  </script>
158  </body>
159  </html>