http-rewrite #1
@@ -6,9 +6,8 @@
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1">
 | 
			
		||||
    <script src="/static/d3.v7.min.js"></script>
 | 
			
		||||
  </head>
 | 
			
		||||
  <body style="background: #EEE">
 | 
			
		||||
  <body style="background: #eee">
 | 
			
		||||
    <div id="container"></div>
 | 
			
		||||
    <script src="/static/index.js"></script>
 | 
			
		||||
  </body>
 | 
			
		||||
</html>
 | 
			
		||||
</html>
 | 
			
		||||
 
 | 
			
		||||
@@ -31,116 +31,117 @@ const drag = (simulation) => {
 | 
			
		||||
    .on("end", dragended);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const drawChart = (data) => {
 | 
			
		||||
  // Specify the dimensions of the chart.
 | 
			
		||||
  const width = 1600;
 | 
			
		||||
  const height = 1200;
 | 
			
		||||
 | 
			
		||||
  // Specify the color scale.
 | 
			
		||||
  const color = d3.scaleOrdinal(d3.schemeCategory10);
 | 
			
		||||
 | 
			
		||||
  // The force simulation mutates links and nodes, so create a copy
 | 
			
		||||
  // so that re-evaluating this cell produces the same result.
 | 
			
		||||
  const links = data.links.map((d) => ({ ...d }));
 | 
			
		||||
  const nodes = data.nodes.map((d) => ({ ...d }));
 | 
			
		||||
 | 
			
		||||
  // Create a simulation with several forces.
 | 
			
		||||
  const simulation = d3
 | 
			
		||||
    .forceSimulation(nodes)
 | 
			
		||||
    .force(
 | 
			
		||||
      "link",
 | 
			
		||||
      d3.forceLink(links).id((d) => d.id),
 | 
			
		||||
    )
 | 
			
		||||
    .force("charge", d3.forceManyBody())
 | 
			
		||||
    .force("x", d3.forceX())
 | 
			
		||||
    .force("y", d3.forceY());
 | 
			
		||||
 | 
			
		||||
  // Create the SVG container.
 | 
			
		||||
  const svg = d3
 | 
			
		||||
    .create("svg")
 | 
			
		||||
    .attr("width", width)
 | 
			
		||||
    .attr("height", height)
 | 
			
		||||
    .attr("viewBox", [-width / 2, -height / 2, width, height])
 | 
			
		||||
    .attr("style", "max-width: 100%; height: auto;");
 | 
			
		||||
 | 
			
		||||
  // Add a line for each link, and a circle for each node.
 | 
			
		||||
  const link = svg
 | 
			
		||||
    .append("g")
 | 
			
		||||
    .attr("stroke", "#999")
 | 
			
		||||
    .attr("stroke-opacity", 0.6)
 | 
			
		||||
    .selectAll("line")
 | 
			
		||||
    .data(links)
 | 
			
		||||
    .join("line")
 | 
			
		||||
    .attr("stroke-width", 1); // (d) => Math.sqrt(d.value));
 | 
			
		||||
 | 
			
		||||
  const node = svg
 | 
			
		||||
    .append("g")
 | 
			
		||||
    .attr("stroke", "#fff")
 | 
			
		||||
    .attr("stroke-width", 1.5)
 | 
			
		||||
    .selectAll("circle")
 | 
			
		||||
    .data(nodes)
 | 
			
		||||
    .join("circle")
 | 
			
		||||
    .attr("r", 5)
 | 
			
		||||
    .attr("fill", (d) => color(d.group));
 | 
			
		||||
 | 
			
		||||
  node.append("title").text((d) => d.id);
 | 
			
		||||
 | 
			
		||||
  // Add a drag behavior.
 | 
			
		||||
  node.call(
 | 
			
		||||
    d3.drag().on("start", dragstarted).on("drag", dragged).on("end", dragended),
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  // Set the position attributes of links and nodes each time the simulation ticks.
 | 
			
		||||
  simulation.on("tick", () => {
 | 
			
		||||
    link
 | 
			
		||||
      .attr("x1", (d) => d.source.x)
 | 
			
		||||
      .attr("y1", (d) => d.source.y)
 | 
			
		||||
      .attr("x2", (d) => d.target.x)
 | 
			
		||||
      .attr("y2", (d) => d.target.y);
 | 
			
		||||
 | 
			
		||||
    node.attr("cx", (d) => d.x).attr("cy", (d) => d.y);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // Reheat the simulation when drag starts, and fix the subject position.
 | 
			
		||||
  function dragstarted(event) {
 | 
			
		||||
    if (!event.active) simulation.alphaTarget(0.3).restart();
 | 
			
		||||
    event.subject.fx = event.subject.x;
 | 
			
		||||
    event.subject.fy = event.subject.y;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Update the subject (dragged node) position during drag.
 | 
			
		||||
  function dragged(event) {
 | 
			
		||||
    event.subject.fx = event.x;
 | 
			
		||||
    event.subject.fy = event.y;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Restore the target alpha so the simulation cools after dragging ends.
 | 
			
		||||
  // Unfix the subject position now that it’s no longer being dragged.
 | 
			
		||||
  function dragended(event) {
 | 
			
		||||
    if (!event.active) simulation.alphaTarget(0);
 | 
			
		||||
    event.subject.fx = null;
 | 
			
		||||
    event.subject.fy = null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // When this cell is re-run, stop the previous simulation. (This doesn’t
 | 
			
		||||
  // really matter since the target alpha is zero and the simulation will
 | 
			
		||||
  // stop naturally, but it’s a good practice.)
 | 
			
		||||
  // invalidation.then(() => simulation.stop());
 | 
			
		||||
 | 
			
		||||
  return svg.node();
 | 
			
		||||
};
 | 
			
		||||
// const drawChart = (data) => {
 | 
			
		||||
//   // Specify the dimensions of the chart.
 | 
			
		||||
//   const width = 1600;
 | 
			
		||||
//   const height = 1200;
 | 
			
		||||
//
 | 
			
		||||
//   // Specify the color scale.
 | 
			
		||||
//   const color = d3.scaleOrdinal(d3.schemeCategory10);
 | 
			
		||||
//
 | 
			
		||||
//   // The force simulation mutates links and nodes, so create a copy
 | 
			
		||||
//   // so that re-evaluating this cell produces the same result.
 | 
			
		||||
//   const links = data.links.map((d) => ({ ...d }));
 | 
			
		||||
//   const nodes = data.nodes.map((d) => ({ ...d }));
 | 
			
		||||
//
 | 
			
		||||
//   // Create a simulation with several forces.
 | 
			
		||||
//   const simulation = d3
 | 
			
		||||
//     .forceSimulation(nodes)
 | 
			
		||||
//     .force(
 | 
			
		||||
//       "link",
 | 
			
		||||
//       d3.forceLink(links).id((d) => d.id),
 | 
			
		||||
//     )
 | 
			
		||||
//     .force("charge", d3.forceManyBody())
 | 
			
		||||
//     .force("x", d3.forceX())
 | 
			
		||||
//     .force("y", d3.forceY());
 | 
			
		||||
//
 | 
			
		||||
//   // Create the SVG container.
 | 
			
		||||
//   const svg = d3
 | 
			
		||||
//     .create("svg")
 | 
			
		||||
//     .attr("width", width)
 | 
			
		||||
//     .attr("height", height)
 | 
			
		||||
//     .attr("viewBox", [-width / 2, -height / 2, width, height])
 | 
			
		||||
//     .attr("style", "max-width: 100%; height: auto;");
 | 
			
		||||
//
 | 
			
		||||
//   // Add a line for each link, and a circle for each node.
 | 
			
		||||
//   const link = svg
 | 
			
		||||
//     .append("g")
 | 
			
		||||
//     .attr("stroke", "#999")
 | 
			
		||||
//     .attr("stroke-opacity", 0.6)
 | 
			
		||||
//     .selectAll("line")
 | 
			
		||||
//     .data(links)
 | 
			
		||||
//     .join("line")
 | 
			
		||||
//     .attr("stroke-width", 1); // (d) => Math.sqrt(d.value));
 | 
			
		||||
//
 | 
			
		||||
//   const node = svg
 | 
			
		||||
//     .append("g")
 | 
			
		||||
//     .attr("stroke", "#fff")
 | 
			
		||||
//     .attr("stroke-width", 1.5)
 | 
			
		||||
//     .selectAll("circle")
 | 
			
		||||
//     .data(nodes)
 | 
			
		||||
//     .join("circle")
 | 
			
		||||
//     .attr("r", 5)
 | 
			
		||||
//     .attr("fill", (d) => color(d.group));
 | 
			
		||||
//
 | 
			
		||||
//   node.append("title").text((d) => d.id);
 | 
			
		||||
//
 | 
			
		||||
//   // Add a drag behavior.
 | 
			
		||||
//   node.call(
 | 
			
		||||
//     d3.drag().on("start", dragstarted).on("drag", dragged).on("end", dragended),
 | 
			
		||||
//   );
 | 
			
		||||
//
 | 
			
		||||
//   // Set the position attributes of links and nodes each time the simulation ticks.
 | 
			
		||||
//   simulation.on("tick", () => {
 | 
			
		||||
//     link
 | 
			
		||||
//       .attr("x1", (d) => d.source.x)
 | 
			
		||||
//       .attr("y1", (d) => d.source.y)
 | 
			
		||||
//       .attr("x2", (d) => d.target.x)
 | 
			
		||||
//       .attr("y2", (d) => d.target.y);
 | 
			
		||||
//
 | 
			
		||||
//     node.attr("cx", (d) => d.x).attr("cy", (d) => d.y);
 | 
			
		||||
//   });
 | 
			
		||||
//
 | 
			
		||||
//   // Reheat the simulation when drag starts, and fix the subject position.
 | 
			
		||||
//   function dragstarted(event) {
 | 
			
		||||
//     if (!event.active) simulation.alphaTarget(0.3).restart();
 | 
			
		||||
//     event.subject.fx = event.subject.x;
 | 
			
		||||
//     event.subject.fy = event.subject.y;
 | 
			
		||||
//   }
 | 
			
		||||
//
 | 
			
		||||
//   // Update the subject (dragged node) position during drag.
 | 
			
		||||
//   function dragged(event) {
 | 
			
		||||
//     event.subject.fx = event.x;
 | 
			
		||||
//     event.subject.fy = event.y;
 | 
			
		||||
//   }
 | 
			
		||||
//
 | 
			
		||||
//   // Restore the target alpha so the simulation cools after dragging ends.
 | 
			
		||||
//   // Unfix the subject position now that it’s no longer being dragged.
 | 
			
		||||
//   function dragended(event) {
 | 
			
		||||
//     if (!event.active) simulation.alphaTarget(0);
 | 
			
		||||
//     event.subject.fx = null;
 | 
			
		||||
//     event.subject.fy = null;
 | 
			
		||||
//   }
 | 
			
		||||
//
 | 
			
		||||
//   // When this cell is re-run, stop the previous simulation. (This doesn’t
 | 
			
		||||
//   // really matter since the target alpha is zero and the simulation will
 | 
			
		||||
//   // stop naturally, but it’s a good practice.)
 | 
			
		||||
//   // invalidation.then(() => simulation.stop());
 | 
			
		||||
//
 | 
			
		||||
//   return svg.node();
 | 
			
		||||
// };
 | 
			
		||||
 | 
			
		||||
const drawChart2 = (data) => {
 | 
			
		||||
  const width = 1600;
 | 
			
		||||
  const height = 1200;
 | 
			
		||||
  const types = Array.from(new Set(data.map((d) => d.type)));
 | 
			
		||||
  const width = window.visualViewport.width;
 | 
			
		||||
  const height = window.visualViewport.height - 10;
 | 
			
		||||
 | 
			
		||||
  const colors = Array.from(new Set(data.map((d) => d.traceId)));
 | 
			
		||||
  const nodes = Array.from(
 | 
			
		||||
    new Set(data.flatMap((l) => [l.source, l.target])),
 | 
			
		||||
    (id) => ({ id }),
 | 
			
		||||
  );
 | 
			
		||||
  const links = data.map((d) => Object.create(d));
 | 
			
		||||
 | 
			
		||||
  const color = d3.scaleOrdinal(types, d3.schemeCategory10);
 | 
			
		||||
  const color = d3.scaleOrdinal(colors, d3.schemeCategory10);
 | 
			
		||||
 | 
			
		||||
  const simulation = d3
 | 
			
		||||
    .forceSimulation(nodes)
 | 
			
		||||
@@ -152,18 +153,19 @@ const drawChart2 = (data) => {
 | 
			
		||||
    .force("x", d3.forceX())
 | 
			
		||||
    .force("y", d3.forceY());
 | 
			
		||||
 | 
			
		||||
  // Canvas settings
 | 
			
		||||
  const svg = d3
 | 
			
		||||
    .create("svg")
 | 
			
		||||
    .attr("viewBox", [-width / 2, -height / 2, width, height])
 | 
			
		||||
    .attr("width", width)
 | 
			
		||||
    .attr("height", height)
 | 
			
		||||
    .attr("style", "max-width: 100%; height: auto; font: 12px sans-serif;");
 | 
			
		||||
    .attr("style", "max-width: 100%; height: auto; font: 14px monospace;");
 | 
			
		||||
 | 
			
		||||
  // Per-type markers, as they don't inherit styles.
 | 
			
		||||
  svg
 | 
			
		||||
    .append("defs")
 | 
			
		||||
    .selectAll("marker")
 | 
			
		||||
    .data(types)
 | 
			
		||||
    .data(colors)
 | 
			
		||||
    .join("marker")
 | 
			
		||||
    .attr("id", (d) => `arrow-${d}`)
 | 
			
		||||
    .attr("viewBox", "0 -5 10 10")
 | 
			
		||||
@@ -183,8 +185,11 @@ const drawChart2 = (data) => {
 | 
			
		||||
    .selectAll("path")
 | 
			
		||||
    .data(links)
 | 
			
		||||
    .join("path")
 | 
			
		||||
    .attr("stroke", (d) => color(d.type))
 | 
			
		||||
    .attr("marker-end", (d) => `url(${new URL(`#arrow-${d.type}`, location)})`);
 | 
			
		||||
    .attr("stroke", (d) => color(d.traceId))
 | 
			
		||||
    .attr(
 | 
			
		||||
      "marker-end",
 | 
			
		||||
      (d) => `url(${new URL(`#arrow-${d.traceId}`, location)})`,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
  const node = svg
 | 
			
		||||
    .append("g")
 | 
			
		||||
@@ -223,6 +228,17 @@ const drawChart2 = (data) => {
 | 
			
		||||
  return Object.assign(svg.node(), { scales: { color } });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const getId = (hop, prevId, trace) => {
 | 
			
		||||
  if (prevId === null) {
 | 
			
		||||
    return trace.origin;
 | 
			
		||||
  }
 | 
			
		||||
  if (hop.name === "*") {
 | 
			
		||||
    return `${trace.id}-${hop.number}-*`;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return hop.ip;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const parseNodesAndLinks = (traces) => {
 | 
			
		||||
  const result = {
 | 
			
		||||
    nodes: [],
 | 
			
		||||
@@ -232,24 +248,12 @@ const parseNodesAndLinks = (traces) => {
 | 
			
		||||
  traces.forEach((trace) => {
 | 
			
		||||
    let prevId = null;
 | 
			
		||||
 | 
			
		||||
    const getId = (hop) => {
 | 
			
		||||
      if (prevId === null) {
 | 
			
		||||
        return trace.origin;
 | 
			
		||||
      }
 | 
			
		||||
      if (hop.name === "*") {
 | 
			
		||||
        return `${trace.id}-${hop.number}-*`;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return hop.ip;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    trace.hops.forEach((hop) => {
 | 
			
		||||
      const id = getId(hop);
 | 
			
		||||
      const id = getId(hop, prevId, trace);
 | 
			
		||||
 | 
			
		||||
      // New node
 | 
			
		||||
      result.nodes.push({
 | 
			
		||||
        id: id,
 | 
			
		||||
        group: trace.origin,
 | 
			
		||||
        radius: 8,
 | 
			
		||||
        value: hop.name || "name?",
 | 
			
		||||
        origin: trace.origin,
 | 
			
		||||
@@ -260,8 +264,8 @@ const parseNodesAndLinks = (traces) => {
 | 
			
		||||
        result.links.push({
 | 
			
		||||
          source: prevId,
 | 
			
		||||
          target: id,
 | 
			
		||||
          type: trace.origin,
 | 
			
		||||
          group: trace.origin,
 | 
			
		||||
          traceId: trace.id,
 | 
			
		||||
          origin: trace.origin,
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@@ -271,9 +275,9 @@ const parseNodesAndLinks = (traces) => {
 | 
			
		||||
    // Last "destination" node
 | 
			
		||||
    result.nodes.push({
 | 
			
		||||
      id: trace.id,
 | 
			
		||||
      group: trace.origin,
 | 
			
		||||
      radius: 8,
 | 
			
		||||
      value: trace.target,
 | 
			
		||||
      origin: trace.origin,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (prevId) {
 | 
			
		||||
@@ -281,8 +285,8 @@ const parseNodesAndLinks = (traces) => {
 | 
			
		||||
      result.links.push({
 | 
			
		||||
        source: prevId,
 | 
			
		||||
        target: trace.target,
 | 
			
		||||
        type: trace.origin,
 | 
			
		||||
        group: trace.origin,
 | 
			
		||||
        traceId: trace.id,
 | 
			
		||||
        origin: trace.origin,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user