noding / static /canvas.js
broadfield-dev's picture
Update static/canvas.js
5ccea09 verified
raw
history blame
7.76 kB
// Initialize Konva stage
const stage = new Konva.Stage({
container: 'container',
width: 1000,
height: 600
});
const layer = new Konva.Layer();
stage.add(layer);
// Store nodes, connections, and parsed data
let nodes = [];
let connections = [];
let parsedConnections = [];
let selectedNode = null;
// Submit code or file for parsing
function submitCode() {
const fileInput = document.getElementById('codeFile');
const codeInput = document.getElementById('codeInput').value;
const formData = new FormData();
if (fileInput.files.length > 0) {
formData.append('file', fileInput.files[0]);
} else if (codeInput) {
formData.append('code', codeInput);
} else {
alert('Please upload a file or paste code.');
return;
}
fetch('/parse_code', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.error) {
alert(data.error);
return;
}
clearCanvas();
parsedConnections = data.connections; // Store for auto-connect
createNodesFromParsedData(data.nodes, data.connections);
})
.catch(error => console.error('Error:', error));
}
// Clear existing nodes and connections
function clearCanvas() {
nodes.forEach(node => node.destroy());
layer.find('Shape').forEach(shape => shape.destroy()); // Includes Bezier curves
nodes = [];
connections = [];
parsedConnections = [];
layer.draw();
}
// Create nodes and connections from parsed data
function createNodesFromParsedData(parsedNodes, parsedConnections) {
parsedNodes.forEach(nodeData => {
const node = createNode(
nodeData.x,
nodeData.y,
nodeData.label,
nodeData.type,
nodeData.inputs,
nodeData.outputs,
nodeData.id
);
nodes.push(node);
layer.add(node);
});
// Initially, don't draw connections; wait for auto-connect or manual
layer.draw();
saveNodes();
}
// Create a node with inputs and outputs
function createNode(x, y, label, type, inputs = [], outputs = [], id) {
const node = new Konva.Group({
x: x,
y: y,
draggable: true
});
// Node rectangle
const color = type === 'function' ? '#ffeb3b' : type.includes('variable') ? '#90caf9' : type === 'import' ? '#a5d6a7' : '#ccc';
const box = new Konva.Rect({
width: 100,
height: 50,
fill: color,
stroke: 'black',
strokeWidth: 2,
cornerRadius: 5
});
// Node label
const text = new Konva.Text({
text: label,
fontSize: 12,
fontFamily: 'Arial',
fill: 'black',
width: 100,
align: 'center',
y: 20
});
node.add(box);
node.add(text);
// Add input/output ports
inputs.forEach((input, i) => {
const circle = new Konva.Circle({
x: 0,
y: 10 + i * 20,
radius: 5,
fill: 'red'
});
node.add(circle);
});
outputs.forEach((output, i) => {
const circle = new Konva.Circle({
x: 100,
y: 10 + i * 20,
radius: 5,
fill: 'green'
});
node.add(circle);
});
// Node data
node.data = {
id: id,
type: type,
label: label,
inputs: inputs,
outputs: outputs,
x: x,
y: y
};
// Handle node click for manual connections
node.on('click', () => {
if (!selectedNode) {
selectedNode = node;
} else {
createSplineConnection(selectedNode, node);
connections.push({
from: selectedNode.data.id,
to: node.data.id
});
selectedNode = null;
saveNodes();
}
});
// Update position and connections on drag
node.on('dragmove', () => {
node.data.x = node.x();
node.data.y = node.y();
updateConnections();
saveNodes();
});
return node;
}
// Create a spline (Bezier curve) connection
function createSplineConnection(fromNode, toNode) {
const startX = fromNode.x() + 100;
const startY = fromNode.y() + 25;
const endX = toNode.x();
const endY = toNode.y() + 25;
// Control points for Bezier curve
const control1X = startX + (endX - startX) / 3;
const control1Y = startY;
const control2X = startX + 2 * (endX - startX) / 3;
const control2Y = endY;
const spline = new Konva.Shape({
sceneFunc: function(context, shape) {
context.beginPath();
context.moveTo(startX, startY);
context.bezierCurveTo(control1X, control1Y, control2X, control2Y, endX, endY);
context.fillStrokeShape(shape);
},
stroke: 'black',
strokeWidth: 2
});
spline.data = { from: fromNode.data.id, to: toNode.data.id };
layer.add(spline);
layer.draw();
}
// Auto-connect nodes based on parsed connections
function autoConnect() {
// Clear existing connections
layer.find('Shape').forEach(shape => {
if (shape.data && shape.data.from !== undefined) {
shape.destroy();
}
});
connections = [];
// Create spline connections for parsed data
parsedConnections.forEach(conn => {
const fromNode = nodes.find(n => n.data.id === conn.from);
const toNode = nodes.find(n => n.data.id === conn.to);
if (fromNode && toNode) {
createSplineConnection(fromNode, toNode);
connections.push({ from: conn.from, to: conn.to });
}
});
layer.draw();
saveNodes();
}
// Add a manual node
function addNode() {
const node = createNode(
Math.random() * (stage.width() - 100),
Math.random() * (stage.height() - 100),
'Function',
'function',
[],
[],
nodes.length
);
nodes.push(node);
layer.add(node);
layer.draw();
saveNodes();
}
// Update spline connections when nodes move
function updateConnections() {
layer.find('Shape').forEach(shape => {
if (shape.data && shape.data.from !== undefined) {
const fromNode = nodes.find(n => n.data.id === shape.data.from);
const toNode = nodes.find(n => n.data.id === shape.data.to);
if (fromNode && toNode) {
const startX = fromNode.x() + 100;
const startY = fromNode.y() + 25;
const endX = toNode.x();
const endY = toNode.y() + 25;
const control1X = startX + (endX - startX) / 3;
const control1Y = startY;
const control2X = startX + 2 * (endX - startX) / 3;
const control2Y = endY;
shape.sceneFunc(function(context, shape) {
context.beginPath();
context.moveTo(startX, startY);
context.bezierCurveTo(control1X, control1Y, control2X, control2Y, endX, endY);
context.fillStrokeShape(shape);
});
}
}
});
layer.draw();
}
// Save nodes and connections to backend
function saveNodes() {
fetch('/save_nodes', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
nodes: nodes.map(n => n.data),
connections: connections
})
}).then(response => response.json())
.then(data => console.log('Saved:', data))
.catch(error => console.error('Error:', error));
}
// Initial draw
layer.draw();