Files
spring-state-machine-renderer/state_machine_exporter/flow_renderer_plan/interactive_poc2.html

185 lines
20 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Interactive State Machine Flows PoC 2</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
display: flex;
margin: 0;
height: 100vh;
background-color: #f8f9fa;
}
#sidebar {
width: 350px;
background: #ffffff;
border-right: 1px solid #e9ecef;
padding: 20px;
box-shadow: 2px 0 5px rgba(0,0,0,0.05);
overflow-y: auto;
}
#sidebar h2 {
margin-top: 0;
color: #343a40;
font-size: 1.5rem;
}
.flow-card {
background: #f1f3f5;
border: 1px solid #dee2e6;
border-radius: 6px;
padding: 15px;
margin-bottom: 15px;
cursor: pointer;
transition: all 0.2s ease;
}
.flow-card:hover {
background: #e3fafc;
border-color: #3bc9db;
transform: translateY(-2px);
box-shadow: 0 4px 6px rgba(0,0,0,0.05);
}
.flow-title {
font-weight: bold;
color: #495057;
margin-bottom: 5px;
}
.flow-desc {
font-size: 0.85rem;
color: #868e96;
}
#diagram-container {
flex-grow: 1;
padding: 20px;
overflow: auto;
display: flex;
justify-content: center;
align-items: center;
}
/* SVG Interactivity Styles */
.diagram svg {
max-width: 100%;
height: auto;
transition: all 0.3s ease;
}
/* Dimming state when a flow is active */
/* Target entities (states), links (transitions) */
.diagram.flow-active svg g.entity,
.diagram.flow-active svg g.link,
.diagram.flow-active svg > g > g[id] /* generic fallback for states like PAID1 */ {
opacity: 0.15;
transition: opacity 0.3s ease;
}
/* Highlighting logic */
.diagram.flow-active svg g.highlighted {
opacity: 1 !important;
}
/* Make highlighted paths thicker and colored */
.diagram.flow-active svg g.highlighted path,
.diagram.flow-active svg g.highlighted polygon {
stroke: #ff6b6b !important; /* Coral red */
stroke-width: 3px !important;
}
/* For states (rects/polygons) */
.diagram.flow-active svg g.highlighted rect,
.diagram.flow-active svg g.highlighted > polygon {
stroke: #ff6b6b !important;
stroke-width: 3px !important;
}
/* Highlight start/end points if included */
.diagram.flow-active svg g.highlighted ellipse {
stroke: #ff6b6b !important;
fill: #ff6b6b !important;
}
</style>
</head>
<body>
<div id="sidebar">
<h2>Business Flows</h2>
<p style="color: #6c757d; font-size: 0.9rem;">Hover over a card to visualize the path through the <b>SimpleEnum</b> state machine.</p>
<!-- Flow 1 -->
<div class="flow-card" data-nodes='[".start.", "SUBMITTED", "PAID", "FULFILLED", ".end."]' data-edges='[[".start.", "SUBMITTED"], ["SUBMITTED", "PAID"], ["PAID", "FULFILLED"], ["FULFILLED", ".end."]]'>
<div class="flow-title">1. Happy Path (Success)</div>
<div class="flow-desc">The standard flow for a successful order: Submitted -> Paid -> Fulfilled.</div>
</div>
<!-- Flow 2 -->
<div class="flow-card" data-nodes='[".start.", "SUBMITTED", "CANCELED", ".end."]' data-edges='[[".start.", "SUBMITTED"], ["SUBMITTED", "CANCELED"], ["CANCELED", ".end."]]'>
<div class="flow-title">2. Immediate Cancellation</div>
<div class="flow-desc">Order is canceled before any payment is made.</div>
</div>
<!-- Flow 3 -->
<div class="flow-card" data-nodes='[".start.", "SUBMITTED", "PAID", "CANCELED", ".end."]' data-edges='[[".start.", "SUBMITTED"], ["SUBMITTED", "PAID"], ["PAID", "CANCELED"], ["CANCELED", ".end."]]'>
<div class="flow-title">3. Cancel Post-Payment</div>
<div class="flow-desc">Order is canceled after payment.</div>
</div>
<!-- Flow 4 -->
<div class="flow-card" data-nodes='[".start.", "SUBMITTED", "PAID", "HAPPEN", "PAID3", "CANCELED", ".end."]' data-edges='[[".start.", "SUBMITTED"], ["SUBMITTED", "PAID"], ["PAID", "HAPPEN"], ["PAID", "PAID3"], ["PAID3", "CANCELED"], ["CANCELED", ".end."]]'>
<div class="flow-title">4. Complex Branching</div>
<div class="flow-desc">Testing choice branching: Paid -> Happen -> Paid3 -> Canceled.</div>
</div>
<!-- Flow 5 -->
<div class="flow-card" data-nodes='["SUBMITTED", "SUBMITTED"]' data-edges='[["SUBMITTED", "SUBMITTED"]]'>
<div class="flow-title">5. Internal Loop</div>
<div class="flow-desc">A transition from Submitted back to itself (ABCD).</div>
</div>
</div>
<div id="diagram-container">
<div id="diagram" class="diagram">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" data-diagram-type="STATE" height="591px" preserveAspectRatio="none" style="width:1018px;height:591px;background:#FFFFFF;" version="1.1" viewBox="0 0 1018 591" width="1018px" zoomAndPan="magnify"><defs/><g><g class="entity" data-entity="PAID" data-uid="ent0002" id="entity_PAID"><polygon fill="#F1F1F1" points="484.38,191,496.38,203,484.38,215,472.38,203,484.38,191" style="stroke:#181818;stroke-width:0.5;"/></g><g class="entity" data-entity="SUBMITTED" data-uid="ent0003" id="entity_SUBMITTED"><polygon fill="#F1F1F1" points="854.38,88.5,866.38,100.5,854.38,112.5,842.38,100.5,854.38,88.5" style="stroke:#181818;stroke-width:0.5;"/></g><ellipse cx="854.38" cy="16" fill="#222222" rx="10" ry="10" style="stroke:#222222;stroke-width:1;"/><g id="FULFILLED"><rect fill="#F1F1F1" height="50" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="89.2139" x="369.78" y="372"/><line style="stroke:#181818;stroke-width:0.5;" x1="369.78" x2="458.9939" y1="398.4883" y2="398.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="69.2139" x="379.78" y="390.5352">FULFILLED</text></g><g id="CANCELED"><rect fill="#F1F1F1" height="50" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="92.502" x="563.13" y="452"/><line style="stroke:#181818;stroke-width:0.5;" x1="563.13" x2="655.632" y1="478.4883" y2="478.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="72.502" x="573.13" y="470.5352">CANCELED</text></g><g id="PAID2"><rect fill="#F1F1F1" height="50" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="60.7695" x="675" y="292"/><line style="stroke:#181818;stroke-width:0.5;" x1="675" x2="735.7695" y1="318.4883" y2="318.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="40.7695" x="685" y="310.5352">PAID2</text></g><g id="PAID3"><rect fill="#F1F1F1" height="50" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="60.7695" x="579" y="292"/><line style="stroke:#181818;stroke-width:0.5;" x1="579" x2="639.7695" y1="318.4883" y2="318.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="40.7695" x="589" y="310.5352">PAID3</text></g><g id="PAID1"><rect fill="#F1F1F1" height="50" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="60.7695" x="7" y="292"/><line style="stroke:#181818;stroke-width:0.5;" x1="7" x2="67.7695" y1="318.4883" y2="318.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="40.7695" x="17" y="310.5352">PAID1</text></g><g id="HAPPEN"><rect fill="#F1F1F1" height="50" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="73.3545" x="244.71" y="292"/><line style="stroke:#181818;stroke-width:0.5;" x1="244.71" x2="318.0645" y1="318.4883" y2="318.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="53.3545" x="254.71" y="310.5352">HAPPEN</text></g><ellipse cx="482.38" cy="574" fill="none" rx="11" ry="11" style="stroke:#222222;stroke-width:1;"/><ellipse cx="482.38" cy="574" fill="#222222" rx="6" ry="6" style="stroke:#222222;stroke-width:1;"/><!--link *start* to SUBMITTED--><g class="link" data-entity-1=".start." data-entity-2="SUBMITTED" data-source-line="42" data-uid="lnk3" id="link_.start._SUBMITTED"><path d="M854.38,26.46 C854.38,41.7 854.38,65.62 854.38,82.04" fill="none" id="*start*-to-SUBMITTED" style="stroke:#181818;stroke-width:1;"/><polygon fill="#181818" points="854.38,88.04,858.38,79.04,854.38,83.04,850.38,79.04,854.38,88.04" style="stroke:#181818;stroke-width:1;"/></g><!--link SUBMITTED to PAID--><g class="link" data-entity-1="SUBMITTED" data-entity-2="PAID" data-source-line="47" data-uid="lnk4" id="link_SUBMITTED_PAID"><path d="M845.24,103.98 C794.16,117.86 550.4403,184.0575 499.3303,197.9375" fill="none" id="SUBMITTED-to-PAID" style="stroke:#1E90FF;stroke-width:2;"/><polygon fill="#1E90FF" points="493.54,199.51,503.2737,201.0115,498.3652,198.1996,501.1771,193.2911,493.54,199.51" style="stroke:#1E90FF;stroke-width:2;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="24.2544" x="692.54" y="157.5684">PAY</text></g><!--link PAID to FULFILLED--><g class="link" data-entity-1="PAID" data-entity-2="FULFILLED" data-source-line="48" data-uid="lnk6" id="link_PAID_FULFILLED"><path d="M474.87,205.93 C458.11,209.91 423.77,220.75 409.38,245 C386.11,284.26 395.0987,334.1504 404.3287,365.7704" fill="none" id="PAID-to-FULFILLED" style="stroke:#1E90FF;stroke-width:2;"/><polygon fill="#1E90FF" points="406.01,371.53,407.3279,361.7697,404.609,366.7303,399.6484,364.0114,406.01,371.53" style="stroke:#1E90FF;stroke-width:2;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="47.4868" x="410.38" y="258.5684">FULFILL</text></g><!--link SUBMITTED to CANCELED--><g class="link" data-entity-1="SUBMITTED" data-entity-2="CANCELED" data-source-line="49" data-uid="lnk8" id="link_SUBMITTED_CANCELED"><path d="M862.55,105.02 C890.89,117.76 981.96,163.51 956.38,215 C893.17,342.26 740.4206,421.2466 661.3606,455.2966" fill="none" id="SUBMITTED-to-CANCELED" style="stroke:#1E90FF;stroke-width:2;"/><polygon fill="#1E90FF" points="655.85,457.67,665.6982,457.7837,660.4422,455.6922,662.5337,450.4362,655.85,457.67" style="stroke:#1E90FF;stroke-width:2;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="70.6938" x="939.65" y="258.5684">CANCEL [&#955;]</text></g><!--link PAID to CANCELED--><g class="link" data-entity-1="PAID" data-entity-2="CANCELED" data-source-line="50" data-uid="lnk9" id="link_PAID_CANCELED"><path d="M484.69,215.23 C485.72,239.41 490.16,297.79 509.38,342 C527.9,384.59 558.2812,421.8711 581.5012,447.1511" fill="none" id="PAID-to-CANCELED" style="stroke:#1E90FF;stroke-width:2;"/><polygon fill="#1E90FF" points="585.56,451.57,582.4177,442.2359,582.1777,447.8876,576.5259,447.6476,585.56,451.57" style="stroke:#1E90FF;stroke-width:2;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="50.54" x="510.38" y="322.0684">CANCEL</text></g><!--link SUBMITTED to SUBMITTED--><g class="link" data-entity-1="SUBMITTED" data-entity-2="SUBMITTED" data-source-line="51" data-uid="lnk10" id="link_SUBMITTED_SUBMITTED"><path d="M862.7,96.15 C879.08,89.77 901.38,91.22 901.38,100.5 C901.38,109.78 884.6709,113.4076 868.2909,107.0276" fill="none" id="SUBMITTED-to-SUBMITTED" style="stroke:#1E90FF;stroke-width:2;"/><polygon fill="#1E90FF" points="862.7,104.85,869.6345,111.8437,867.3591,106.6647,872.5381,104.3892,862.7,104.85" style="stroke:#1E90FF;stroke-width:2;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="35.1787" x="907.38" y="105.5684">ABCD</text></g><!--link SUBMITTED to PAID2--><g class="link" data-entity-1="SUBMITTED" data-entity-2="PAID2" data-source-line="52" data-uid="lnk12" id="link_SUBMITTED_PAID2"><path d="M857.11,110.16 C862.76,129.71 874.08,178.39 859.38,215 C838.6,266.78 780.2918,293.0219 741.6518,305.6819" fill="none" id="SUBMITTED-to-PAID2" style="stroke:#4682B4;stroke-width:2;"/><polygon fill="#4682B4" points="735.95,307.55,745.7481,308.549,740.7015,305.9932,743.2572,300.9466,735.95,307.55" style="stroke:#4682B4;stroke-width:2;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="81.2119" x="866.32" y="208.0684">[&#955;] (order=0)</text></g><!--link SUBMITTED to PAID3--><g class="link" data-entity-1="SUBMITTED" data-entity-2="PAID3" data-source-line="53" data-uid="lnk14" id="link_SUBMITTED_PAID3"><path d="M848.89,107.58 C836.57,121.44 806.45,156.88 788.38,191 C772.73,220.57 787.77,239.1 763.38,262 C727.69,295.52 703.04,274.31 657.38,292 C651.74,294.19 651.2682,294.2117 645.6482,296.9117" fill="none" id="SUBMITTED-to-PAID3" style="stroke:#4682B4;stroke-width:2;"/><polygon fill="#4682B4" points="640.24,299.51,650.0845,299.2181,644.7469,297.3448,646.6202,292.0071,640.24,299.51" style="stroke:#4682B4;stroke-width:2;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="61.0581" x="789.38" y="208.0684">(order=1)</text></g><!--link PAID to PAID1--><g class="link" data-entity-1="PAID" data-entity-2="PAID1" data-source-line="54" data-uid="lnk16" id="link_PAID_PAID1"><path d="M473.06,204.21 C432.48,205.22 290.87,211.13 180.38,245 C139.71,257.47 101.58,277.4822 73.42,293.9422" fill="none" id="PAID-to-PAID1" style="stroke:#FF6347;stroke-width:2;"/><polygon fill="#FF6347" points="68.24,296.97,78.0285,295.8816,72.5567,294.4468,73.9915,288.975,68.24,296.97" style="stroke:#FF6347;stroke-width:2;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="81.2119" x="181.38" y="258.5684">[&#955;] (order=0)</text></g><!--link PAID to PAID2--><g class="link" data-entity-1="PAID" data-entity-2="PAID2" data-source-line="55" data-uid="lnk17" id="link_PAID_PAID2"><path d="M493.63,206.1 C514.52,211.07 566.61,224.63 606.38,245 C631.61,257.92 652.8443,273.0376 671.8443,288.0676" fill="none" id="PAID-to-PAID2" style="stroke:#FF6347;stroke-width:2;"/><polygon fill="#FF6347" points="676.55,291.79,671.9731,283.0692,672.6286,288.688,667.0099,289.3435,676.55,291.79" style="stroke:#FF6347;stroke-width:2;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="118.7012" x="636.19" y="258.5684">[guard1] (order=1)</text></g><!--link PAID to HAPPEN--><g class="link" data-entity-1="PAID" data-entity-2="HAPPEN" data-source-line="56" data-uid="lnk19" id="link_PAID_HAPPEN"><path d="M473.25,204.44 C434.05,206.22 303.48,214.41 278.38,245 C267.9,257.78 267.8049,270.7968 271.4349,285.8668" fill="none" id="PAID-to-HAPPEN" style="stroke:#FF6347;stroke-width:2;"/><polygon fill="#FF6347" points="272.84,291.7,274.6212,282.0135,271.6691,286.839,266.8436,283.887,272.84,291.7" style="stroke:#FF6347;stroke-width:2;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="81.2119" x="279.38" y="258.5684">[&#955;] (order=2)</text></g><!--link PAID to PAID3--><g class="link" data-entity-1="PAID" data-entity-2="PAID3" data-source-line="57" data-uid="lnk20" id="link_PAID_PAID3"><path d="M489.56,210.05 C499,220.94 519.82,244.33 539.38,262 C551.69,273.11 561.2732,280.8557 573.7832,290.2557" fill="none" id="PAID-to-PAID3" style="stroke:#FF6347;stroke-width:2;"/><polygon fill="#FF6347" points="578.58,293.86,573.7877,285.2557,574.5827,290.8564,568.982,291.6514,578.58,293.86" style="stroke:#FF6347;stroke-width:2;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="61.0581" x="540.38" y="258.5684">(order=3)</text></g><!--link PAID2 to CANCELED--><g class="link" data-entity-1="PAID2" data-entity-2="CANCELED" data-source-line="58" data-uid="lnk21" id="link_PAID2_CANCELED"><path d="M690.6,342.34 C672.55,372.03 645.3561,416.8026 627.3061,446.5026" fill="none" id="PAID2-to-CANCELED" style="stroke:#1E90FF;stroke-width:2;"/><polygon fill="#1E90FF" points="624.19,451.63,632.2824,446.0164,626.7868,447.3572,625.4459,441.8616,624.19,451.63" style="stroke:#1E90FF;stroke-width:2;"/></g><!--link PAID3 to CANCELED--><g class="link" data-entity-1="PAID3" data-entity-2="CANCELED" data-source-line="59" data-uid="lnk22" id="link_PAID3_CANCELED"><path d="M609.38,342.34 C609.38,372.03 609.38,415.93 609.38,445.63" fill="none" id="PAID3-to-CANCELED" style="stroke:#1E90FF;stroke-width:2;"/><polygon fill="#1E90FF" points="609.38,451.63,613.38,442.63,609.38,446.63,605.38,442.63,609.38,451.63" style="stroke:#1E90FF;stroke-width:2;"/></g><!--link PAID1 to PAID1--><g class="link" data-entity-1="PAID1" data-entity-2="PAID1" data-source-line="60" data-uid="lnk23" id="link_PAID1_PAID1"><path d="M67.99,305.79 C85.95,303.4 102.77,307.14 102.77,317 C102.77,326.86 91.8976,331.3915 73.9376,329.0015" fill="none" id="PAID1-to-PAID1" style="stroke:#1E90FF;stroke-width:2;"/><polygon fill="#1E90FF" points="67.99,328.21,76.3837,333.3622,72.9463,328.8696,77.439,325.4321,67.99,328.21" style="stroke:#1E90FF;stroke-width:2;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="112.7661" x="108.77" y="322.0684">ABCD / &#955;, action2</text></g><!--link CANCELED to *end*--><g class="link" data-entity-1="CANCELED" data-entity-2=".end." data-source-line="66" data-uid="lnk25" id="link_CANCELED_.end."><path d="M576.68,502.46 C548.02,523.91 513.1147,550.0162 495.8147,562.9562" fill="none" id="CANCELED-to-*end*" style="stroke:#181818;stroke-width:1;"/><polygon fill="#181818" points="491.01,566.55,500.6128,564.3624,495.0139,563.5552,495.8211,557.9562,491.01,566.55" style="stroke:#181818;stroke-width:1;"/></g><!--link FULFILLED to *end*--><g class="link" data-entity-1="FULFILLED" data-entity-2=".end." data-source-line="67" data-uid="lnk26" id="link_FULFILLED_.end."><path d="M423.84,422.33 C439.02,461.4 466.0072,530.8572 476.4072,557.6272" fill="none" id="FULFILLED-to-*end*" style="stroke:#181818;stroke-width:1;"/><polygon fill="#181818" points="478.58,563.22,479.0494,553.3823,476.7694,558.5594,471.5923,556.2793,478.58,563.22" style="stroke:#181818;stroke-width:1;"/></g><!--SRC=[dPJjRg9058R_SnKdsJzRKoiCQblZal1bQc9TaxMR66C82rDbPPa6i1zfUcMzXrxJ0ZEWw03RDJ4PvttcvNZcvGoZ-CN7YW0GnNQCuJLP0Lmu6-8v-Iy0pNQswv3i0bSdFWbXugqtyGBxFddAY3U1Vkqm94_irCGBy7pZETi0Hn58r1S_npWCR1zUCvswVP7CQt4qoXmInWjuZ8nqGqOvunFd61YDr9uevi3lNU347WcEcVwrrYqOuXtfLohIpE8XzoJSbdKaQaXLSvqsoOfV7d0P4xFF4UQacYMU52HtBxcaL2Qx_IkqBxr4ehfEbKZv-Ed6PKMTtJBPLtkgRd39NaMBMIGwBJ2VxJyFFXx0JH8RFuqEsBuFSMW7aPTUKWH9gy66w04xthtd07x4GGoj3Zr_WQtRXMN-DAVpqhD2xC9RIWqxBCN2ndCn38Tvp1GbYJKECKdlA1VpV775B5XS9KyKNqoYn1NI3765W_3KwImrpOZKZA1cH6v6kir8hum8ozOAscq5Vjnfj-Fvt3G4WKwRcJesYiEAmdOBx50Izhlj9PiOvx-8xwuIO-PpSEt93-jxwEBGJACKMJDraUmE4d8XPFIfoUXkCXfF9cQ34yCoDxQkhKrNfxhPw4gfp9GkOVdnlgegzJyzQ-iyx7gDgQhfHcQPBig6T4ILBWNnOZh8_Xjy9QdjD_6iqKNckp03wQne4nsdfRCIxrqwgQ3605KOh7Tsw4ghvYfkrDdCd3QNWMhBaFa6xAnCpw9_pOf0BJz3InNldVI9l407FjxFmSu6AIgcDJ-rfqEcwaLi8baDJHYT4OU3g-X6EhsIAIRiPmJR-Gi0]--></g></svg>
</div>
</div>
<script>
document.addEventListener("DOMContentLoaded", initializeInteractivity);
function initializeInteractivity() {
const diagramElement = document.getElementById("diagram");
const svgRoot = diagramElement.querySelector("svg");
const cards = document.querySelectorAll(".flow-card");
cards.forEach(card => {
card.addEventListener("mouseenter", () => {
diagramElement.classList.add("flow-active");
const nodes = JSON.parse(card.getAttribute("data-nodes"));
const edges = JSON.parse(card.getAttribute("data-edges"));
nodes.forEach(nodeName => {
let el = document.getElementById(nodeName) || document.getElementById("entity_" + nodeName);
if (el) el.classList.add("highlighted");
});
edges.forEach(edge => {
const from = edge[0];
const to = edge[1];
let link = document.getElementById(`link_${from}_${to}`);
if (!link) {
link = svgRoot.querySelector(`g.link[data-entity-1="${from}"][data-entity-2="${to}"]`);
}
if (link) link.classList.add("highlighted");
});
});
card.addEventListener("mouseleave", () => {
diagramElement.classList.remove("flow-active");
svgRoot.querySelectorAll(".highlighted").forEach(el => el.classList.remove("highlighted"));
});
});
}
</script>
</body>
</html>