Changed around line 1
+ class Node {
+ constructor(x, y, content = 'New Node') {
+ this.x = x;
+ this.y = y;
+ this.width = 150;
+ this.height = 100;
+ this.content = content;
+ this.isDragging = false;
+ }
+
+ draw(ctx) {
+ ctx.save();
+ ctx.translate(this.x, this.y);
+
+ // Node background
+ ctx.fillStyle = '#3b82f6';
+ ctx.beginPath();
+ ctx.roundRect(0, 0, this.width, this.height, 12);
+ ctx.fill();
+
+ // Node content
+ ctx.fillStyle = '#ffffff';
+ ctx.font = '14px sans-serif';
+ ctx.textAlign = 'center';
+ ctx.textBaseline = 'middle';
+ ctx.fillText(this.content, this.width/2, this.height/2);
+
+ ctx.restore();
+ }
+
+ isPointInside(x, y) {
+ return x > this.x && x < this.x + this.width &&
+ y > this.y && y < this.y + this.height;
+ }
+ }
+
+ class Dashboard {
+ constructor(canvas) {
+ this.canvas = canvas;
+ this.ctx = canvas.getContext('2d');
+ this.nodes = [];
+ this.selectedNode = null;
+ this.isDragging = false;
+ this.offsetX = 0;
+ this.offsetY = 0;
+
+ this.setupEventListeners();
+ this.resizeCanvas();
+ this.animate();
+ }
+
+ setupEventListeners() {
+ this.canvas.addEventListener('mousedown', this.handleMouseDown.bind(this));
+ this.canvas.addEventListener('mousemove', this.handleMouseMove.bind(this));
+ this.canvas.addEventListener('mouseup', this.handleMouseUp.bind(this));
+ this.canvas.addEventListener('dblclick', this.handleDoubleClick.bind(this));
+ this.canvas.addEventListener('contextmenu', this.handleRightClick.bind(this));
+ window.addEventListener('resize', this.resizeCanvas.bind(this));
+ }
+
+ handleMouseDown(e) {
+ const rect = this.canvas.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+
+ for (let node of this.nodes) {
+ if (node.isPointInside(x, y)) {
+ this.selectedNode = node;
+ this.isDragging = true;
+ this.offsetX = x - node.x;
+ this.offsetY = y - node.y;
+ break;
+ }
+ }
+ }
+
+ handleMouseMove(e) {
+ if (this.isDragging && this.selectedNode) {
+ const rect = this.canvas.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+
+ this.selectedNode.x = x - this.offsetX;
+ this.selectedNode.y = y - this.offsetY;
+ }
+ }
+
+ handleMouseUp() {
+ this.isDragging = false;
+ this.selectedNode = null;
+ }
+
+ handleDoubleClick(e) {
+ const rect = this.canvas.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+
+ for (let node of this.nodes) {
+ if (node.isPointInside(x, y)) {
+ this.editNode(node);
+ break;
+ }
+ }
+ }
+
+ handleRightClick(e) {
+ e.preventDefault();
+ const rect = this.canvas.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+
+ for (let i = this.nodes.length - 1; i >= 0; i--) {
+ if (this.nodes[i].isPointInside(x, y)) {
+ this.nodes.splice(i, 1);
+ break;
+ }
+ }
+ }
+
+ editNode(node) {
+ const dialog = document.getElementById('editDialog');
+ const textarea = document.getElementById('nodeContent');
+ textarea.value = node.content;
+
+ dialog.showModal();
+
+ dialog.querySelector('form').onsubmit = (e) => {
+ e.preventDefault();
+ node.content = textarea.value;
+ dialog.close();
+ };
+
+ document.getElementById('cancelEdit').onclick = () => dialog.close();
+ }
+
+ addNode() {
+ const x = this.canvas.width / 2 - 75;
+ const y = this.canvas.height / 2 - 50;
+ this.nodes.push(new Node(x, y));
+ }
+
+ resizeCanvas() {
+ this.canvas.width = window.innerWidth;
+ this.canvas.height = window.innerHeight;
+ }
+
+ animate() {
+ this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
+
+ for (let node of this.nodes) {
+ node.draw(this.ctx);
+ }
+
+ requestAnimationFrame(this.animate.bind(this));
+ }
+ }
+
+ // Initialize dashboard
+ const canvas = document.getElementById('dashboardCanvas');
+ const dashboard = new Dashboard(canvas);
+
+ // Add node button
+ document.getElementById('addNode').addEventListener('click', () => {
+ dashboard.addNode();
+ });