prototipo-2-agente / interface /visualization.html
Pecximenes's picture
Uploading Fauses's agent to HuggingFace Spaces
2dd02d0
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Enhanced Directed Graph Visualization</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
body,
html {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
}
#mynetwork {
width: 100%;
height: 100%;
}
.node circle {
fill: #69b3a2;
stroke: #333;
stroke-width: 1.5px;
}
.node text {
font: 12px sans-serif;
pointer-events: none;
fill: #555;
}
.link {
fill: none;
stroke: #999;
stroke-opacity: 0.6;
stroke-width: 1.5px;
marker-end: url(#arrowhead);
}
.link.directed {
stroke: #ff5722;
}
.link.highlighted {
stroke-width: 3px;
stroke: #ff5722;
}
.tooltip {
position: absolute;
text-align: center;
width: auto;
height: auto;
padding: 5px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
opacity: 0;
}
#controls {
position: absolute;
top: 10px;
left: 10px;
z-index: 1;
}
#legend {
position: absolute;
top: 10px;
right: 10px;
background-color: rgba(255, 255, 255, 0.7);
padding: 10px;
border-radius: 3px;
font-size: 12px;
}
#legend .legend-item {
display: flex;
align-items: center;
}
#legend .legend-item span {
margin-left: 5px;
}
#legend .legend-color {
width: 12px;
height: 12px;
border-radius: 50%;
}
#search {
position: absolute;
top: 50px;
left: 10px;
z-index: 1;
}
</style>
</head>
<body>
<div id="controls">
<button onclick="fitNetwork()">Fit View</button>
<button onclick="expandAll()">Expand All</button>
<button onclick="collapseAll()">Collapse All</button>
<input type="range" id="charge" min="-1000" max="0" value="-300" step="10">
<label for="charge">Charge Strength</label>
</div>
<div id="search">
<input type="text" id="searchInput" placeholder="Search nodes...">
<button onclick="searchNode()">Search</button>
</div>
<div id="legend">
<div class="legend-item">
<div class="legend-color" style="background-color: #69b3a2;"></div>
<span>Node</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background-color: #ff5722;"></div>
<span>Directed Link</span>
</div>
</div>
<div id="mynetwork"></div>
<div class="tooltip"></div>
<script>
// Define dimensions
const width = window.innerWidth;
const height = window.innerHeight;
// Default graph data
const defaultGraphData = {
"nodes": [
{"id": "1", "label": "Root"},
{"id": "2", "label": "Child 1"},
{"id": "3", "label": "Child 2"}
],
"edges": [
{"from": "1", "to": "2"},
{"from": "1", "to": "3"}
]
};
// Function to initialize the graph
function initializeGraph(graphData) {
// Create the SVG container
const svg = d3.select("#mynetwork")
.append("svg")
.attr("width", width)
.attr("height", height)
.call(d3.zoom().on("zoom", function (event) {
svg.attr("transform", event.transform);
}))
.append("g");
// Create a tooltip
const tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// Define the arrowhead marker
svg.append("defs").append("marker")
.attr("id", "arrowhead")
.attr("viewBox", "0 -5 10 10")
.attr("refX", 20)
.attr("refY", 0)
.attr("markerWidth", 8)
.attr("markerHeight", 8)
.attr("orient", "auto")
.append("path")
.attr("d", "M 0,-5 L 10,0 L 0,5")
.attr("fill", "#999");
// Rename edges from "from" and "to" to "source" and "target"
graphData.edges.forEach(edge => {
edge.source = edge.from;
edge.target = edge.to;
delete edge.from;
delete edge.to;
});
// Collect all node IDs
const nodeIds = new Set(graphData.nodes.map(node => node.id));
// Create a mapping for default nodes
const defaultNode = {
id: "default",
label: "Unknown Node",
x: width / 2,
y: height / 2
};
// Ensure all edges have valid nodes
graphData.edges.forEach(edge => {
if (!nodeIds.has(edge.source)) {
graphData.nodes.push({ ...defaultNode, id: edge.source });
nodeIds.add(edge.source);
}
if (!nodeIds.has(edge.target)) {
graphData.nodes.push({ ...defaultNode, id: edge.target });
nodeIds.add(edge.target);
}
});
// Create the simulation
const simulation = d3.forceSimulation(graphData.nodes)
.force("link", d3.forceLink(graphData.edges).id(d => d.id).distance(100))
.force("charge", d3.forceManyBody().strength(-300))
.force("center", d3.forceCenter(width / 2, height / 2))
.force("collision", d3.forceCollide().radius(50));
// Create links
const link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graphData.edges)
.enter().append("line")
.attr("class", "link directed");
// Create nodes
const node = svg.append("g")
.attr("class", "nodes")
.selectAll("g")
.data(graphData.nodes)
.enter().append("g")
.attr("class", "node")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
node.append("circle")
.attr("r", 15)
.attr("fill", "#69b3a2");
node.append("text")
.attr("x", 18)
.attr("y", 5)
.text(d => d.label)
.attr("font-size", "12px")
.attr("fill", "#555");
// Add tooltips and highlighting
node.on("mouseover", function (event, d) {
highlightConnections(d);
showTooltip(event, d);
}).on("mouseout", function () {
unhighlightConnections();
hideTooltip();
});
// Update positions on tick
simulation.on("tick", () => {
link
.attr("x1", d => d.source.x)
.attr("y1", d => d.source.y)
.attr("x2", d => d.target.x)
.attr("y2", d => d.target.y);
node
.attr("transform", d => `translate(${d.x},${d.y})`);
});
function dragstarted(event, d) {
if (!event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(event, d) {
d.fx = event.x;
d.fy = event.y;
}
function dragended(event, d) {
if (!event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
function highlightConnections(d) {
node.style("opacity", n => n === d || graphData.edges.some(l => (l.source === d && l.target === n) || (l.target === d && l.source === n)) ? 1 : 0.1);
link.style("opacity", l => l.source === d || l.target === d ? 1 : 0.1)
.classed("highlighted", l => l.source === d || l.target === d);
}
function unhighlightConnections() {
node.style("opacity", 1);
link.style("opacity", 1).classed("highlighted", false);
}
function showTooltip(event, d) {
tooltip.transition().duration(200).style("opacity", .9);
tooltip.html(`
<strong>${d.label}</strong><br/>
ID: ${d.id}<br/>
Connections: ${graphData.edges.filter(l => l.source === d || l.target === d).length}
`)
.style("left", (event.pageX + 10) + "px")
.style("top", (event.pageY - 28) + "px");
}
function hideTooltip() {
tooltip.transition().duration(500).style("opacity", 0);
}
window.fitNetwork = () => {
const bounds = svg.node().getBBox();
const parent = svg.node().parentElement;
const fullWidth = parent.clientWidth;
const fullHeight = parent.clientHeight;
const width = bounds.width;
const height = bounds.height;
const midX = bounds.x + width / 2;
const midY = bounds.y + height / 2;
if (width === 0 || height === 0) return; // nothing to fit
const scale = 0.8 / Math.max(width / fullWidth, height / fullHeight);
const translate = [fullWidth / 2 - scale * midX, fullHeight / 2 - scale * midY];
svg.transition()
.duration(750)
.call(
d3.zoom().transform,
d3.zoomIdentity.translate(translate[0], translate[1]).scale(scale)
);
};
window.expandAll = () => {
node.style("display", "block");
link.style("display", "block");
simulation.alpha(1).restart();
};
window.collapseAll = () => {
node.style("display", d => d.id === 'root' ? "block" : "none");
link.style("display", "none");
simulation.alpha(1).restart();
};
d3.select("#charge").on("input", function () {
simulation.force("charge").strength(+this.value);
simulation.alpha(1).restart();
});
window.searchNode = () => {
const searchTerm = document.getElementById("searchInput").value.toLowerCase();
node.style("opacity", d => d.label.toLowerCase().includes(searchTerm) ? 1 : 0.1);
link.style("opacity", 0.1);
};
}
// Function to load graph data and initialize
function loadAndInitializeGraph(graphDataOrUrl) {
if (typeof graphDataOrUrl === 'string') {
// If it's a URL, fetch the data
d3.json(graphDataOrUrl).then(data => {
initializeGraph(data);
}).catch(error => {
console.error("Error loading the JSON file:", error);
initializeGraph(defaultGraphData);
});
} else if (typeof graphDataOrUrl === 'object') {
// If it's an object, use it directly
initializeGraph(graphDataOrUrl);
} else {
// If neither, use the default data
initializeGraph(defaultGraphData);
}
}
// Usage:
// loadAndInitializeGraph(someJsonObject); // To use a JSON object
// loadAndInitializeGraph(); // To use default data
// Initialize with default data
loadAndInitializeGraph("../memory/graph_data.json"); // To load from a file
</script>
</body>
</html>