diff --git a/Box.js b/Box.js index e80ea43..79abaac 100644 --- a/Box.js +++ b/Box.js @@ -8,6 +8,7 @@ class Box { y; element; + content; static instances = []; @@ -23,11 +24,22 @@ class Box { this.title = title; this.x = Camera.x + 100; this.y = Camera.y + 200; - this.buildElement(); - this.updatePosition(); + + let closestDistance; + do { + closestDistance = 999999; + this.x += 50; + this.y += 50; + for (let box of Box.instances) { + if (box == this) continue; + closestDistance = Math.min(Math.abs(box.x - this.x), Math.abs(box.y - this.y), closestDistance); + } + } while (closestDistance < 50); } buildElement() { + if (this.element) return this.element; + this.element = document.createElement("div"); this.element.classList.add("box"); @@ -35,20 +47,19 @@ class Box { topBar.classList.add("boxTopBar"); this.element.appendChild(topBar); - let deleteButton = document.createElement("span"); deleteButton.classList.add("boxDeleteButton"); deleteButton.addEventListener("click", () => { this.deleteBox() }); topBar.appendChild(deleteButton); - let content = document.createElement("div"); - content.classList.add("boxContent"); - this.element.appendChild(content); + this.content = document.createElement("div"); + this.content.classList.add("boxContent"); + this.element.appendChild(this.content); let title = document.createElement("span"); title.classList.add("boxTitle"); title.innerText = this.title; - content.appendChild(title); + this.content.appendChild(title); let connectorContainer = document.createElement("div"); connectorContainer.classList.add("boxConnectorContainer"); @@ -64,22 +75,33 @@ class Box { connectorContainer.appendChild(inputConnectorContainer); connectorContainer.appendChild(outputConnectorContainer); - content.appendChild(connectorContainer); + this.content.appendChild(connectorContainer); - for (connector of this.inputs) { - inputConnectorContainer.appendChild(connector.element); + for (let connector of this.inputs) { + inputConnectorContainer.appendChild(connector.buildElement()); } - for (connector of this.outputs) { - outputConnectorContainer.appendChild(connector.element); + for (let connector of this.outputs) { + outputConnectorContainer.appendChild(connector.buildElement()); } + + this.updatePosition(); + return this.element; } updatePosition() { + if (!this.element) return; + this.element.style.left = (this.x - Camera.x) + "px"; this.element.style.top = (this.y - Camera.y) + "px"; } deleteBox() { + for (let connector of this.inputs) { + connector.disconnectBoth(); + } + for (let connector of this.outputs) { + connector.disconnectBoth(); + } this.element.parentNode.removeChild(this.element); for (let i = 0; i < Box.instances.length; i++) { if (Box.instances[i] == this) { @@ -88,10 +110,4 @@ class Box { } } } -} - -function addElement(type) { - let box = new Box("test"); - - document.getElementById("playground").appendChild(box.element); } \ No newline at end of file diff --git a/Connector.js b/Connector.js index e5af0a9..5bc1319 100644 --- a/Connector.js +++ b/Connector.js @@ -2,41 +2,91 @@ class Connector { static INPUT = 0; static OUTPUT = 1; - type; + direction; + label; + + connection; element; + circle; - constructor(type, label = "") { - this.type = type; + listeners = []; + + constructor(direction, label = "") { + this.direction = direction; this.element = ""; this.label = label; + if (this.label == "") { - switch (this.type) { + switch (this.direction) { case Connector.INPUT: this.label = "Input"; + break; case Connector.OUTPUT: this.label = "Output"; + break; } } - - this.buildElement(); } buildElement() { + if (this.element) return this.element; + this.element = document.createElement("div"); this.element.classList.add("connector"); - if (this.type == Connector.INPUT) { + if (this.direction == Connector.INPUT) { this.element.classList.add("connectorInput"); } - if (this.type == Connector.OUTPUT) { + if (this.direction == Connector.OUTPUT) { this.element.classList.add("connectorOutput"); } - let circle = document.createElement("span"); - circle.classList.add("connectorCircle"); + this.circle = document.createElement("span"); + this.circle.classList.add("connectorCircle"); let label = document.createElement("span"); + label.innerText = this.label; label.classList.add("connectorLabel"); + + this.element.appendChild(this.circle); + this.element.appendChild(label); + + this.element.addEventListener("click", () => { + ConnectionController.clickConnector(this); + }) + + return this.element; + } + + connect(connector) { + this.connection = connector; + this.element.classList.add("connected"); + } + + disconnect() { + this.connection = null; + this.element.classList.remove("connected"); + } + + disconnectBoth() { + if (!this.connection) return; + this.connection.disconnect(); + this.disconnect(); + } + + send(data) { + if (!this.connection) return; + this.connection.receive(data); + } + + receive(data) { + for (let listener of this.listeners) { + listener(data); + } + } + + addListener(listener) { + this.listeners.push(listener); } } \ No newline at end of file diff --git a/TextBox.js b/TextBox.js new file mode 100644 index 0000000..9e0cc9d --- /dev/null +++ b/TextBox.js @@ -0,0 +1,30 @@ +class TextBox extends Box { + textbox; + + constructor() { + super("Text Box"); + + let input = new Connector(Connector.INPUT); + input.addListener((data) => { + this.outputs[0].send(data); + this.textbox.value = data; + }); + + this.inputs.push(input); + this.outputs.push(new Connector(Connector.OUTPUT)); + } + + buildElement() { + if (this.element) return this.element; + super.buildElement(); + + this.textbox = document.createElement("textarea"); + this.textbox.placeholder = "Lots of text..."; + this.textbox.addEventListener("input", () => { + this.outputs[0].send(this.textbox.value); + }) + this.content.appendChild(this.textbox); + + return this.element; + } +} \ No newline at end of file diff --git a/draw-controller.js b/draw-controller.js new file mode 100644 index 0000000..2e51545 --- /dev/null +++ b/draw-controller.js @@ -0,0 +1,66 @@ +let cv, c; + +document.addEventListener("DOMContentLoaded", () => { + cv = document.getElementById("canvas"); + c = cv.getContext("2d"); + + window.requestAnimationFrame(draw); +}); + +function draw() { + + cv.width = window.innerWidth; + cv.height = window.innerHeight; + + + // draw connections + c.strokeStyle = "white"; + c.lineWidth = 3; + + for (let box of Box.instances) { + for (let input of box.inputs) { + if (!input.connection) continue; + let output = input.connection; + + let i = input.circle.getBoundingClientRect(); + let ix = i.x + i.width / 2; + let iy = i.y + i.height / 2; + + let o = output.circle.getBoundingClientRect(); + let ox = o.x + o.width / 2; + let oy = o.y + o.height / 2; + + drawConnection(ox, oy, ix, iy); + } + } + + // draw currently connecting connection + + if (ConnectionController.currentlySelectedConnector) { + let i = ConnectionController.currentlySelectedConnector.circle.getBoundingClientRect(); + let ix = i.x + i.width / 2; + let iy = i.y + i.height / 2; + + let ox = Mouse.position.x; + let oy = Mouse.position.y; + if (ConnectionController.currentlySelectedConnector.direction == Connector.OUTPUT) { + ox = ix; + oy = iy; + ix = Mouse.position.x; + iy = Mouse.position.y; + } + drawConnection(ox, oy, ix, iy); + } + + window.requestAnimationFrame(draw); +} + +function drawConnection(x1, y1, x2, y2) { + let cpDistance = Math.min(Math.max((x1 - x2), 50), 100); + c.beginPath(); + c.moveTo(x1, y1); + c.lineTo(x1 + 10, y1); + c.bezierCurveTo(x1 + cpDistance, y1, x2 - cpDistance, y2, x2 - 10, y2); + c.lineTo(x2, y2); + c.stroke(); +} \ No newline at end of file diff --git a/element-controller.js b/element-controller.js new file mode 100644 index 0000000..12a321e --- /dev/null +++ b/element-controller.js @@ -0,0 +1,54 @@ +function addElement(type) { + if (type == "TextBox") { + document.getElementById("playground").appendChild(new TextBox().buildElement()); + } +} + +class ConnectionController { + static currentlySelectedConnector = null; + + static clickConnector(connector) { + if (this.currentlySelectedConnector) { + + let a = this.currentlySelectedConnector; + let b = connector; + + if (a == b) { + this.unselect(); + return; + } + if (a.direction == b.direction) { + this.unselect(); + this.clickConnector(b); + return; + } + + if (b.connection) { + b.disconnectBoth(); + } + + a.element.classList.add("connected"); + b.element.classList.add("connected"); + + a.connect(b); + b.connect(a); + + a.element.classList.remove("connecting"); + this.currentlySelectedConnector = null; + } else { + + if (connector.connection) { + connector.disconnectBoth(); + } + + connector.element.classList.add("connecting"); + this.currentlySelectedConnector = connector; + } + } + + static unselect() { + if (!this.currentlySelectedConnector) return; + this.currentlySelectedConnector.element.classList.remove("connecting"); + this.currentlySelectedConnector = null; + } +} \ No newline at end of file diff --git a/index.html b/index.html index dde95cd..b0ae68b 100644 --- a/index.html +++ b/index.html @@ -4,9 +4,13 @@