hierarchical-estimates-visu.../packages/webpage-refactor/components/graph/graph.js

221 lines
5.8 KiB
JavaScript
Raw Normal View History

2022-06-18 03:20:44 +00:00
import React, { useEffect, useState, useRef } from "react";
2022-06-18 18:18:15 +00:00
import colormap from "colormap";
2022-06-18 03:20:44 +00:00
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";
2022-06-18 18:18:15 +00:00
// import avsdf from "cytoscape-avsdf";
2022-06-18 03:20:44 +00:00
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 =
2022-06-18 18:18:15 +00:00
sparklineConcat + " →" + sparkline.sparkline.replace("▁▁▁▁▁▁▁▁▁▁▁▁▁", "");
2022-06-18 03:20:44 +00:00
//alert("▁▁▁▁▁▁▁▁▁▁▁");
}
if (num.asNum) {
sparklineConcat =
sparklineConcat + " ⇾ " + truncateValueForDisplay(num.num);
//alert("▁▁▁▁▁▁▁▁▁▁▁");
}
return squiggleString + sparklineConcat; //sparkline;
};
2022-06-18 18:18:15 +00:00
const getColors = (n) => {
let colors = colormap({
colormap: "viridis",
nshades: n,
format: "hex",
alpha: 1,
});
return colors;
};
const cutOffLongNames = (string) => {
let maxLength = 40;
let result;
if (string.length < maxLength) {
result = string;
} else {
result = string.slice(0, maxLength - 4);
result = result + "...";
}
return result;
};
export function Graph({
listOfElements,
links,
isListOrdered,
mergeSortOrder,
}) {
2022-06-18 23:10:27 +00:00
const containerRef = useRef("hello-world");
2022-06-18 18:18:15 +00:00
const [visibility, setVisibility] = useState(""); /// useState("invisible");
const callEffect = async ({
listOfElements,
links,
isListOrdered,
mergeSortOrder,
}) => {
//setVisibility("invisible");
let layoutName = "circle"; //
// cytoscape.use(circle); // spread, circle,
let listOfElementsForGraph = isListOrdered
? mergeSortOrder
: listOfElements;
2022-06-18 03:20:44 +00:00
2022-06-18 18:18:15 +00:00
let colors = new Array(listOfElements.length);
if (isListOrdered) {
colors = getColors(listOfElements.length);
}
2022-06-18 03:20:44 +00:00
2022-06-18 18:18:15 +00:00
let nodeElements = listOfElements.map((element, i) => {
return {
data: {
id: cutOffLongNames(element.name),
color: colors[i] || "darkgreen",
2022-06-18 18:56:37 +00:00
labelColor:
isListOrdered && i >= listOfElementsForGraph.length - 2
? "black"
: "white",
2022-06-18 18:18:15 +00:00
},
};
2022-06-18 03:20:44 +00:00
});
let linkElements = await Promise.all(
links.map(async (link, i) => {
return {
data: {
id: `link-${i}`,
2022-06-18 18:18:15 +00:00
source: cutOffLongNames(link.source),
target: cutOffLongNames(link.target),
2022-06-18 03:20:44 +00:00
label: await getEdgeLabel(link.squiggleString),
},
};
})
);
2022-06-18 18:18:15 +00:00
const cytoscapeStylesheet = [
{
selector: "node",
style: {
2022-06-18 18:56:37 +00:00
padding: "30px",
2022-06-18 18:18:15 +00:00
shape: "round-rectangle",
content: "data(id)",
"background-color": "data(color)",
"text-wrap": "wrap",
//"text-overflow-wrap": "anywhere",
"text-max-width": 70,
"z-index": 1,
2022-06-18 03:20:44 +00:00
},
2022-06-18 18:18:15 +00:00
},
{
selector: "node[id]",
style: {
label: "data(id)",
2022-06-18 18:56:37 +00:00
"font-size": "13",
color: "data(labelColor)",
2022-06-18 18:18:15 +00:00
"text-halign": "center",
"text-valign": "center",
"z-index": 1,
2022-06-18 03:20:44 +00:00
},
2022-06-18 18:18:15 +00:00
},
{
selector: "edge",
style: {
"curve-style": "unbundled-bezier",
"target-arrow-shape": "vee",
width: 1.5,
"target-arrow-color": "green",
"arrow-scale": 3,
"target-arrow-fill": "filled",
"text-rotation": "autorotate",
"z-index": 0,
},
},
{
selector: "edge[label]",
style: {
label: "data(label)",
"font-size": "12",
"text-background-color": "#f9f9f9",
"text-background-opacity": 1,
"text-background-padding": "4px",
"text-border-color": "black",
"text-border-style": "solid",
"text-border-width": 0.5,
"text-border-opacity": 1,
"z-index": 3,
// "text-rotation": "autorotate"
},
},
];
const config = {
container: containerRef.current,
style: cytoscapeStylesheet,
2022-06-18 03:20:44 +00:00
elements: [
/* Dummy data:
{ data: { id: "n1" } },
{ data: { id: "n2" } },
{ data: { id: "e1", source: "n1", target: "n2" } },
Real data:*/
...nodeElements,
...linkElements,
],
layout: {
2022-06-18 18:18:15 +00:00
name: layoutName, // circle, grid, dagre
2022-06-18 03:20:44 +00:00
minDist: 10,
//prelayout: false,
2022-06-18 03:38:06 +00:00
// animate: false, // whether to transition the node positions
// animationDuration: 250, // duration of animation in ms if enabled
2022-06-18 03:20:44 +00:00
},
userZoomingEnabled: false,
userPanningEnabled: false,
};
cytoscape(config);
2022-06-18 18:18:15 +00:00
// setTimeout(() => setVisibility(""), 700);
2022-06-18 03:20:44 +00:00
};
useEffect(async () => {
2022-06-18 18:18:15 +00:00
await callEffect({ listOfElements, links, isListOrdered, mergeSortOrder });
2022-06-18 03:20:44 +00:00
// console.log(JSON.stringify(config, null, 10));
2022-06-18 18:56:37 +00:00
}, [listOfElements, links, isListOrdered]);
2022-06-18 03:20:44 +00:00
return (
<div>
2022-06-18 03:38:06 +00:00
<div className={visibility}>
2022-06-18 18:18:15 +00:00
<div ref={containerRef} style={{ height: "900px", width: "1000px" }} />
2022-06-18 03:38:06 +00:00
</div>
2022-06-18 03:20:44 +00:00
<button
className={effectButtonStyle}
2022-06-18 18:18:15 +00:00
onClick={() =>
callEffect({ listOfElements, links, isListOrdered, mergeSortOrder })
}
2022-06-18 03:20:44 +00:00
>
{"Redraw graph"}
</button>
</div>
);
2022-06-17 22:48:11 +00:00
}