ADA-Python / templates /graph.html
ussu321's picture
Upload 50 files
bd86de0 verified
Raw
History Blame Contribute Delete
19.4 kB
{% extends "base.html" %}
{% block title %}Graph Algorithms | USSU Algorithm Analyzer v4.0{% endblock %}
{% block extra_head %}
<style>
#graph-viz { width: 100%; height: 520px; border-radius: 16px; background: rgba(15,23,42,0.6); border: 1px solid rgba(255,255,255,0.08); position: relative; }
.graph-controls { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 20px; }
@media (max-width: 900px) { .graph-controls { grid-template-columns: 1fr; } }
.graph-overlay { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; color: #64748b; pointer-events: none; }
.graph-legend { display: flex; gap: 16px; margin-top: 12px; flex-wrap: wrap; }
.legend-item { display: flex; align-items: center; gap: 6px; font-size: 12px; color: #94a3b8; }
.legend-dot { width: 10px; height: 10px; border-radius: 50%; }
.result-metric-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-top: 16px; }
@media (max-width: 768px) { .result-metric-grid { grid-template-columns: repeat(2, 1fr); } }
.result-detail-card { background: rgba(30,41,59,0.6); border: 1px solid rgba(255,255,255,0.06); border-radius: 10px; padding: 12px; }
.result-detail-label { font-family: 'Orbitron', sans-serif; font-size: 10px; color: var(--cyan); text-transform: uppercase; letter-spacing: 1px; margin-bottom: 4px; }
.result-detail-value { font-family: 'Orbitron', sans-serif; font-size: 18px; color: #f8fafc; font-weight: 700; }
.btn-small { padding: 8px 16px; font-size: 11px; }
.process-flow { display: flex; align-items: center; gap: 8px; margin: 16px 0; flex-wrap: wrap; }
.process-node { background: linear-gradient(135deg, rgba(6,182,212,0.15), rgba(139,92,246,0.15)); border: 1px solid rgba(6,182,212,0.2); border-radius: 8px; padding: 8px 12px; font-size: 12px; color: #e2e8f0; }
.process-arrow { color: var(--cyan); font-size: 16px; }
</style>
{% endblock %}
{% block content %}
<div class="page-header animate-in">
<h1>🕸️ GRAPH ALGORITHMS</h1>
<p>Interactive graph traversal, shortest path, MST, and DAG analysis with real-time visualization.</p>
<div class="header-line"></div>
</div>
<div class="graph-controls">
<div class="glass-card animate-in delay-1">
<h3 style="font-family: 'Orbitron'; color: var(--bright-cyan); margin-bottom: 16px;">Create Graph</h3>
<form method="POST" id="graphForm">
<input type="hidden" name="action" value="create">
<div class="form-group">
<label class="form-label">Vertices</label>
<input type="number" name="n" value="5" min="2" max="50" class="form-input">
</div>
<div class="form-group">
<label class="form-label">Edge Probability (0-1)</label>
<input type="number" name="p" value="0.4" step="0.1" min="0.1" max="1" class="form-input">
</div>
<div class="form-group" style="display: flex; gap: 20px;">
<label style="display: flex; align-items: center; gap: 6px; color: #94a3b8; font-size: 14px; cursor: pointer;">
<input type="checkbox" name="directed"> Directed
</label>
<label style="display: flex; align-items: center; gap: 6px; color: #94a3b8; font-size: 14px; cursor: pointer;">
<input type="checkbox" name="weighted" checked> Weighted
</label>
</div>
<div style="display: flex; gap: 10px;">
<button type="submit" class="btn-liquid">Generate Random Graph</button>
<button type="button" class="btn-liquid btn-small" onclick="fillRandomEdges()">⚡ Random Demo</button>
</div>
</form>
<div class="section-divider" style="margin-top: 24px;">
<h3>▸ OR CUSTOM EDGES</h3>
<div class="line"></div>
</div>
<form method="POST" style="margin-top: 12px;">
<input type="hidden" name="action" value="custom">
<div class="form-group">
<label class="form-label">Edges (one per line: u v [w])</label>
<textarea name="edges" id="customEdges" class="form-textarea" style="min-height: 100px;" placeholder="0 1 5&#10;1 2 3&#10;2 0 2&#10;0 3 1&#10;3 4 7"></textarea>
</div>
<div class="form-group" style="display: flex; gap: 20px;">
<label style="display: flex; align-items: center; gap: 6px; color: #94a3b8; font-size: 14px; cursor: pointer;">
<input type="checkbox" name="directed" id="customDirected"> Directed
</label>
<label style="display: flex; align-items: center; gap: 6px; color: #94a3b8; font-size: 14px; cursor: pointer;">
<input type="checkbox" name="weighted" id="customWeighted" checked> Weighted
</label>
</div>
<div style="display: flex; gap: 10px;">
<button type="submit" class="btn-liquid">Build Custom Graph</button>
<button type="button" class="btn-liquid btn-small" onclick="fillRandomEdges()">⚡ Auto-Fill Random</button>
</div>
</form>
</div>
<div class="glass-card animate-in delay-2">
<h3 style="font-family: 'Orbitron'; color: var(--bright-cyan); margin-bottom: 16px;">Run Algorithm</h3>
<form method="POST" id="runForm">
<input type="hidden" name="action" value="run">
<input type="hidden" name="graph_json" id="graphJson" value='{% if graph_data %}{{ graph_data|tojson|safe }}{% endif %}'>
<div class="form-group">
<label class="form-label">Algorithm</label>
<select name="algo" class="form-select" id="algoSelect">
<option value="bfs" {% if algo == 'bfs' %}selected{% endif %}>BFS Traversal</option>
<option value="dfs_iter" {% if algo == 'dfs_iter' %}selected{% endif %}>DFS Iterative</option>
<option value="dfs_rec" {% if algo == 'dfs_rec' %}selected{% endif %}>DFS Recursive</option>
<option value="dijkstra" {% if algo == 'dijkstra' %}selected{% endif %}>Dijkstra Shortest Path</option>
<option value="bellman_ford" {% if algo == 'bellman_ford' %}selected{% endif %}>Bellman-Ford</option>
<option value="floyd_warshall" {% if algo == 'floyd_warshall' %}selected{% endif %}>Floyd-Warshall</option>
<option value="prim" {% if algo == 'prim' %}selected{% endif %}>Prim MST</option>
<option value="kruskal" {% if algo == 'kruskal' %}selected{% endif %}>Kruskal MST</option>
<option value="topological" {% if algo == 'topological' %}selected{% endif %}>Topological Sort</option>
<option value="kosaraju" {% if algo == 'kosaraju' %}selected{% endif %}>Kosaraju SCC</option>
<option value="astar" {% if algo == 'astar' %}selected{% endif %}>A* Search</option>
<option value="longest_path_dag" {% if algo == 'longest_path_dag' %}selected{% endif %}>Longest Path (DAG)</option>
</select>
</div>
<div class="form-group">
<label class="form-label">Start Node</label>
<input type="number" name="start" value="0" min="0" class="form-input">
</div>
<div class="form-group" id="targetGroup">
<label class="form-label">Target Node (optional for traversal)</label>
<input type="number" name="target" value="" class="form-input" placeholder="Leave empty for traversal only">
</div>
<button type="submit" class="btn-liquid btn-liquid-glow" id="runBtn">Execute Algorithm</button>
</form>
{% if graph_data %}
<div class="graph-legend">
<div class="legend-item"><div class="legend-dot" style="background:#06b6d4;"></div> Node</div>
<div class="legend-item"><div class="legend-dot" style="background:#8b5cf6;"></div> Edge</div>
<div class="legend-item"><div class="legend-dot" style="background:#10b981;"></div> Visited</div>
<div class="legend-item"><div class="legend-dot" style="background:#f59e0b;"></div> Highlight</div>
</div>
{% endif %}
</div>
</div>
{% if graph_data %}
<div class="glass-card animate-in delay-3" style="margin-top: 24px;">
<h3 style="font-family: 'Orbitron'; color: var(--bright-cyan); margin-bottom: 12px;">Graph Visualization</h3>
<div id="graph-viz">
<div class="graph-overlay" id="graphOverlay">
<div style="font-size: 32px; margin-bottom: 8px;">🕸️</div>
<div>Initializing graph engine...</div>
</div>
</div>
<p id="graph-status" style="text-align:center; color:#64748b; margin-top:8px; font-size:12px;"></p>
<div style="text-align: center; margin-top: 8px;">
<button onclick="fitGraph()" class="btn-liquid btn-small">Fit View</button>
<button onclick="togglePhysics()" class="btn-liquid btn-small">Toggle Physics</button>
<button onclick="stabilizeGraph()" class="btn-liquid btn-small">Stabilize</button>
</div>
</div>
{% else %}
<div class="glass-card animate-in delay-3" style="margin-top: 24px; text-align: center; padding: 60px 20px;">
<div style="font-size: 48px; margin-bottom: 16px; animation: float 3s ease-in-out infinite;">🕸️</div>
<h3 style="font-family: 'Orbitron'; color: var(--bright-cyan); margin-bottom: 8px;">No Graph Generated Yet</h3>
<p style="color: #64748b;">Create a random graph, use "Auto-Fill Random" for quick demo, or enter custom edges.</p>
</div>
{% endif %}
{% if img_data %}
<div class="glass-card animate-in" style="margin-top: 24px;">
<h3 style="font-family: 'Orbitron'; color: var(--bright-cyan); margin-bottom: 12px;">Result Visualization</h3>
<img src="data:image/png;base64,{{ img_data }}" style="width: 100%; border-radius: 12px; border: 1px solid rgba(255,255,255,0.06);">
</div>
{% endif %}
{% if result %}
<div class="glass-card animate-in" style="margin-top: 24px;">
<h3 style="font-family: 'Orbitron'; color: var(--bright-cyan); margin-bottom: 12px;">Algorithm Result</h3>
{% if result.status is defined %}
<div class="result-metric-grid">
<div class="result-detail-card">
<div class="result-detail-label">Status</div>
<div class="result-detail-value" style="color: {% if result.status == 'ok' %}var(--green){% elif result.status == 'error' %}var(--red){% else %}var(--yellow){% endif %}">{{ result.status|upper }}</div>
</div>
<div class="result-detail-card">
<div class="result-detail-label">Message</div>
<div class="result-detail-value" style="font-size: 14px;">{{ result.message }}</div>
</div>
{% if result.vertices is defined %}
<div class="result-detail-card">
<div class="result-detail-label">Vertices</div>
<div class="result-detail-value">{{ result.vertices }}</div>
</div>
{% endif %}
{% if result.edges is defined %}
<div class="result-detail-card">
<div class="result-detail-label">Edges</div>
<div class="result-detail-value">{{ result.edges }}</div>
</div>
{% endif %}
</div>
{% endif %}
{% if result.execution_time_ms is defined %}
<div class="result-metric-grid" style="margin-top: 12px;">
<div class="result-detail-card">
<div class="result-detail-label">Execution Time</div>
<div class="result-detail-value">{{ "%.4f"|format(result.execution_time_ms) }} <span style="font-size: 12px; color: #64748b;">ms</span></div>
</div>
<div class="result-detail-card">
<div class="result-detail-label">Memory Used</div>
<div class="result-detail-value">{{ "%.2f"|format(result.memory_used_kb) }} <span style="font-size: 12px; color: #64748b;">KB</span></div>
</div>
<div class="result-detail-card">
<div class="result-detail-label">Comparisons</div>
<div class="result-detail-value">{{ result.comparisons }}</div>
</div>
<div class="result-detail-card">
<div class="result-detail-label">Accesses</div>
<div class="result-detail-value">{{ result.accesses }}</div>
</div>
</div>
{% endif %}
{% if result.algorithm is defined and result.execution_time_ms is defined %}
<div class="process-flow" style="margin-top: 16px;">
<div class="process-node">{{ result.algorithm }}</div>
<div class="process-arrow"></div>
<div class="process-node">{{ result.time_complexity }}</div>
<div class="process-arrow"></div>
<div class="process-node">{{ result.space_complexity }}</div>
</div>
{% endif %}
<div class="code-block" style="margin-top: 16px; max-height: 400px; overflow-y: auto;">{{ result|tojson_pretty }}</div>
</div>
{% endif %}
{% endblock %}
{% block extra_scripts %}
<script type="text/javascript">
var network = null;
var graphData = null;
function fillRandomEdges() {
var n = 6;
var edges = [];
var seen = new Set();
for (var i = 0; i < n; i++) {
for (var j = i + 1; j < n; j++) {
if (Math.random() < 0.5) {
var w = Math.floor(Math.random() * 20) + 1;
edges.push(i + " " + j + " " + w);
seen.add(i + "-" + j);
}
}
}
// Ensure connected
for (var i = 0; i < n - 1; i++) {
if (!seen.has(i + "-" + (i+1)) && !seen.has((i+1) + "-" + i)) {
edges.push(i + " " + (i+1) + " " + (Math.floor(Math.random() * 20) + 1));
}
}
document.getElementById('customEdges').value = edges.join("\n");
// Auto-check weighted
document.getElementById('customWeighted').checked = true;
// Visual feedback
var ta = document.getElementById('customEdges');
ta.style.borderColor = 'var(--cyan)';
setTimeout(function() { ta.style.borderColor = ''; }, 1000);
}
function initGraph() {
var container = document.getElementById('graph-viz');
var overlay = document.getElementById('graphOverlay');
var statusEl = document.getElementById('graph-status');
{% if graph_data %}
graphData = {{ graph_data|tojson|safe }};
{% else %}
graphData = null;
{% endif %}
if (!graphData || !container) {
if (statusEl) statusEl.textContent = 'No graph data available';
return;
}
if (typeof vis === 'undefined') {
if (overlay) overlay.innerHTML = '<div style="color:var(--red)">⚠ vis.js failed to load.<br>Check internet connection.</div>';
if (statusEl) statusEl.innerHTML = '<span style="color:var(--red)">Error: vis.js library not loaded</span>';
return;
}
try {
var nodes = new vis.DataSet(graphData.nodes || []);
var edges = new vis.DataSet(graphData.edges || []);
var data = { nodes: nodes, edges: edges };
var options = {
nodes: {
shape: 'dot',
size: 28,
font: { size: 16, color: '#f8fafc', face: 'Orbitron', strokeWidth: 0 },
borderWidth: 2,
shadow: { enabled: true, color: 'rgba(6,182,212,0.5)', size: 10, x: 0, y: 0 },
color: { background: '#06b6d4', border: '#22d3ee', highlight: { background: '#10b981', border: '#22d3ee' } }
},
edges: {
width: 2,
color: { color: '#8b5cf6', highlight: '#22d3ee', hover: '#22d3ee' },
font: { color: '#f59e0b', size: 12, align: 'middle', strokeWidth: 0 },
smooth: { type: 'continuous', roundness: 0.2 },
shadow: { enabled: true, color: 'rgba(139,92,246,0.3)', size: 5, x: 0, y: 0 },
arrows: { to: { enabled: graphData.directed === true, scaleFactor: 0.8 } }
},
physics: {
enabled: true,
stabilization: {
enabled: true,
iterations: 200,
updateInterval: 25,
onlyDynamicEdges: false,
fit: true
},
barnesHut: {
gravitationalConstant: -4000,
centralGravity: 0.3,
springLength: 140,
springConstant: 0.04,
damping: 0.09,
avoidOverlap: 0.2
}
},
interaction: {
hover: true,
tooltipDelay: 200,
hideEdgesOnDrag: true,
navigationButtons: true,
keyboard: true
},
layout: { randomSeed: 42 }
};
network = new vis.Network(container, data, options);
network.on("stabilizationIterationsDone", function() {
if (overlay) overlay.style.display = 'none';
network.fit({ animation: { duration: 500, easingFunction: 'easeInOutQuad' } });
if (statusEl) statusEl.innerHTML = '<span style="color:var(--green)">✓</span> Graph ready — ' + (graphData.nodes||[]).length + ' nodes, ' + (graphData.edges||[]).length + ' edges';
});
network.on("stabilizationProgress", function(params) {
if (overlay && overlay.style.display !== 'none') {
overlay.innerHTML = '<div style="color:var(--cyan)">Stabilizing... ' + Math.round(params.iterations/200*100) + '%</div>';
}
});
var runForm = document.getElementById('runForm');
if (runForm) {
runForm.addEventListener('submit', function(e) {
document.getElementById('graphJson').value = JSON.stringify(graphData);
});
}
} catch (err) {
console.error('Graph render error:', err);
if (overlay) overlay.innerHTML = '<div style="color:var(--red)">⚠ Render error: ' + err.message + '</div>';
if (statusEl) statusEl.innerHTML = '<span style="color:var(--red)">Error: ' + err.message + '</span>';
}
}
function fitGraph() {
if (network) network.fit({ animation: { duration: 500, easingFunction: 'easeInOutQuad' } });
}
function togglePhysics() {
if (network) {
var enabled = network.physics.physicsEnabled;
network.setOptions({ physics: { enabled: !enabled } });
}
}
function stabilizeGraph() {
if (network) {
network.stabilize();
network.fit();
}
}
document.addEventListener('DOMContentLoaded', function() {
var algoSelect = document.getElementById('algoSelect');
var targetGroup = document.getElementById('targetGroup');
if (algoSelect && targetGroup) {
var noTarget = ['bfs', 'dfs_iter', 'dfs_rec', 'floyd_warshall', 'topological', 'kosaraju', 'prim', 'kruskal', 'bellman_ford', 'longest_path_dag'];
function updateTarget() {
targetGroup.style.display = noTarget.includes(algoSelect.value) ? 'none' : 'block';
}
algoSelect.addEventListener('change', updateTarget);
updateTarget();
}
initGraph();
});
</script>
{% endblock %}