// 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} nodes - Array of node data objects with * backgroundColor, bordercolor, height, id, label, shape, and width. * @param {Array} 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; }