141 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			141 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
import React, { useEffect, useState, useRef } from "react";
 | 
						|
import cytoscape from "cytoscape";
 | 
						|
import spread from "cytoscape-spread";
 | 
						|
import {
 | 
						|
  resolveToNumIfPossible,
 | 
						|
  getSquiggleSparkline,
 | 
						|
} from "../../lib/squiggle.js";
 | 
						|
import { truncateValueForDisplay } from "../../lib/truncateNums.js";
 | 
						|
 | 
						|
// import dagre from "cytoscape-dagre";
 | 
						|
// import cola from "cytoscape-cola";
 | 
						|
// import fcose from "cytoscape-fcose";
 | 
						|
import avsdf from "cytoscape-avsdf";
 | 
						|
 | 
						|
const effectButtonStyle =
 | 
						|
  "bg-transparent m-2 hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5";
 | 
						|
 | 
						|
const getEdgeLabel = async (squiggleString) => {
 | 
						|
  let sparkline = await getSquiggleSparkline(squiggleString);
 | 
						|
  let num = await resolveToNumIfPossible(squiggleString);
 | 
						|
 | 
						|
  let sparklineConcat = "";
 | 
						|
  if (false && sparkline.success) {
 | 
						|
    console.log(sparkline);
 | 
						|
 | 
						|
    sparklineConcat =
 | 
						|
      sparklineConcat +
 | 
						|
      " →" +
 | 
						|
      sparkline.sparkline.replace("▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", "");
 | 
						|
    //alert("▁▁▁▁▁▁▁▁▁▁▁");
 | 
						|
  }
 | 
						|
  if (num.asNum) {
 | 
						|
    sparklineConcat =
 | 
						|
      sparklineConcat + " ⇾ " + truncateValueForDisplay(num.num);
 | 
						|
    //alert("▁▁▁▁▁▁▁▁▁▁▁");
 | 
						|
  }
 | 
						|
 | 
						|
  return squiggleString + sparklineConcat; //sparkline;
 | 
						|
};
 | 
						|
 | 
						|
export function Graph({ listOfElements, links }) {
 | 
						|
  const containerRef = useRef();
 | 
						|
  const [visibility, setVisibility] = useState("invisible");
 | 
						|
 | 
						|
  const callEffect = async (listOfElements, links) => {
 | 
						|
    setVisibility("invisible");
 | 
						|
    cytoscape.use(spread); // spread
 | 
						|
 | 
						|
    let nodeElements = listOfElements.map((element) => {
 | 
						|
      return { data: { id: element.name } };
 | 
						|
    });
 | 
						|
    let linkElements = await Promise.all(
 | 
						|
      links.map(async (link, i) => {
 | 
						|
        return {
 | 
						|
          data: {
 | 
						|
            id: `link-${i}`,
 | 
						|
            source: link.source,
 | 
						|
            target: link.target,
 | 
						|
            label: await getEdgeLabel(link.squiggleString),
 | 
						|
          },
 | 
						|
        };
 | 
						|
      })
 | 
						|
    );
 | 
						|
    const config = {
 | 
						|
      container: containerRef.current,
 | 
						|
      style: [
 | 
						|
        {
 | 
						|
          selector: "node",
 | 
						|
          style: {
 | 
						|
            content: "data(id)",
 | 
						|
            "background-color": "darkgreen",
 | 
						|
            "text-wrap": "wrap",
 | 
						|
            "text-max-width": 200,
 | 
						|
            "source-text-offset": 20,
 | 
						|
            //"text-valign": "bottom",
 | 
						|
            "text-justification": "auto",
 | 
						|
          },
 | 
						|
          padding: 2,
 | 
						|
        },
 | 
						|
        {
 | 
						|
          selector: "edge",
 | 
						|
          style: {
 | 
						|
            label: "data(label)", // maps to data.label
 | 
						|
            labelColor: "blue",
 | 
						|
            "curve-style": "unbundled-bezier",
 | 
						|
            "target-arrow-color": "green",
 | 
						|
            "arrow-scale": 3,
 | 
						|
            "target-arrow-fill": "filled",
 | 
						|
            "font-size": 15,
 | 
						|
            "line-color": "green",
 | 
						|
            "target-arrow-shape": "vee",
 | 
						|
            "text-rotation": "autorotate",
 | 
						|
            "text-margin-x": +25,
 | 
						|
            "text-margin-y": +25,
 | 
						|
            padding: 5,
 | 
						|
          },
 | 
						|
        },
 | 
						|
      ],
 | 
						|
      elements: [
 | 
						|
        /* Dummy data:
 | 
						|
        { data: { id: "n1" } },
 | 
						|
        { data: { id: "n2" } },
 | 
						|
        { data: { id: "e1", source: "n1", target: "n2" } },
 | 
						|
        
 | 
						|
        Real data:*/
 | 
						|
        ...nodeElements,
 | 
						|
        ...linkElements,
 | 
						|
      ],
 | 
						|
      layout: {
 | 
						|
        name: "spread", // circle, grid, dagre
 | 
						|
        minDist: 10,
 | 
						|
        //prelayout: false,
 | 
						|
        // animate: false, // whether to transition the node positions
 | 
						|
        // animationDuration: 250, // duration of animation in ms if enabled
 | 
						|
      },
 | 
						|
      userZoomingEnabled: false,
 | 
						|
      userPanningEnabled: false,
 | 
						|
    };
 | 
						|
    cytoscape(config);
 | 
						|
    setTimeout(() => setVisibility(""), 700);
 | 
						|
  };
 | 
						|
  useEffect(async () => {
 | 
						|
    await callEffect(listOfElements, links);
 | 
						|
    // console.log(JSON.stringify(config, null, 10));
 | 
						|
  }, [listOfElements, links]);
 | 
						|
 | 
						|
  return (
 | 
						|
    <div>
 | 
						|
      <div className={visibility}>
 | 
						|
        <div ref={containerRef} style={{ height: "700px", width: "1000px" }} />
 | 
						|
      </div>
 | 
						|
      <button
 | 
						|
        className={effectButtonStyle}
 | 
						|
        onClick={() => callEffect(listOfElements, links)}
 | 
						|
      >
 | 
						|
        {"Redraw graph"}
 | 
						|
      </button>
 | 
						|
    </div>
 | 
						|
  );
 | 
						|
}
 |