Skip to content

Commit d210b36

Browse files
committed
Improved port hitboxes and edge rendering with consistent positioning
1 parent 13d6065 commit d210b36

File tree

3 files changed

+84
-10
lines changed

3 files changed

+84
-10
lines changed

TODO.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
11
# TODO
22

3-
- [ ] Add node context menu
4-
- [ ] Copy node
5-
- [ ] Delete node
6-
73
- [ ] Node labeling

src/VisualScripting.js

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -251,16 +251,43 @@ const VisualScripting = () => {
251251
const nodeType = nodeTypes[node.type];
252252
const dimensions = renderer.getNodeDimensions(node, canvasRef.current.getContext('2d'));
253253

254+
// Port icon dimensions (from Renderer.drawPortIcon)
255+
const portIconWidth = 6 * 1.5; // Base width of triangle * scale
256+
const portIconHeight = 10 * 1.5; // Base height of triangle * scale
257+
const portOffset = 5; // Distance from node border
258+
259+
// Calculate port Y position using the same logic as in drawEdges
260+
const getPortY = (index) => {
261+
const titleHeight = 25;
262+
const portSpacing = 14;
263+
const portVerticalGap = 5;
264+
return node.y + titleHeight + portVerticalGap + (index * portSpacing) + 4;
265+
};
266+
254267
// Check input ports
255268
for (let i = 0; i < nodeType.inputs.length; i++) {
256-
if (node.isPortClicked(x, y, i, true, dimensions)) {
269+
const portY = getPortY(i);
270+
const portX = node.x - portOffset;
271+
272+
// 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) {
257277
return node.getPortPosition(i, true, dimensions);
258278
}
259279
}
260280

261281
// Check output ports
262282
for (let i = 0; i < nodeType.outputs.length; i++) {
263-
if (node.isPortClicked(x, y, i, false, dimensions)) {
283+
const portY = getPortY(i);
284+
const portX = node.x + dimensions.width + portOffset;
285+
286+
// 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) {
264291
return node.getPortPosition(i, false, dimensions);
265292
}
266293
}
@@ -357,8 +384,34 @@ const VisualScripting = () => {
357384
const exampleNodes = examples[param].nodes.map(node =>
358385
Node.createFromExample(node, nodeTypes)
359386
);
387+
388+
// Reconstruct edges with proper port positions
389+
const reconstructedEdges = examples[param].edges.map(edge => {
390+
const startNode = exampleNodes.find(n => n.id === edge.start.nodeId);
391+
const endNode = exampleNodes.find(n => n.id === edge.end.nodeId);
392+
393+
if (startNode && endNode) {
394+
const startDimensions = renderer.getNodeDimensions(startNode, canvasRef.current.getContext('2d'));
395+
const endDimensions = renderer.getNodeDimensions(endNode, canvasRef.current.getContext('2d'));
396+
397+
return {
398+
start: {
399+
...edge.start,
400+
x: edge.start.isInput ? startNode.x : startNode.x + startDimensions.width,
401+
y: startNode.y + startDimensions.portStartY + (edge.start.index * 20)
402+
},
403+
end: {
404+
...edge.end,
405+
x: edge.end.isInput ? endNode.x : endNode.x + endDimensions.width,
406+
y: endNode.y + endDimensions.portStartY + (edge.end.index * 20)
407+
}
408+
};
409+
}
410+
return null;
411+
}).filter(edge => edge !== null);
412+
360413
setNodes(exampleNodes);
361-
setEdges(examples[param].edges);
414+
setEdges(reconstructedEdges);
362415
setUndoStack([]);
363416
setRedoStack([]);
364417
}

src/engine/Renderer.js

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,21 +144,46 @@ class Renderer {
144144
return;
145145
}
146146

147-
const startPort = startNode.getPortPosition(edge.start.index, edge.start.isInput, startDims);
148-
const endPort = endNode.getPortPosition(edge.end.index, edge.end.isInput, endDims);
147+
const getPortY = (node, dims, index) => {
148+
const titleHeight = 25;
149+
const portSpacing = 14;
150+
const portVerticalGap = 5;
151+
return node.y + titleHeight + portVerticalGap + (index * portSpacing) + 4;
152+
};
153+
154+
const startPort = {
155+
x: edge.start.isInput ? startNode.x : startNode.x + startDims.width,
156+
y: getPortY(startNode, startDims, edge.start.index)
157+
};
158+
159+
const endPort = {
160+
x: edge.end.isInput ? endNode.x : endNode.x + endDims.width,
161+
y: getPortY(endNode, endDims, edge.end.index)
162+
};
149163

150164
const dx = endPort.x - startPort.x;
151165
const controlPoint1 = { x: startPort.x + dx * 0.5, y: startPort.y };
152166
const controlPoint2 = { x: endPort.x - dx * 0.5, y: endPort.y };
153167

168+
// Draw the connection line
154169
ctx.beginPath();
155170
ctx.moveTo(startPort.x, startPort.y);
156171
ctx.bezierCurveTo(controlPoint1.x, controlPoint1.y, controlPoint2.x, controlPoint2.y, endPort.x, endPort.y);
157172
ctx.strokeStyle = '#666';
158173
ctx.lineWidth = 2;
159174
ctx.stroke();
160175

161-
if (nodeTypes[startNode.type].outputs[edge.start.index].type === 'control') {
176+
// Get the port types
177+
const startPortType = edge.start.isInput
178+
? nodeTypes[startNode.type].inputs[edge.start.index].type
179+
: nodeTypes[startNode.type].outputs[edge.start.index].type;
180+
181+
const endPortType = edge.end.isInput
182+
? nodeTypes[endNode.type].inputs[edge.end.index].type
183+
: nodeTypes[endNode.type].outputs[edge.end.index].type;
184+
185+
// Draw arrow if either port is a control type or if it's a data connection
186+
if (startPortType === 'control' || endPortType === 'control' || startPortType === 'data' || endPortType === 'data') {
162187
this.drawArrow(ctx, endPort.x, endPort.y, Math.atan2(endPort.y - controlPoint2.y, endPort.x - controlPoint2.x));
163188
}
164189
});

0 commit comments

Comments
 (0)