Skip to content

Instantly share code, notes, and snippets.

@ryanzec
Created February 16, 2025 19:41
Show Gist options
  • Save ryanzec/7857391ffe40bfe8b447aaf22f8b39e0 to your computer and use it in GitHub Desktop.
Save ryanzec/7857391ffe40bfe8b447aaf22f8b39e0 to your computer and use it in GitHub Desktop.
cytoscape solidjs template
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