broadfield-dev commited on
Commit
73622ec
·
verified ·
1 Parent(s): 6a4e54c

Update static/canvas.js

Browse files
Files changed (1) hide show
  1. static/canvas.js +75 -36
static/canvas.js CHANGED
@@ -16,6 +16,7 @@ let parsedConnections = [];
16
  let selectedPort = null;
17
  let disconnectMode = false;
18
  let codeWindow = null; // Track open code window
 
19
 
20
  // Zoom functionality
21
  let scale = 1;
@@ -87,15 +88,29 @@ function clearCanvas() {
87
  codeWindow.destroy();
88
  codeWindow = null;
89
  }
 
 
 
 
90
  layer.draw();
91
  }
92
 
93
  // Create nodes and connections from parsed data
94
  function createNodesFromParsedData(parsedNodes, parsedConnections) {
 
95
  parsedNodes.forEach(nodeData => {
 
 
 
 
 
 
 
 
 
96
  const node = createNode(
97
- nodeData.x,
98
- nodeData.y,
99
  nodeData.label,
100
  nodeData.type,
101
  nodeData.inputs,
@@ -109,7 +124,7 @@ function createNodesFromParsedData(parsedNodes, parsedConnections) {
109
  layer.add(node);
110
  });
111
  layer.draw();
112
- autoConnect(); // Call autoConnect after nodes are created
113
  saveNodes();
114
  }
115
 
@@ -260,11 +275,15 @@ function createNode(x, y, label, type, inputs = [], outputs = [], id, source = '
260
  codeWindow.destroy();
261
  codeWindow = null;
262
  }
 
 
 
 
263
 
264
  const nodePos = node.getAbsolutePosition();
265
  codeWindow = new Konva.Group({
266
- x: nodePos.x,
267
- y: nodePos.y + height + 10
268
  });
269
 
270
  const codeBox = new Konva.Rect({
@@ -276,20 +295,46 @@ function createNode(x, y, label, type, inputs = [], outputs = [], id, source = '
276
  cornerRadius: 5
277
  });
278
 
279
- const textarea = document.createElement('textarea');
280
- textarea.style.position = 'absolute';
281
- textarea.style.left = `${nodePos.x / scale + stage.x() / scale}px`;
282
- textarea.style.top = `${(nodePos.y + height + 10) / scale + stage.y() / scale}px`;
283
- textarea.style.width = '300px';
284
- textarea.style.height = '100px';
285
- textarea.style.fontFamily = 'monospace';
286
- textarea.value = source || '';
287
- document.body.appendChild(textarea);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
288
 
289
  // Update code on change
290
- textarea.addEventListener('change', () => {
291
- const newSource = textarea.value;
292
  node.data.source = newSource;
 
293
  fetch('/update_node', {
294
  method: 'POST',
295
  headers: { 'Content-Type': 'application/json' },
@@ -314,14 +359,15 @@ function createNode(x, y, label, type, inputs = [], outputs = [], id, source = '
314
  stage.on('click', (e) => {
315
  if (e.target !== box && codeWindow) {
316
  codeWindow.destroy();
317
- document.body.removeChild(textarea);
318
  codeWindow = null;
 
 
 
 
319
  stage.off('click');
320
  }
321
  });
322
 
323
- codeWindow.add(codeBox);
324
- layer.add(codeWindow);
325
  layer.draw();
326
  });
327
 
@@ -329,14 +375,14 @@ function createNode(x, y, label, type, inputs = [], outputs = [], id, source = '
329
  node.on('dragmove', () => {
330
  node.data.x = node.x();
331
  node.data.y = node.y();
332
- if (codeWindow) {
333
  const nodePos = node.getAbsolutePosition();
334
- codeWindow.position({ x: nodePos.x, y: nodePos.y + height + 10 });
335
- const textarea = document.querySelector(`textarea`);
336
- if (textarea) {
337
- textarea.style.left = `${nodePos.x / scale + stage.x() / scale}px`;
338
- textarea.style.top = `${(nodePos.y + height + 10) / scale + stage.y() / scale}px`;
339
- }
340
  }
341
  updateConnections();
342
  saveNodes();
@@ -384,7 +430,6 @@ function createSplineConnection(fromNode, fromPortId, toNode, toPortId) {
384
 
385
  // Enhanced auto-connect based on hierarchy, position, and role
386
  function autoConnect() {
387
- // Clear existing connections
388
  layer.find('Shape').forEach(shape => {
389
  if (shape.data && shape.data.fromNodeId !== undefined) {
390
  shape.destroy();
@@ -392,13 +437,11 @@ function autoConnect() {
392
  });
393
  connections = [];
394
 
395
- // Sort nodes by level and y-position to approximate program order
396
  const sortedNodes = [...nodes].sort((a, b) => {
397
  if (a.data.level !== b.data.level) return a.data.level - b.data.level;
398
- return a.data.y - b.data.y;
399
  });
400
 
401
- // Build hierarchy map
402
  const hierarchy = {};
403
  sortedNodes.forEach(node => {
404
  const parent = node.data.parent_path.split(' -> ')[0] || 'global';
@@ -406,7 +449,6 @@ function autoConnect() {
406
  hierarchy[parent].push(node);
407
  });
408
 
409
- // Create connections based on parsed connections and hierarchy
410
  parsedConnections.forEach(conn => {
411
  const fromNode = nodes.find(n => n.data.id === conn.from);
412
  const toNode = nodes.find(n => n.data.id === conn.to);
@@ -425,13 +467,11 @@ function autoConnect() {
425
  }
426
  });
427
 
428
- // Additional connections based on hierarchy and role
429
  sortedNodes.forEach(node => {
430
  const nodeId = node.data.id;
431
  const parent = node.data.parent_path.split(' -> ')[0] || 'global';
432
  const role = node.data.type;
433
 
434
- // Connect to parent if applicable
435
  if (parent !== 'global') {
436
  const parentNode = nodes.find(n => n.data.id === parent || n.data.label === parent.split('[')[0]);
437
  if (parentNode && parentNode.data.outputs.length > 0 && node.data.inputs.length > 0) {
@@ -449,7 +489,6 @@ function autoConnect() {
449
  }
450
  }
451
 
452
- // Connect variables to their uses
453
  if (role.includes('variable')) {
454
  const varName = node.data.label;
455
  sortedNodes.forEach(otherNode => {
@@ -498,7 +537,7 @@ function updateProgram() {
498
  function reconstructProgram() {
499
  const sortedNodes = [...nodes].sort((a, b) => {
500
  if (a.data.level !== b.data.level) return a.data.level - b.data.level;
501
- return a.data.y - b.data.y;
502
  });
503
 
504
  let program = '';
@@ -587,7 +626,7 @@ function saveNodes() {
587
  })),
588
  connections: connections
589
  })
590
- }).then(response => response.json())
591
  .then(data => console.log('Saved:', data))
592
  .catch(error => console.error('Error:', error));
593
  }
 
16
  let selectedPort = null;
17
  let disconnectMode = false;
18
  let codeWindow = null; // Track open code window
19
+ let codeTextarea = null; // Track textarea element
20
 
21
  // Zoom functionality
22
  let scale = 1;
 
88
  codeWindow.destroy();
89
  codeWindow = null;
90
  }
91
+ if (codeTextarea) {
92
+ codeTextarea.remove();
93
+ codeTextarea = null;
94
+ }
95
  layer.draw();
96
  }
97
 
98
  // Create nodes and connections from parsed data
99
  function createNodesFromParsedData(parsedNodes, parsedConnections) {
100
+ const scopePositions = {}; // Track x-position per scope
101
  parsedNodes.forEach(nodeData => {
102
+ const scope = nodeData.parent_path.split(' -> ')[0] || 'global';
103
+ if (!scopePositions[scope]) {
104
+ scopePositions[scope] = { x: 50, count: 0 };
105
+ }
106
+ // Stack left to right: increment x based on level and scope
107
+ const x = 50 + nodeData.level * 150 + scopePositions[scope].count * 200;
108
+ const y = scopePositions[scope].count * 80 + 50; // Slight y offset for readability
109
+ scopePositions[scope].count += 1;
110
+
111
  const node = createNode(
112
+ x,
113
+ y,
114
  nodeData.label,
115
  nodeData.type,
116
  nodeData.inputs,
 
124
  layer.add(node);
125
  });
126
  layer.draw();
127
+ autoConnect();
128
  saveNodes();
129
  }
130
 
 
275
  codeWindow.destroy();
276
  codeWindow = null;
277
  }
278
+ if (codeTextarea) {
279
+ codeTextarea.remove();
280
+ codeTextarea = null;
281
+ }
282
 
283
  const nodePos = node.getAbsolutePosition();
284
  codeWindow = new Konva.Group({
285
+ x: node.x(),
286
+ y: node.y() + height + 10
287
  });
288
 
289
  const codeBox = new Konva.Rect({
 
295
  cornerRadius: 5
296
  });
297
 
298
+ // Display source in Konva Text for visual containment
299
+ const codeText = new Konva.Text({
300
+ x: 5,
301
+ y: 5,
302
+ text: source || '',
303
+ fontSize: 12,
304
+ fontFamily: 'monospace',
305
+ fill: 'black',
306
+ width: 290,
307
+ padding: 5
308
+ });
309
+
310
+ codeWindow.add(codeBox);
311
+ codeWindow.add(codeText);
312
+ layer.add(codeWindow);
313
+
314
+ // Create textarea for editing
315
+ codeTextarea = document.createElement('textarea');
316
+ codeTextarea.style.position = 'absolute';
317
+ // Calculate position relative to canvas
318
+ const canvasRect = stage.container().getBoundingClientRect();
319
+ const textareaX = (nodePos.x + stage.x()) / scale + canvasRect.left;
320
+ const textareaY = (nodePos.y + height + 10 + stage.y()) / scale + canvasRect.top;
321
+ codeTextarea.style.left = `${textareaX}px`;
322
+ codeTextarea.style.top = `${textareaY}px`;
323
+ codeTextarea.style.width = `${300 / scale}px`;
324
+ codeTextarea.style.height = `${100 / scale}px`;
325
+ codeTextarea.style.fontFamily = 'monospace';
326
+ codeTextarea.style.fontSize = `${12 / scale}px`;
327
+ codeTextarea.style.background = 'transparent';
328
+ codeTextarea.style.border = 'none';
329
+ codeTextarea.style.resize = 'none';
330
+ codeTextarea.value = source || '';
331
+ document.body.appendChild(codeTextarea);
332
 
333
  // Update code on change
334
+ codeTextarea.addEventListener('change', () => {
335
+ const newSource = codeTextarea.value;
336
  node.data.source = newSource;
337
+ codeText.text(newSource);
338
  fetch('/update_node', {
339
  method: 'POST',
340
  headers: { 'Content-Type': 'application/json' },
 
359
  stage.on('click', (e) => {
360
  if (e.target !== box && codeWindow) {
361
  codeWindow.destroy();
 
362
  codeWindow = null;
363
+ if (codeTextarea) {
364
+ codeTextarea.remove();
365
+ codeTextarea = null;
366
+ }
367
  stage.off('click');
368
  }
369
  });
370
 
 
 
371
  layer.draw();
372
  });
373
 
 
375
  node.on('dragmove', () => {
376
  node.data.x = node.x();
377
  node.data.y = node.y();
378
+ if (codeWindow && codeTextarea) {
379
  const nodePos = node.getAbsolutePosition();
380
+ codeWindow.position({ x: node.x(), y: node.y() + height + 10 });
381
+ const canvasRect = stage.container().getBoundingClientRect();
382
+ const textareaX = (nodePos.x + stage.x()) / scale + canvasRect.left;
383
+ const textareaY = (nodePos.y + height + 10 + stage.y()) / scale + canvasRect.top;
384
+ codeTextarea.style.left = `${textareaX}px`;
385
+ codeTextarea.style.top = `${textareaY}px`;
386
  }
387
  updateConnections();
388
  saveNodes();
 
430
 
431
  // Enhanced auto-connect based on hierarchy, position, and role
432
  function autoConnect() {
 
433
  layer.find('Shape').forEach(shape => {
434
  if (shape.data && shape.data.fromNodeId !== undefined) {
435
  shape.destroy();
 
437
  });
438
  connections = [];
439
 
 
440
  const sortedNodes = [...nodes].sort((a, b) => {
441
  if (a.data.level !== b.data.level) return a.data.level - b.data.level;
442
+ return a.data.x - b.data.x; // Sort by x for left-to-right order
443
  });
444
 
 
445
  const hierarchy = {};
446
  sortedNodes.forEach(node => {
447
  const parent = node.data.parent_path.split(' -> ')[0] || 'global';
 
449
  hierarchy[parent].push(node);
450
  });
451
 
 
452
  parsedConnections.forEach(conn => {
453
  const fromNode = nodes.find(n => n.data.id === conn.from);
454
  const toNode = nodes.find(n => n.data.id === conn.to);
 
467
  }
468
  });
469
 
 
470
  sortedNodes.forEach(node => {
471
  const nodeId = node.data.id;
472
  const parent = node.data.parent_path.split(' -> ')[0] || 'global';
473
  const role = node.data.type;
474
 
 
475
  if (parent !== 'global') {
476
  const parentNode = nodes.find(n => n.data.id === parent || n.data.label === parent.split('[')[0]);
477
  if (parentNode && parentNode.data.outputs.length > 0 && node.data.inputs.length > 0) {
 
489
  }
490
  }
491
 
 
492
  if (role.includes('variable')) {
493
  const varName = node.data.label;
494
  sortedNodes.forEach(otherNode => {
 
537
  function reconstructProgram() {
538
  const sortedNodes = [...nodes].sort((a, b) => {
539
  if (a.data.level !== b.data.level) return a.data.level - b.data.level;
540
+ return a.data.x - b.data.x; // Sort by x for left-to-right order
541
  });
542
 
543
  let program = '';
 
626
  })),
627
  connections: connections
628
  })
629
+ }).then(response => response.json золото
630
  .then(data => console.log('Saved:', data))
631
  .catch(error => console.error('Error:', error));
632
  }