Files
Ayabusa-new-website/projects/script.js

119 lines
4.1 KiB
JavaScript

// ─── Configuration ────────────────────────────────────────────
// Each pair is [sourceId, targetId].
// Arrows go from the bottom-center of the source
// to the top-center of the target.
const CONNECTIONS = [
['proj', 'fich'],
['proj', 'hack'],
['fich', 'rust'],
['rust', 'alac'],
['hack', 'alac'],
['alac', 'mine'],
];
// ─── 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) {
let x1 = r1.left + r1.width / 2; // bottom-center of source
const y1 = r1.top + r1.height + 10;
let x2 = r2.left + r2.width / 2; // top-center of target
const y2 = r2.top + 5; // stop 8px above target (arrowhead gap)
let shift = 5;
if (x1 > x2) {
x1 -= shift;
x2 += shift;
} else if (x2 > x1) {
x1 += shift;
x2 -= shift;
}
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));
if (tgt.left > src.left) {
pathEls[i].style.stroke = "#008000";
} else if (tgt.left < src.left){
pathEls[i].style.stroke = "#ff0000";
} else {
pathEls[i].style.stroke = "#0000ff";
}
});
}
// ─── 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 ─────────────────────────────────────────────
window.addEventListener('load', redraw);
// also redraws if anything inside the scene changes size
new ResizeObserver(redraw).observe(scene);