First commit
This commit is contained in:
291
index.html
Normal file
291
index.html
Normal file
@@ -0,0 +1,291 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Live Snap Drag Window with Canvas</title>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="top-panel">
|
||||
|
||||
<button id="graphExplorer">Graph Explorer</button>
|
||||
|
||||
<button id="resetParticlesButton">Reset Particles</button>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="wireMenu" style="
|
||||
position: absolute;
|
||||
display: none;
|
||||
background: #333;
|
||||
color: #eee;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 2px 6px rgba(0,0,0,0.8);
|
||||
">
|
||||
<button id="deleteWireBtn" style="background:#900; color:#fff; border:none; padding:4px 8px; cursor:pointer;">Delete Wire</button>
|
||||
</div>
|
||||
|
||||
<!-- Node context menu -->
|
||||
<div id="nodeMenu" style="
|
||||
position: absolute;
|
||||
display: none;
|
||||
background: #333;
|
||||
color: #eee;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 2px 6px rgba(0,0,0,0.8);
|
||||
">
|
||||
<button id="deleteNodeBtn" style="background:#900; color:#fff; border:none; padding:4px 8px; cursor:pointer;">Delete Node</button>
|
||||
</div>
|
||||
|
||||
<link rel="stylesheet" href="./style/main.css" >
|
||||
<script type="module">
|
||||
function autoLayoutNodes( graphExplorer ) {
|
||||
|
||||
const placedNodes = new Set();
|
||||
const visited = new Set();
|
||||
const levels = new Map();
|
||||
|
||||
function dfs( node, level ) {
|
||||
|
||||
if ( visited.has( node ) ) return;
|
||||
|
||||
visited.add( node );
|
||||
|
||||
// Assign the current level (depth) if it’s deeper
|
||||
if ( !levels.has( node ) || levels.get( node ) < level ) {
|
||||
|
||||
levels.set( node, level );
|
||||
|
||||
}
|
||||
|
||||
// Traverse all outgoing edges
|
||||
for ( var i = 0; i < graphExplorer.edges.length; i++ ) {
|
||||
|
||||
const edge = graphExplorer.edges[i];
|
||||
|
||||
if ( edge.fromNode === node ) {
|
||||
|
||||
dfs( edge.toNode, level + 1 );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start from nodes with no incoming edges
|
||||
for ( var i = 0; i < graphExplorer.nodes.length; i++ ) {
|
||||
|
||||
const node = graphExplorer.nodes[i];
|
||||
|
||||
const hasIncoming = graphExplorer.edges.some( edge => edge.toNode === node );
|
||||
|
||||
if ( !hasIncoming ) {
|
||||
|
||||
dfs( node, 0 );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Group nodes by level
|
||||
const layers = {};
|
||||
|
||||
for ( const [node, level] of levels ) {
|
||||
|
||||
if ( !layers[level] ) layers[level] = [];
|
||||
|
||||
layers[level].push( node );
|
||||
|
||||
}
|
||||
|
||||
const xSpacing = 400;
|
||||
const yBase = 150;
|
||||
|
||||
for ( const levelEntry of Object.entries( layers ) ) {
|
||||
|
||||
const levelStr = levelEntry[0];
|
||||
const nodesAtLevel = levelEntry[1];
|
||||
const level = Number( levelStr );
|
||||
|
||||
const spacing = yBase + Math.max(...nodesAtLevel.map(n => n.inputs.length)) * 25;
|
||||
|
||||
for ( let i = 0; i < nodesAtLevel.length; i++ ) {
|
||||
|
||||
const node = nodesAtLevel[i];
|
||||
|
||||
const xJitter = ( Math.random() - 0.5 ) * 80; // wider jitter horizontally
|
||||
const yJitter = ( Math.random() - 0.5 ) * 80; // wider jitter vertically
|
||||
|
||||
node.x = level * xSpacing + xJitter;
|
||||
node.y = i * spacing + yJitter;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
async function loadJSON( pathName ) {
|
||||
|
||||
const response = await fetch( pathName );
|
||||
|
||||
if ( !response.ok ) {
|
||||
|
||||
throw new Error( `Failed to load shader: ${ pathName }` );
|
||||
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
|
||||
}
|
||||
|
||||
function getShaderByName( shaders, shaderName ) {
|
||||
|
||||
for (var i = 0; i < shaders.length; i++) {
|
||||
|
||||
var shader = shaders[i]
|
||||
|
||||
if( shader.name == shaderName ) {
|
||||
|
||||
return shader;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function getPortIndex( bindings, variableName ) {
|
||||
|
||||
for (var i = 0; i < bindings.length; i++) {
|
||||
|
||||
var binding = bindings[i]
|
||||
|
||||
if( binding.varName == variableName ) {
|
||||
|
||||
return i;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
import { Node } from "./GraphExplorer.js"
|
||||
|
||||
import { Edge } from "./GraphExplorer.js"
|
||||
|
||||
import { GraphExplorer } from "./GraphExplorer.js"
|
||||
|
||||
import { WindowController } from "./WindowController.js"
|
||||
|
||||
|
||||
var graphExplorer = new GraphExplorer();
|
||||
|
||||
const windowController = new WindowController();
|
||||
|
||||
windowController.setGraphExplorer( graphExplorer );
|
||||
|
||||
|
||||
|
||||
var graphCanvas = document.createElement( "canvas" );
|
||||
|
||||
graphCanvas.id = "graphCanvas";
|
||||
|
||||
graphCanvas.width = windowController.startWidth;
|
||||
graphCanvas.height = windowController.startHeight;
|
||||
|
||||
|
||||
|
||||
console.log("set element", graphCanvas);
|
||||
|
||||
await windowController.setElement( graphCanvas );
|
||||
|
||||
await windowController.setup();
|
||||
|
||||
|
||||
windowController.maximizeWindow();
|
||||
|
||||
var nodes = await loadJSON("./nodes.json");
|
||||
|
||||
console.log(nodes);
|
||||
|
||||
var shaders = nodes.shaders;
|
||||
|
||||
for (var i = 0; i < shaders.length; i++) {
|
||||
|
||||
var shader = shaders[i]
|
||||
|
||||
var bindings = shader.bindings;
|
||||
|
||||
var newNode = new Node(shader.name, 50 + 240 * i, 100, [], []);
|
||||
|
||||
for (var j = 0; j < bindings.length; j++) {
|
||||
|
||||
var binding = bindings[j]
|
||||
|
||||
var varName = binding.varName;
|
||||
|
||||
newNode.inputs[j] = varName;
|
||||
|
||||
newNode.outputs[j] = varName;
|
||||
}
|
||||
|
||||
shader.node = newNode;
|
||||
|
||||
graphExplorer.addNode( newNode );
|
||||
|
||||
}
|
||||
var edges = nodes.edges;
|
||||
|
||||
for (var i = 0; i < edges.length; i++) {
|
||||
|
||||
var edge = edges[i]
|
||||
|
||||
var fromShader = getShaderByName( shaders, edge.from );
|
||||
|
||||
var toShader = getShaderByName( shaders, edge.to );
|
||||
|
||||
var fromPortIndex = getPortIndex( fromShader.bindings, edge.fromBuffer );
|
||||
|
||||
var toPortIndex = getPortIndex( toShader.bindings, edge.buffer );
|
||||
|
||||
var edge = new Edge( fromShader.node, fromPortIndex, toShader.node, toPortIndex );
|
||||
|
||||
graphExplorer.addEdge( edge );
|
||||
|
||||
//console.log(edge, shaders, edge.from, fromShader);
|
||||
|
||||
}
|
||||
|
||||
autoLayoutNodes( graphExplorer );
|
||||
|
||||
graphExplorer.setup( graphCanvas );
|
||||
graphExplorer.inertiaLoop();
|
||||
graphExplorer.draw();
|
||||
|
||||
|
||||
document.querySelector("#graphExplorer").addEventListener("click", function () {
|
||||
|
||||
windowController.show();
|
||||
|
||||
});
|
||||
|
||||
|
||||
windowController.resizeCanvas();
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user