Skip to content

Commit 8dcabfe

Browse files
committed
Added custom node labels and improved node rendering
1 parent d210b36 commit 8dcabfe

File tree

13 files changed

+355
-301
lines changed

13 files changed

+355
-301
lines changed

TODO.md

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/CodeGenerator.js

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,14 @@ class CodeGenerator {
132132
case 'Random':
133133
const randomType = node.properties.type || 'number';
134134
const resultVar = this.getUniqueVariableName('randomResult');
135-
135+
136136
switch (randomType) {
137137
case 'number':
138138
const min = parseFloat(node.properties.min) || 1;
139139
const max = parseFloat(node.properties.max) || 100;
140140
this.addLine(`const ${resultVar} = Math.floor(Math.random() * (${max} - ${min} + 1)) + ${min};`);
141141
break;
142-
142+
143143
case 'string':
144144
const length = parseInt(node.properties.length) || 10;
145145
const charset = node.properties.charset || 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
@@ -150,15 +150,15 @@ class CodeGenerator {
150150
this.indentLevel--;
151151
this.addLine(`}`);
152152
break;
153-
153+
154154
case 'boolean':
155155
const probability = parseFloat(node.properties.probability) || 50;
156156
this.addLine(`const ${resultVar} = Math.random() * 100 < ${probability};`);
157157
break;
158158
default:
159159
this.addLine(`// Unknown random type: ${node.properties.type}`);
160160
}
161-
161+
162162
this.nodeOutputs.set(node.id, resultVar);
163163
break;
164164
case 'Switch':
@@ -170,7 +170,7 @@ class CodeGenerator {
170170

171171
const ignoreCase = node.properties.ignoreCase;
172172
const cases = node.properties.cases || [];
173-
173+
174174
if (ignoreCase) {
175175
this.addLine(`switch (${switchValue}.toString().toLowerCase()) {`);
176176
} else {
@@ -196,46 +196,46 @@ class CodeGenerator {
196196

197197
this.addLine(`case ${caseValue}:`);
198198
this.indentLevel++;
199-
199+
200200
// Find and generate code for the case branch
201-
const caseEdge = this.edges.find(edge =>
202-
edge.start.nodeId === node.id &&
201+
const caseEdge = this.edges.find(edge =>
202+
edge.start.nodeId === node.id &&
203203
edge.start.index === index + 1 && // +1 because index 0 is the default output
204204
!edge.start.isInput
205205
);
206-
206+
207207
if (caseEdge) {
208208
const nextNode = this.nodes.find(n => n.id === caseEdge.end.nodeId);
209209
if (nextNode) {
210210
this.generateNodeCodeSequence(nextNode);
211211
}
212212
}
213-
213+
214214
this.addLine('break;');
215215
this.indentLevel--;
216216
});
217217

218218
// Default case
219219
this.addLine('default:');
220220
this.indentLevel++;
221-
221+
222222
// Find and generate code for the default branch
223-
const defaultEdge = this.edges.find(edge =>
224-
edge.start.nodeId === node.id &&
225-
edge.start.index === 0 &&
223+
const defaultEdge = this.edges.find(edge =>
224+
edge.start.nodeId === node.id &&
225+
edge.start.index === 0 &&
226226
!edge.start.isInput
227227
);
228-
228+
229229
if (defaultEdge) {
230230
const defaultNode = this.nodes.find(n => n.id === defaultEdge.end.nodeId);
231231
if (defaultNode) {
232232
this.generateNodeCodeSequence(defaultNode);
233233
}
234234
}
235-
235+
236236
this.addLine('break;');
237237
this.indentLevel--;
238-
238+
239239
this.indentLevel--;
240240
this.addLine('}');
241241
break;
@@ -275,7 +275,7 @@ class CodeGenerator {
275275
handleVariableNode(node) {
276276
const { name, type, initialValue } = node.properties;
277277
const inputValue = this.getNodeInputValue(node, 1);
278-
278+
279279
if (!this.variables.has(name)) {
280280
// First time this variable is used - declare and initialize it
281281
let declaration = `${this.settings.useConst ? 'const' : 'let'} ${name}`;
@@ -290,7 +290,7 @@ class CodeGenerator {
290290
// Variable already declared, just update its value
291291
this.addLine(`${name} = ${inputValue}`);
292292
}
293-
293+
294294
this.nodeOutputs.set(node.id, name);
295295
}
296296

@@ -724,9 +724,9 @@ class CodeGenerator {
724724
this.indentLevel++;
725725

726726
// Find and generate code for the 'True' branch
727-
const trueEdge = this.edges.find(edge =>
728-
edge.start.nodeId === node.id &&
729-
edge.start.isInput === false &&
727+
const trueEdge = this.edges.find(edge =>
728+
edge.start.nodeId === node.id &&
729+
edge.start.isInput === false &&
730730
edge.start.index === 0
731731
);
732732
if (trueEdge) {
@@ -741,9 +741,9 @@ class CodeGenerator {
741741
this.indentLevel++;
742742

743743
// Find and generate code for the 'False' branch
744-
const falseEdge = this.edges.find(edge =>
745-
edge.start.nodeId === node.id &&
746-
edge.start.isInput === false &&
744+
const falseEdge = this.edges.find(edge =>
745+
edge.start.nodeId === node.id &&
746+
edge.start.isInput === false &&
747747
edge.start.index === 1
748748
);
749749
if (falseEdge) {

src/VisualScripting.js

Lines changed: 59 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ const VisualScripting = () => {
7474
e.preventDefault();
7575
const rect = canvasRef.current.getBoundingClientRect();
7676
const { x, y } = camera.screenToWorld(e.clientX - rect.left, e.clientY - rect.top);
77-
77+
7878
const clickedNode = findClickedNode(x, y);
7979
if (clickedNode) {
8080
setNodeContextMenu({ visible: true, x, y });
@@ -241,39 +241,40 @@ const VisualScripting = () => {
241241

242242
// #region Node Operations
243243
const findClickedNode = (x, y) => {
244-
return nodes.find(node =>
245-
node.isPointInside(x, y, renderer.getNodeDimensions(node, canvasRef.current.getContext('2d')))
246-
);
244+
return nodes.find(node => {
245+
const nodeInstance = Node.createInstance(node, nodeTypes);
246+
return nodeInstance.isPointInside(x, y, renderer.getNodeDimensions(node, canvasRef.current.getContext('2d')));
247+
});
247248
};
248249

249250
const findClickedPort = (x, y) => {
250251
for (const node of nodes) {
251252
const nodeType = nodeTypes[node.type];
252253
const dimensions = renderer.getNodeDimensions(node, canvasRef.current.getContext('2d'));
253-
254+
254255
// Port icon dimensions (from Renderer.drawPortIcon)
255256
const portIconWidth = 6 * 1.5; // Base width of triangle * scale
256257
const portIconHeight = 10 * 1.5; // Base height of triangle * scale
257258
const portOffset = 5; // Distance from node border
258-
259+
259260
// Calculate port Y position using the same logic as in drawEdges
260261
const getPortY = (index) => {
261262
const titleHeight = 25;
262263
const portSpacing = 14;
263264
const portVerticalGap = 5;
264265
return node.y + titleHeight + portVerticalGap + (index * portSpacing) + 4;
265266
};
266-
267+
267268
// Check input ports
268269
for (let i = 0; i < nodeType.inputs.length; i++) {
269270
const portY = getPortY(i);
270271
const portX = node.x - portOffset;
271-
272+
272273
// Create a square hitbox around the port
273-
if (x >= portX - portIconWidth &&
274-
x <= portX + portIconWidth &&
275-
y >= portY - portIconHeight/2 &&
276-
y <= portY + portIconHeight/2) {
274+
if (x >= portX - portIconWidth &&
275+
x <= portX + portIconWidth &&
276+
y >= portY - portIconHeight / 2 &&
277+
y <= portY + portIconHeight / 2) {
277278
return node.getPortPosition(i, true, dimensions);
278279
}
279280
}
@@ -282,12 +283,12 @@ const VisualScripting = () => {
282283
for (let i = 0; i < nodeType.outputs.length; i++) {
283284
const portY = getPortY(i);
284285
const portX = node.x + dimensions.width + portOffset;
285-
286+
286287
// Create a square hitbox around the port
287-
if (x >= portX - portIconWidth &&
288-
x <= portX + portIconWidth &&
289-
y >= portY - portIconHeight/2 &&
290-
y <= portY + portIconHeight/2) {
288+
if (x >= portX - portIconWidth &&
289+
x <= portX + portIconWidth &&
290+
y >= portY - portIconHeight / 2 &&
291+
y <= portY + portIconHeight / 2) {
291292
return node.getPortPosition(i, false, dimensions);
292293
}
293294
}
@@ -313,7 +314,7 @@ const VisualScripting = () => {
313314
}
314315
return node;
315316
});
316-
317+
317318
setUndoStack([...undoStack, { nodes, edges }]);
318319
setRedoStack([]);
319320
setNodes(updatedNodes);
@@ -325,7 +326,7 @@ const VisualScripting = () => {
325326
}
326327
return node;
327328
}));
328-
329+
329330
setNeedsRedraw(true);
330331
};
331332

@@ -342,6 +343,35 @@ const VisualScripting = () => {
342343
setNeedsRedraw(true);
343344
}
344345
};
346+
347+
const setNodeLabel = () => {
348+
if (selectedNodes.length === 0) return;
349+
350+
const currentNode = selectedNodes[0];
351+
const newLabel = prompt('Enter node label:', currentNode.label || '');
352+
353+
if (newLabel !== null) { // Check if user didn't cancel
354+
setNodes(nodes.map(node => {
355+
if (node.id === currentNode.id) {
356+
const updatedNode = Node.createInstance(node, nodeTypes);
357+
updatedNode.label = newLabel;
358+
return updatedNode;
359+
}
360+
return node;
361+
}));
362+
363+
setSelectedNodes(prevSelected => prevSelected.map(node => {
364+
if (node.id === currentNode.id) {
365+
const updatedNode = Node.createInstance(node, nodeTypes);
366+
updatedNode.label = newLabel;
367+
return updatedNode;
368+
}
369+
return node;
370+
}));
371+
372+
setNeedsRedraw(true);
373+
}
374+
};
345375
// #endregion
346376

347377
// #region Menu Operations
@@ -381,19 +411,19 @@ const VisualScripting = () => {
381411
break;
382412
case 'loadExample':
383413
if (examples[param]) {
384-
const exampleNodes = examples[param].nodes.map(node =>
414+
const exampleNodes = examples[param].nodes.map(node =>
385415
Node.createFromExample(node, nodeTypes)
386416
);
387-
417+
388418
// Reconstruct edges with proper port positions
389419
const reconstructedEdges = examples[param].edges.map(edge => {
390420
const startNode = exampleNodes.find(n => n.id === edge.start.nodeId);
391421
const endNode = exampleNodes.find(n => n.id === edge.end.nodeId);
392-
422+
393423
if (startNode && endNode) {
394424
const startDimensions = renderer.getNodeDimensions(startNode, canvasRef.current.getContext('2d'));
395425
const endDimensions = renderer.getNodeDimensions(endNode, canvasRef.current.getContext('2d'));
396-
426+
397427
return {
398428
start: {
399429
...edge.start,
@@ -811,26 +841,28 @@ const VisualScripting = () => {
811841
const handleNodeContextMenuAction = (action) => {
812842
switch (action) {
813843
case 'copy':
814-
setCopiedNodes([...selectedNodes]);
844+
setCopiedNodes(selectedNodes.map(node => Node.createInstance(node, nodeTypes)));
815845
break;
816846
case 'delete':
817847
deleteSelectedNodes();
818848
break;
819849
case 'cut':
820-
setCopiedNodes([...selectedNodes]);
850+
setCopiedNodes(selectedNodes.map(node => Node.createInstance(node, nodeTypes)));
821851
deleteSelectedNodes();
822852
break;
823853
case 'duplicate':
824854
const newNodes = selectedNodes.map(node => {
825-
// Create a proper Node instance using the static create method
826855
const duplicatedNode = Node.create(node.type, node.x + 20, node.y + 20, nodeTypes);
827-
// Copy over the properties
828856
duplicatedNode.properties = { ...node.properties };
857+
duplicatedNode.label = node.label;
829858
return duplicatedNode;
830859
});
831860
setNodes([...nodes, ...newNodes]);
832861
setSelectedNodes(newNodes);
833862
break;
863+
case 'setLabel':
864+
setNodeLabel();
865+
break;
834866
default:
835867
console.log(`Unhandled node context menu action: ${action}`);
836868
}

0 commit comments

Comments
 (0)