Files
lucia-frontend/src/module/cytoscapeMapTrace.js
2026-03-09 20:53:25 +08:00

117 lines
3.3 KiB
JavaScript

// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// imacat.yang@dsp.im (imacat), 2023/9/23
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
/**
* @module cytoscapeMapTrace Cytoscape.js process map rendering for
* individual trace visualization.
*/
import cytoscape from "cytoscape";
import dagre from "cytoscape-dagre";
import tippy from "tippy.js";
import "tippy.js/dist/tippy.css";
import { createTooltipContent } from "@/module/tooltipContent.js";
cytoscape.use(dagre);
/**
* Creates a Cytoscape.js instance for rendering a single trace's
* process map with left-to-right dagre layout and tooltips.
*
* @param {Array<Object>} nodes - Array of node data objects with
* backgroundColor, bordercolor, height, id, label, shape, and width.
* @param {Array<Object>} edges - Array of edge data objects.
* @param {HTMLElement} graphId - The DOM container element for Cytoscape.
*/
export default function cytoscapeMapTrace(nodes, edges, graphId) {
// create Cytoscape
let cy = cytoscape({
container: graphId,
elements: {
nodes: nodes, // Node data
edges: edges, // Edge data
},
layout: {
name: "dagre",
rankDir: "LR", // Vertical TB | Horizontal LR, variable from 'cytoscape-dagre' plugin
},
style: [
// Node styling
{
selector: "node",
style: {
label: function (node) {
// Text to display on the node
let text = "";
// node.data('label') accesses the original array value at node.data.label
text =
node.data("label").length > 18
? `${node.data("label").substr(0, 15)}...`
: `${node.data("label")}`;
return text;
},
"text-opacity": 0.7,
"background-color": "data(backgroundColor)",
"border-color": "data(bordercolor)",
"border-width": "1",
shape: "data(shape)",
"text-wrap": "wrap",
"text-max-width": 75,
"text-halign": "center",
"text-valign": "center",
height: "data(height)",
width: "data(width)",
color: "#001933",
"font-size": 14,
},
},
// Edge styling
{
selector: "edge",
style: {
"curve-style": "taxi", // unbundled-bezier | taxi
"target-arrow-shape": "triangle", // Arrow shape pointing to target: triangle
color: "gray", //#0066cc
width: "data(lineWidth)",
"line-style": "data(style)",
},
},
// Style changes when a node is selected
{
selector: "node:selected",
style: {
"border-color": "red",
"border-width": "3",
},
},
],
});
// creat tippy.js
let tip;
cy.on("mouseover", "node", function (event) {
tip?.destroy();
const node = event.target;
let ref = node.popperRef();
let dummyDomEle = document.createElement("div");
let content = createTooltipContent(node.data("label"));
tip = new tippy(dummyDomEle, {
// tippy props:
getReferenceClientRect: ref.getBoundingClientRect,
trigger: "manual",
content: content,
});
tip.show();
});
cy.on("mouseout", "node", function (event) {
tip?.destroy();
tip = null;
});
return cy;
}