Skip to content

Feature/dove graph #422

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 25 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions media/explain/borderAndIconDraw.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// @ts-nocheck
import {
getNodeTopLeftAbsolute,
getTopLeftForBorder,
getBorderWidthAndHeight,
} from "./graphUtils.js";

export function deleteAllBorders() {
document.querySelectorAll(".border").forEach((el) => el.remove());
}

// @ts-ignore
const iconMap = window.iconMap;

const getCodiconClass = (label) => {
const className = iconMap[label];
return className !== undefined ? `codicon-${className}` : "";
};

function drawNodeIcon(fontSize, color, label) {
const icon = document.createElement("i");
const codiconClass = getCodiconClass(label);
icon.className = `codicon ${codiconClass}`;
Object.assign(icon.style, {
fontSize: `${fontSize}px`,
color,
height: "fit-content",
});
return icon;
}

export function drawBorderAndIconForEachExplainNode(
cy,
windowPadding
) {
const paddingX = 30;
const paddingY = 10;
const iconGap = 20;
const borderRadius = 10;
const iconColor = "#007acc";

let minIconSize = 50;
cy.nodes().forEach((node) => {
const nodeW = node.renderedWidth();
const iconSize = nodeW / 2;
minIconSize = Math.min(minIconSize, iconSize);
});


cy.nodes().forEach((node) => {
const nodeW = node.renderedWidth();
const nodeH = node.renderedHeight();

const nodeTopLeft = getNodeTopLeftAbsolute(node, cy);

const topLeft = getTopLeftForBorder(
nodeTopLeft.x,
nodeTopLeft.y,
paddingX,
paddingY,
minIconSize,
iconGap
);
const dimensions = getBorderWidthAndHeight(
paddingX,
nodeW,
paddingY,
nodeH,
minIconSize,
iconGap
);

const border = document.createElement("div");
border.className = "border";

Object.assign(border.style, {
width: `${dimensions.width}px`,
height: `${dimensions.height}px`,
position: "absolute",
top: `${topLeft.y}px`,
left: `${topLeft.x}px`,
display: "flex",
justifyContent: "center",
paddingTop: `${paddingY}px`,
borderRadius: `${borderRadius}px`,
borderColor: "transparent"
});

border.appendChild(drawNodeIcon(minIconSize, iconColor, node.data().label));
document.body.appendChild(border);
});
}
31 changes: 31 additions & 0 deletions media/explain/cytoscape.min.js

Large diffs are not rendered by default.

66 changes: 66 additions & 0 deletions media/explain/explain.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@

/* .diagram-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: none;
margin: 0;
} */

.diagram-container{
position: absolute;
top: 0;
box-sizing: border-box;
left: 0;
right: 0;
bottom: 0;
height: 100%;
overflow: hidden;
height: 100%;
border: none;
margin: 0;
border: 2px solid red;
}


.hover-box {
border-radius: 6px;
padding: 6px 10px;
font-size: 13px;
font-family: sans-serif;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
border: 1px solid #444;
white-space: nowrap;
z-index: 1000;
transition: opacity 0.2s ease;
opacity: 0.95;
position: absolute;
background: #fff;
border: 1px solid #aaa;
padding: 4px 8px;
color: black;
}

.border {
border: 3px solid #007acc;
pointer-events: none;
}

.warning-div {
position: fixed;
width: 100%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 9999;
padding: 2rem;
text-align: center;
}

.warning-div-title {
margin: 0;
font-size: 1.5rem;
color: #007acc;
}
164 changes: 164 additions & 0 deletions media/explain/explain.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
// @ts-nocheck
import {
getTooltipPosition,
showResizeWarning,
isWindowTooSmall,
isEnoughAreaWithoutBorders,
} from "./graphUtils.js";
import {
deleteAllBorders,
drawBorderAndIconForEachExplainNode,
} from "./borderAndIconDraw.js";

const tooltips = window.tooltips;
const vscode = window.acquireVsCodeApi();
const GRAPH_PADDING = 50;

if (isWindowTooSmall(GRAPH_PADDING)) {
showResizeWarning();
} else {
// Initialize Cytoscape
const cy = cytoscape({
container: document.getElementById("diagramContainer"),
elements: window.data,
userZoomingEnabled: false,
style: [
{
selector: "node",
// style: {
// padding: "5px",
// height: "15px",
// width: "label",
// "background-color": "var(--vscode-list-activeSelectionBackground)",
// color: "var(--vscode-list-activeSelectionForeground)",
// label: "data(label)",
// "text-valign": "center",
// "font-size": "14px",
// },
style: {
padding: "5px",
width: "150px", // fixed width
shape: "roundrectangle",
"background-color": "var(--vscode-list-activeSelectionBackground)",
color: "var(--vscode-list-activeSelectionForeground)",
label: "data(label)",
"text-wrap": "wrap", // enable wrapping
"text-max-width": "150px", // must match or be less than width
"text-valign": "center",
"text-halign": "center",
"font-size": "14px",
"line-height": "1.2",
// "text-overflow-wrap": "anywhere",
},
},
{
selector: "edge",
style: {
width: 2,
"line-color": "#5c96bc",
"target-arrow-color": "#5c96bc",
"target-arrow-shape": "triangle",
"curve-style": "bezier",
},
},
],

layout: {
name: "grid",
fit: true, // whether to fit the viewport to the graph
padding: GRAPH_PADDING, // padding used on fit
avoidOverlap: true, // prevents node overlap, may overflow boundingBox if not enough space
avoidOverlapPadding: 10, // extra spacing around nodes when avoidOverlap: true
nodeDimensionsIncludeLabels: false, // Excludes the label when calculating node bounding boxes for the layout algorithm
spacingFactor: undefined, // Applies a multiplicative factor (>0) to expand or compress the overall area that the nodes take up
condense: false, // uses all available space on false, uses minimal space on true
rows: undefined, // force num of rows in the grid
cols: undefined, // force num of columns in the grid
position: function (node) {}, // returns { row, col } for element
sort: undefined, // a sorting function to order the nodes; e.g. function(a, b){ return a.data('weight') - b.data('weight') }
animate: false, // whether to transition the node positions
animationDuration: 500, // duration of animation in ms if enabled
animationEasing: undefined, // easing of animation if enabled
animateFilter: function (node, i) {
return true;
}, // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts
ready: undefined, // callback on layoutready
stop: undefined, // callback on layoutstop
transform: function (node, position) {
return position;
}, // transform a given node position. Useful for changing flow direction in discrete layouts
},

// layout: {
// name: "breadthfirst",
// fit: true, // whether to fit the viewport to the graph
// directed: false,
// padding: GRAPH_PADDING, // paddinsg used on fit
// boudingBox: { x1: 0, y1: 0, w: window.innerWidth, h: window.innerHeight },
// circle: false, // put depths in concentric circles if true, put depths top down if false
// grid: false,
// avoidOverlap: true,
// nodeDimensionsIncludeLabels: false, // Excludes the label when calculating node bounding boxes for the layout algorithm
// },
});

window.addEventListener("resize", () => {
cy.resize(); // Resize Cytoscape's canvas
cy.fit(cy.nodes().boundingBox(), GRAPH_PADDING); // Optional: Fit all nodes back into view
cy.center();
});

if (!isEnoughAreaWithoutBorders(cy, GRAPH_PADDING)) {
cy.destroy();
showResizeWarning();
} else {
// When clicked, we display the details for the node in the bottom tree view
cy.on("tap", "node", function (evt) {
const id = evt.target.id();
vscode.postMessage({
command: "selected",
nodeId: id,
});
});

// === Tooltip Hover Handler ===
cy.nodes().on("mouseover", (event) => {
const node = event.target;

const hoverDiv = document.createElement("pre");
const id = node.id();
const tooltip = tooltips[id];
hoverDiv.innerText = tooltip;
hoverDiv.className = "hover-box";
document.body.appendChild(hoverDiv);

function updatePosition() {
const { left, top } = getTooltipPosition(
node,
cy.container(),
hoverDiv
);
hoverDiv.style.left = `${left}px`;
hoverDiv.style.top = `${top}px`;
}

updatePosition();
cy.on("pan zoom resize", updatePosition);
node.on("position", updatePosition);

node.once("mouseout", () => {
hoverDiv.remove();
cy.off("pan zoom resize", updatePosition);
node.off("position", updatePosition);
});
});

function redrawBorders() {
deleteAllBorders();
drawBorderAndIconForEachExplainNode(cy, GRAPH_PADDING);
}

cy.on("pan zoom resize", redrawBorders);
drawBorderAndIconForEachExplainNode(cy, GRAPH_PADDING);
}
}
Loading