Started working on arrows
This commit is contained in:
97
projects/script.js
Normal file
97
projects/script.js
Normal file
@@ -0,0 +1,97 @@
|
||||
// ─── Configuration ────────────────────────────────────────────
|
||||
// Each pair is [sourceId, targetId].
|
||||
// Arrows go from the bottom-center of the source
|
||||
// to the top-center of the target.
|
||||
const CONNECTIONS = [
|
||||
['n0', 'n1'],
|
||||
['n1', 'n2'],
|
||||
['n2', 'n3'],
|
||||
];
|
||||
|
||||
// ─── Setup ────────────────────────────────────────────────────
|
||||
const scene = document.getElementById('body');
|
||||
const svg = document.getElementById('arrows');
|
||||
|
||||
// Create one SVG <path> per connection
|
||||
const pathEls = CONNECTIONS.map(() => {
|
||||
const p = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
||||
p.setAttribute('class', 'arrow-path');
|
||||
p.setAttribute('marker-end', 'url(#head)');
|
||||
svg.appendChild(p);
|
||||
return p;
|
||||
});
|
||||
|
||||
// ─── Core: Manhattan path between two elements ────────────────
|
||||
// r1 = bounding rect of source, r2 = bounding rect of target
|
||||
// Both rects are relative to the scene container.
|
||||
function manhattanPath(r1, r2) {
|
||||
const x1 = r1.left + r1.width / 2; // bottom-center of source
|
||||
const y1 = r1.top + r1.height + 10;
|
||||
const x2 = r2.left + r2.width / 2; // top-center of target
|
||||
const y2 = r2.top + 5; // stop 8px above target (arrowhead gap)
|
||||
|
||||
const ymid = y1 + (y2 - y1) / 2; // elbow halfway between the two
|
||||
|
||||
// M: move to source bottom
|
||||
// L: go straight down to mid-y
|
||||
// L: go horizontally to target x
|
||||
// L: go straight down to target top
|
||||
return `M ${x1} ${y1}
|
||||
L ${x1} ${ymid}
|
||||
L ${x2} ${ymid}
|
||||
L ${x2} ${y2}`;
|
||||
}
|
||||
|
||||
// ─── Redraw all arrows ────────────────────────────────────────
|
||||
function redraw() {
|
||||
const sceneRect = scene.getBoundingClientRect();
|
||||
|
||||
CONNECTIONS.forEach(([srcId, tgtId], i) => {
|
||||
const src = document.getElementById(srcId).getBoundingClientRect();
|
||||
const tgt = document.getElementById(tgtId).getBoundingClientRect();
|
||||
|
||||
// Convert from viewport coords → scene-local coords
|
||||
const r1 = {
|
||||
left: src.left - sceneRect.left,
|
||||
top: src.top - sceneRect.top,
|
||||
width: src.width,
|
||||
height: src.height,
|
||||
};
|
||||
const r2 = {
|
||||
left: tgt.left - sceneRect.left,
|
||||
top: tgt.top - sceneRect.top,
|
||||
width: tgt.width,
|
||||
height: tgt.height,
|
||||
};
|
||||
|
||||
pathEls[i].setAttribute('d', manhattanPath(r1, r2));
|
||||
});
|
||||
}
|
||||
|
||||
// ─── Drag logic ───────────────────────────────────────────────
|
||||
document.querySelectorAll('.node').forEach(node => {
|
||||
node.addEventListener('mousedown', e => {
|
||||
e.preventDefault();
|
||||
const startX = e.clientX;
|
||||
const startY = e.clientY;
|
||||
const originL = parseInt(node.style.left);
|
||||
const originT = parseInt(node.style.top);
|
||||
|
||||
const onMove = e => {
|
||||
node.style.left = Math.max(0, originL + e.clientX - startX) + 'px';
|
||||
node.style.top = Math.max(0, originT + e.clientY - startY) + 'px';
|
||||
redraw();
|
||||
};
|
||||
const onUp = () => {
|
||||
window.removeEventListener('mousemove', onMove);
|
||||
window.removeEventListener('mouseup', onUp);
|
||||
};
|
||||
|
||||
window.addEventListener('mousemove', onMove);
|
||||
window.addEventListener('mouseup', onUp);
|
||||
});
|
||||
});
|
||||
|
||||
// ─── Initial draw ─────────────────────────────────────────────
|
||||
// Wait two frames so the browser has laid out the divs
|
||||
requestAnimationFrame(() => requestAnimationFrame(redraw));
|
||||
Reference in New Issue
Block a user