Skip to content

Instantly share code, notes, and snippets.

@v1vendi
Last active April 10, 2023 05:42
Show Gist options
  • Save v1vendi/0cfbf3434d4d97993e5e48bce889d32d to your computer and use it in GitHub Desktop.
Save v1vendi/0cfbf3434d4d97993e5e48bce889d32d to your computer and use it in GitHub Desktop.
Blender-like node editor
<title>JS node editor</title>
<link rel="stylesheet" href="style.css">
<div class=node style='left:50px; top: 50px;'>
<div class='in'>input label</div>
<div class='out'>output label</div>
</div>
<svg class=link width=50 height=127 style='left:350px;top: 95px'>
<path d="M 0 0, C 50 0, 00 127, 50 127" />
</svg>
<div class=node style='left: 400px; top: 200px;'>
<div class='in'>input label</div>
<div class='out'>output label</div>
</div>
class Node {
inputs = ['input label']
outputs = ['output label']
position = {
left: '50px',
top: '50px',
}
render() {
this.div = document.createElement('div')
this.div.className = 'node'
this.inputNodes = this.inputs.map(input => {
const div = document.createElement('div')
div.className = 'in'
div.textContent = input
return div
})
this.outputNodes = this.outputs.map(output => {
const div = document.createElement('div')
div.className = 'out'
div.textContent = output
return div
})
this.div.append(...this.inputNodes, ...this.outputNodes)
return this.div
}
}
const firstNode = new Node()
const secondNode = new Node()
secondNode.position = {
left: '400px',
top: '200px',
}
class Link {
from = {
node: firstNode,
index: 0
}
to = {
node: secondNode,
index: 0,
}
render() {
const fromNode = this.from.node.outputNodes[this.from.index]
const inputNode = this.to.node.outputNode[this.to.index]
if (!fromNode.isConnected || !toNode.isConnected) {
throw 'Cannot render a link between unmounted Nodes'
}
const { right: fromX, bottom: fromY } = fromNode.getBoundingClientRect()
const { left: toX, bottom: toY } = inputNode.getBoundingClientRect()
const box = {}
}
}
function createSpline(from, to) {
const x = from.x < to.x ? from.x : to.x - 100
const width = from.x < to.x ? to.x - from.x : to.x - front.x + 100
const y = Math.min(from.y, to.y)
const height = Math.abs(from.y - to.y)
const path = `M 0 0 C ${from.x < to.x ? to.x : from.x + 100} ${from.y}, ${from.x < to.x ? 0 : to.x - 100} ${to.y}, ${to.x} ${to.y}`
document.body.innerHTML += `<svg width=${width} height=${height}><path d='${path}' /></svg>`
}
// createSpline({x: 0, y: 0}, {x: 100, y: 100})
* {
box-sizing: border-box;
}
body {
--grid-size: 20px;
--grid-first-step: calc(var(--grid-size) - 1px);
background:
repeating-linear-gradient(to right, transparent, transparent var(--grid-first-step), #333, #333 var(--grid-size)),
repeating-linear-gradient(to bottom, transparent, transparent var(--grid-first-step), #333, #333 var(--grid-size));
background-color: #444;
font-size: 14px;
font-family: sans-serif;
}
.node {
position: absolute;
background: #555a;
width: 300px;
height: 100px;
border: 1px solid #222a;
border-radius: 16px;
padding: 8px 0;
box-shadow: 0 4px 8px #0005;
}
.in, .out {
position: relative;
width: 100%;
display: flex;
padding: 4px 12px;
}
.in {
justify-content: flex-start;
}
.out {
justify-content: flex-end;
}
.in:before, .out:after {
position: absolute;
content: '';
width: 13px;
height: 13px;
border-radius: 50%;
background: white;
top: 5px;
}
.in:before {
left: -7px;
}
.out:after {
right: -7px;
}
.link {
position: absolute;
stroke: white;
stroke-width: 2px;
fill: transparent;
filter: drop-shadow(0 0 2px black) drop-shadow(0 0 4px #0003);
z-index: -1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment