Changed around line 1
+ class GraphViz {
+ constructor(canvasId) {
+ this.canvas = document.getElementById(canvasId);
+ this.ctx = this.canvas.getContext('2d');
+ this.nodes = [];
+ this.edges = [];
+ this.isDragging = false;
+ this.selectedNode = null;
+ this.mode = 'node';
+
+ this.initializeCanvas();
+ this.addEventListeners();
+ }
+
+ initializeCanvas() {
+ this.canvas.width = this.canvas.offsetWidth;
+ this.canvas.height = this.canvas.offsetHeight;
+ this.draw();
+ }
+
+ addEventListeners() {
+ this.canvas.addEventListener('mousedown', this.handleMouseDown.bind(this));
+ this.canvas.addEventListener('mousemove', this.handleMouseMove.bind(this));
+ this.canvas.addEventListener('mouseup', this.handleMouseUp.bind(this));
+ window.addEventListener('resize', () => this.initializeCanvas());
+ }
+
+ handleMouseDown(e) {
+ const rect = this.canvas.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+
+ if (this.mode === 'node') {
+ this.nodes.push({ x, y, radius: 20 });
+ } else {
+ this.selectedNode = this.findNode(x, y);
+ if (this.selectedNode) this.isDragging = true;
+ }
+ this.draw();
+ }
+
+ handleMouseMove(e) {
+ if (!this.isDragging) return;
+
+ const rect = this.canvas.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+
+ if (this.mode === 'edge') {
+ this.drawTempEdge(this.selectedNode.x, this.selectedNode.y, x, y);
+ }
+ }
+
+ handleMouseUp(e) {
+ if (this.mode === 'edge' && this.isDragging) {
+ const rect = this.canvas.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+
+ const targetNode = this.findNode(x, y);
+ if (targetNode && targetNode !== this.selectedNode) {
+ this.edges.push({
+ from: this.selectedNode,
+ to: targetNode
+ });
+ }
+ }
+
+ this.isDragging = false;
+ this.selectedNode = null;
+ this.draw();
+ }
+
+ findNode(x, y) {
+ return this.nodes.find(node => {
+ const dx = node.x - x;
+ const dy = node.y - y;
+ return Math.sqrt(dx * dx + dy * dy) < node.radius;
+ });
+ }
+
+ draw() {
+ this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
+
+ // Draw edges
+ this.edges.forEach(edge => {
+ this.ctx.beginPath();
+ this.ctx.moveTo(edge.from.x, edge.from.y);
+ this.ctx.lineTo(edge.to.x, edge.to.y);
+ this.ctx.strokeStyle = '#2a6ef5';
+ this.ctx.lineWidth = 2;
+ this.ctx.stroke();
+ });
+
+ // Draw nodes
+ this.nodes.forEach(node => {
+ this.ctx.beginPath();
+ this.ctx.arc(node.x, node.y, node.radius, 0, Math.PI * 2);
+ this.ctx.fillStyle = '#fff';
+ this.ctx.fill();
+ this.ctx.strokeStyle = '#2a6ef5';
+ this.ctx.lineWidth = 2;
+ this.ctx.stroke();
+ });
+ }
+
+ drawTempEdge(fromX, fromY, toX, toY) {
+ this.draw();
+ this.ctx.beginPath();
+ this.ctx.moveTo(fromX, fromY);
+ this.ctx.lineTo(toX, toY);
+ this.ctx.strokeStyle = '#e74c3c';
+ this.ctx.setLineDash([5, 5]);
+ this.ctx.lineWidth = 2;
+ this.ctx.stroke();
+ this.ctx.setLineDash([]);
+ }
+
+ clear() {
+ this.nodes = [];
+ this.edges = [];
+ this.draw();
+ }
+
+ setMode(mode) {
+ this.mode = mode;
+ }
+ }
+
+ // Initialize the graph visualization
+ document.addEventListener('DOMContentLoaded', () => {
+ const graph = new GraphViz('graphCanvas');
+
+ document.getElementById('addNode').addEventListener('click', () => graph.setMode('node'));
+ document.getElementById('addEdge').addEventListener('click', () => graph.setMode('edge'));
+ document.getElementById('clear').addEventListener('click', () => graph.clear());
+ });