Spaces:
Running
Running
Update static/canvas.js
Browse files- static/canvas.js +83 -40
static/canvas.js
CHANGED
@@ -8,9 +8,10 @@ const stage = new Konva.Stage({
|
|
8 |
const layer = new Konva.Layer();
|
9 |
stage.add(layer);
|
10 |
|
11 |
-
// Store nodes and
|
12 |
let nodes = [];
|
13 |
let connections = [];
|
|
|
14 |
let selectedNode = null;
|
15 |
|
16 |
// Submit code or file for parsing
|
@@ -39,6 +40,7 @@ function submitCode() {
|
|
39 |
return;
|
40 |
}
|
41 |
clearCanvas();
|
|
|
42 |
createNodesFromParsedData(data.nodes, data.connections);
|
43 |
})
|
44 |
.catch(error => console.error('Error:', error));
|
@@ -47,9 +49,10 @@ function submitCode() {
|
|
47 |
// Clear existing nodes and connections
|
48 |
function clearCanvas() {
|
49 |
nodes.forEach(node => node.destroy());
|
50 |
-
layer.find('
|
51 |
nodes = [];
|
52 |
connections = [];
|
|
|
53 |
layer.draw();
|
54 |
}
|
55 |
|
@@ -69,23 +72,7 @@ function createNodesFromParsedData(parsedNodes, parsedConnections) {
|
|
69 |
layer.add(node);
|
70 |
});
|
71 |
|
72 |
-
|
73 |
-
const fromNode = nodes.find(n => n.data.id === conn.from);
|
74 |
-
const toNode = nodes.find(n => n.data.id === conn.to);
|
75 |
-
if (fromNode && toNode) {
|
76 |
-
const line = new Konva.Line({
|
77 |
-
points: [
|
78 |
-
fromNode.x() + 100, fromNode.y() + 25,
|
79 |
-
toNode.x(), toNode.y() + 25
|
80 |
-
],
|
81 |
-
stroke: 'black',
|
82 |
-
strokeWidth: 2
|
83 |
-
});
|
84 |
-
layer.add(line);
|
85 |
-
connections.push({ from: conn.from, to: conn.to });
|
86 |
-
}
|
87 |
-
});
|
88 |
-
|
89 |
layer.draw();
|
90 |
saveNodes();
|
91 |
}
|
@@ -99,7 +86,7 @@ function createNode(x, y, label, type, inputs = [], outputs = [], id) {
|
|
99 |
});
|
100 |
|
101 |
// Node rectangle
|
102 |
-
const color = type === 'function' ? '#ffeb3b' : type.includes('variable') ? '#90caf9' : '#ccc';
|
103 |
const box = new Konva.Rect({
|
104 |
width: 100,
|
105 |
height: 50,
|
@@ -160,15 +147,7 @@ function createNode(x, y, label, type, inputs = [], outputs = [], id) {
|
|
160 |
if (!selectedNode) {
|
161 |
selectedNode = node;
|
162 |
} else {
|
163 |
-
|
164 |
-
points: [
|
165 |
-
selectedNode.x() + 100, selectedNode.y() + 25,
|
166 |
-
node.x(), node.y() + 25
|
167 |
-
],
|
168 |
-
stroke: 'black',
|
169 |
-
strokeWidth: 2
|
170 |
-
});
|
171 |
-
layer.add(line);
|
172 |
connections.push({
|
173 |
from: selectedNode.data.id,
|
174 |
to: node.data.id
|
@@ -189,6 +168,59 @@ function createNode(x, y, label, type, inputs = [], outputs = [], id) {
|
|
189 |
return node;
|
190 |
}
|
191 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
192 |
// Add a manual node
|
193 |
function addNode() {
|
194 |
const node = createNode(
|
@@ -206,18 +238,29 @@ function addNode() {
|
|
206 |
saveNodes();
|
207 |
}
|
208 |
|
209 |
-
// Update
|
210 |
function updateConnections() {
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
221 |
}
|
222 |
}
|
223 |
});
|
|
|
8 |
const layer = new Konva.Layer();
|
9 |
stage.add(layer);
|
10 |
|
11 |
+
// Store nodes, connections, and parsed data
|
12 |
let nodes = [];
|
13 |
let connections = [];
|
14 |
+
let parsedConnections = [];
|
15 |
let selectedNode = null;
|
16 |
|
17 |
// Submit code or file for parsing
|
|
|
40 |
return;
|
41 |
}
|
42 |
clearCanvas();
|
43 |
+
parsedConnections = data.connections; // Store for auto-connect
|
44 |
createNodesFromParsedData(data.nodes, data.connections);
|
45 |
})
|
46 |
.catch(error => console.error('Error:', error));
|
|
|
49 |
// Clear existing nodes and connections
|
50 |
function clearCanvas() {
|
51 |
nodes.forEach(node => node.destroy());
|
52 |
+
layer.find('Shape').forEach(shape => shape.destroy()); // Includes Bezier curves
|
53 |
nodes = [];
|
54 |
connections = [];
|
55 |
+
parsedConnections = [];
|
56 |
layer.draw();
|
57 |
}
|
58 |
|
|
|
72 |
layer.add(node);
|
73 |
});
|
74 |
|
75 |
+
// Initially, don't draw connections; wait for auto-connect or manual
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
layer.draw();
|
77 |
saveNodes();
|
78 |
}
|
|
|
86 |
});
|
87 |
|
88 |
// Node rectangle
|
89 |
+
const color = type === 'function' ? '#ffeb3b' : type.includes('variable') ? '#90caf9' : type === 'import' ? '#a5d6a7' : '#ccc';
|
90 |
const box = new Konva.Rect({
|
91 |
width: 100,
|
92 |
height: 50,
|
|
|
147 |
if (!selectedNode) {
|
148 |
selectedNode = node;
|
149 |
} else {
|
150 |
+
createSplineConnection(selectedNode, node);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
151 |
connections.push({
|
152 |
from: selectedNode.data.id,
|
153 |
to: node.data.id
|
|
|
168 |
return node;
|
169 |
}
|
170 |
|
171 |
+
// Create a spline (Bezier curve) connection
|
172 |
+
function createSplineConnection(fromNode, toNode) {
|
173 |
+
const startX = fromNode.x() + 100;
|
174 |
+
const startY = fromNode.y() + 25;
|
175 |
+
const endX = toNode.x();
|
176 |
+
const endY = toNode.y() + 25;
|
177 |
+
|
178 |
+
// Control points for Bezier curve
|
179 |
+
const control1X = startX + (endX - startX) / 3;
|
180 |
+
const control1Y = startY;
|
181 |
+
const control2X = startX + 2 * (endX - startX) / 3;
|
182 |
+
const control2Y = endY;
|
183 |
+
|
184 |
+
const spline = new Konva.Shape({
|
185 |
+
sceneFunc: function(context, shape) {
|
186 |
+
context.beginPath();
|
187 |
+
context.moveTo(startX, startY);
|
188 |
+
context.bezierCurveTo(control1X, control1Y, control2X, control2Y, endX, endY);
|
189 |
+
context.fillStrokeShape(shape);
|
190 |
+
},
|
191 |
+
stroke: 'black',
|
192 |
+
strokeWidth: 2
|
193 |
+
});
|
194 |
+
|
195 |
+
spline.data = { from: fromNode.data.id, to: toNode.data.id };
|
196 |
+
layer.add(spline);
|
197 |
+
layer.draw();
|
198 |
+
}
|
199 |
+
|
200 |
+
// Auto-connect nodes based on parsed connections
|
201 |
+
function autoConnect() {
|
202 |
+
// Clear existing connections
|
203 |
+
layer.find('Shape').forEach(shape => {
|
204 |
+
if (shape.data && shape.data.from !== undefined) {
|
205 |
+
shape.destroy();
|
206 |
+
}
|
207 |
+
});
|
208 |
+
connections = [];
|
209 |
+
|
210 |
+
// Create spline connections for parsed data
|
211 |
+
parsedConnections.forEach(conn => {
|
212 |
+
const fromNode = nodes.find(n => n.data.id === conn.from);
|
213 |
+
const toNode = nodes.find(n => n.data.id === conn.to);
|
214 |
+
if (fromNode && toNode) {
|
215 |
+
createSplineConnection(fromNode, toNode);
|
216 |
+
connections.push({ from: conn.from, to: conn.to });
|
217 |
+
}
|
218 |
+
});
|
219 |
+
|
220 |
+
layer.draw();
|
221 |
+
saveNodes();
|
222 |
+
}
|
223 |
+
|
224 |
// Add a manual node
|
225 |
function addNode() {
|
226 |
const node = createNode(
|
|
|
238 |
saveNodes();
|
239 |
}
|
240 |
|
241 |
+
// Update spline connections when nodes move
|
242 |
function updateConnections() {
|
243 |
+
layer.find('Shape').forEach(shape => {
|
244 |
+
if (shape.data && shape.data.from !== undefined) {
|
245 |
+
const fromNode = nodes.find(n => n.data.id === shape.data.from);
|
246 |
+
const toNode = nodes.find(n => n.data.id === shape.data.to);
|
247 |
+
if (fromNode && toNode) {
|
248 |
+
const startX = fromNode.x() + 100;
|
249 |
+
const startY = fromNode.y() + 25;
|
250 |
+
const endX = toNode.x();
|
251 |
+
const endY = toNode.y() + 25;
|
252 |
+
|
253 |
+
const control1X = startX + (endX - startX) / 3;
|
254 |
+
const control1Y = startY;
|
255 |
+
const control2X = startX + 2 * (endX - startX) / 3;
|
256 |
+
const control2Y = endY;
|
257 |
+
|
258 |
+
shape.sceneFunc(function(context, shape) {
|
259 |
+
context.beginPath();
|
260 |
+
context.moveTo(startX, startY);
|
261 |
+
context.bezierCurveTo(control1X, control1Y, control2X, control2Y, endX, endY);
|
262 |
+
context.fillStrokeShape(shape);
|
263 |
+
});
|
264 |
}
|
265 |
}
|
266 |
});
|