Created
February 16, 2025 19:41
-
-
Save ryanzec/7857391ffe40bfe8b447aaf22f8b39e0 to your computer and use it in GitHub Desktop.
cytoscape solidjs template
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import styles from '$/core/components/cytoscape/cytoscape.sandbox.module.css'; | |
import { loggerUtils } from '$/core/utils/logger'; | |
import SandboxExamplesContainer from '$sandbox/components/sandbox-examples-container/sandbox-examples-container'; | |
import cytoscape, { type LayoutOptions } from 'cytoscape'; | |
import cytoscapeDagre from 'cytoscape-dagre'; | |
import { onMount } from 'solid-js'; | |
export default { | |
title: 'Components/Cytoscape', | |
}; | |
export const Default = () => { | |
let cytoscapeElement: HTMLDivElement | undefined; | |
onMount(() => { | |
if (!cytoscapeElement) { | |
return; | |
} | |
console.log(cytoscapeElement); | |
// @ts-expect-error not sure why typescript thinks this is an error, but it is not | |
cytoscape.use(cytoscapeDagre); | |
const cy = cytoscape({ | |
container: cytoscapeElement, | |
minZoom: 0.5, | |
maxZoom: 10, | |
wheelSensitivity: 0.5, | |
userZoomingEnabled: true, | |
userPanningEnabled: true, | |
boxSelectionEnabled: true, | |
autoungrabify: true, | |
elements: { | |
nodes: [ | |
{ data: { id: 'security', label: 'Security Management' } }, | |
{ data: { id: 'access', label: 'Access Control' } }, | |
{ data: { id: 'incident', label: 'Incident Response' } }, | |
{ data: { id: 'risk', label: 'Risk Management' } }, | |
{ data: { id: 'compliance', label: 'Compliance' } }, | |
{ data: { id: 'auth', label: 'Authentication' } }, | |
{ data: { id: 'authz', label: 'Authorization' } }, | |
{ data: { id: 'iam', label: 'Identity Management' } }, | |
{ data: { id: 'detection', label: 'Detection' } }, | |
{ data: { id: 'response', label: 'Response' } }, | |
{ data: { id: 'recovery', label: 'Recovery' } }, | |
{ data: { id: 'assessment', label: 'Risk Assessment' } }, | |
{ data: { id: 'mitigation', label: 'Risk Mitigation' } }, | |
{ data: { id: 'monitoring', label: 'Risk Monitoring' } }, | |
{ data: { id: 'audit', label: 'Audit' } }, | |
{ data: { id: 'reporting', label: 'Reporting' } }, | |
{ data: { id: 'policy', label: 'Policy Management' } }, | |
], | |
edges: [ | |
{ data: { source: 'security', target: 'access' } }, | |
{ data: { source: 'security', target: 'incident' } }, | |
{ data: { source: 'security', target: 'risk' } }, | |
{ data: { source: 'security', target: 'compliance' } }, | |
{ data: { source: 'access', target: 'auth' } }, | |
{ data: { source: 'access', target: 'authz' } }, | |
{ data: { source: 'access', target: 'iam' } }, | |
{ data: { source: 'incident', target: 'detection' } }, | |
{ data: { source: 'incident', target: 'response' } }, | |
{ data: { source: 'incident', target: 'recovery' } }, | |
{ data: { source: 'risk', target: 'assessment' } }, | |
{ data: { source: 'risk', target: 'mitigation' } }, | |
{ data: { source: 'risk', target: 'monitoring' } }, | |
{ data: { source: 'compliance', target: 'audit' } }, | |
{ data: { source: 'compliance', target: 'reporting' } }, | |
{ data: { source: 'compliance', target: 'policy' } }, | |
], | |
}, | |
style: [ | |
{ | |
selector: 'node', | |
style: { | |
label: 'data(label)', | |
'text-valign': 'center', | |
'text-halign': 'center', | |
'background-color': '#6c757d', | |
color: '#fff', | |
'font-size': '12px', | |
width: '100px', | |
height: '35px', | |
'text-wrap': 'wrap', | |
}, | |
}, | |
{ | |
selector: 'edge', | |
style: { | |
width: 1, | |
'line-color': '#adb5bd', | |
'target-arrow-color': '#adb5bd', | |
'target-arrow-shape': 'triangle', | |
'curve-style': 'straight', | |
'source-distance-from-node': 3, | |
'target-distance-from-node': 3, | |
'arrow-scale': 0.8, | |
}, | |
}, | |
], | |
layout: { | |
name: 'dagre', | |
spacingFactor: 0.8, | |
fit: true, | |
animate: true, | |
animationDuration: 500, | |
rankDir: 'LR', | |
padding: 30, | |
nodeSpacing: 100, | |
nodeSeparation: 150, | |
rankSep: 200, | |
edgeLengthVal: 200, | |
// there seems to be issue with typescript recongnizing darge layout option so this cast bypasses that | |
// biome-ignore lint/suspicious/noExplicitAny: see above | |
} as LayoutOptions & Record<string, any>, | |
}); | |
cy.on('tap', 'node', (event) => { | |
const node = event.target; | |
console.log('Clicked node: ', node); | |
}); | |
cy.on('mouseover', 'node', (event) => { | |
const node = event.target; | |
const renderedPosition = node.renderedPosition(); | |
const containerOffset = cy.container()?.getBoundingClientRect(); | |
if (!containerOffset) { | |
loggerUtils.warn(`could not get container offset for node ${node.data('label')}`); | |
return; | |
} | |
const absolutePosition = { | |
x: containerOffset.x + renderedPosition.x, | |
y: containerOffset.y + renderedPosition.y, | |
}; | |
console.log('Node position:', { | |
nodeLabel: node.data('label'), | |
renderedPosition, | |
containerOffset, | |
absolutePosition, | |
}); | |
}); | |
cy.on('mouseout', 'node', (event) => { | |
const node = event.target; | |
console.log('Mouse left node:', node); | |
}); | |
}); | |
return ( | |
<SandboxExamplesContainer class={styles.container}> | |
<div ref={cytoscapeElement} class={styles.container} /> | |
</SandboxExamplesContainer> | |
); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment