mirror of https://github.com/lgc-4/DataTools3.git
feature dump, i don't wanna write individual commits for this. not yet.
This commit is contained in:
parent
3faca12367
commit
750676cb23
52
Box.js
52
Box.js
|
@ -8,6 +8,7 @@ class Box {
|
||||||
y;
|
y;
|
||||||
|
|
||||||
element;
|
element;
|
||||||
|
content;
|
||||||
|
|
||||||
static instances = [];
|
static instances = [];
|
||||||
|
|
||||||
|
@ -23,11 +24,22 @@ class Box {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.x = Camera.x + 100;
|
this.x = Camera.x + 100;
|
||||||
this.y = Camera.y + 200;
|
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() {
|
buildElement() {
|
||||||
|
if (this.element) return this.element;
|
||||||
|
|
||||||
this.element = document.createElement("div");
|
this.element = document.createElement("div");
|
||||||
this.element.classList.add("box");
|
this.element.classList.add("box");
|
||||||
|
|
||||||
|
@ -35,20 +47,19 @@ class Box {
|
||||||
topBar.classList.add("boxTopBar");
|
topBar.classList.add("boxTopBar");
|
||||||
this.element.appendChild(topBar);
|
this.element.appendChild(topBar);
|
||||||
|
|
||||||
|
|
||||||
let deleteButton = document.createElement("span");
|
let deleteButton = document.createElement("span");
|
||||||
deleteButton.classList.add("boxDeleteButton");
|
deleteButton.classList.add("boxDeleteButton");
|
||||||
deleteButton.addEventListener("click", () => { this.deleteBox() });
|
deleteButton.addEventListener("click", () => { this.deleteBox() });
|
||||||
topBar.appendChild(deleteButton);
|
topBar.appendChild(deleteButton);
|
||||||
|
|
||||||
let content = document.createElement("div");
|
this.content = document.createElement("div");
|
||||||
content.classList.add("boxContent");
|
this.content.classList.add("boxContent");
|
||||||
this.element.appendChild(content);
|
this.element.appendChild(this.content);
|
||||||
|
|
||||||
let title = document.createElement("span");
|
let title = document.createElement("span");
|
||||||
title.classList.add("boxTitle");
|
title.classList.add("boxTitle");
|
||||||
title.innerText = this.title;
|
title.innerText = this.title;
|
||||||
content.appendChild(title);
|
this.content.appendChild(title);
|
||||||
|
|
||||||
let connectorContainer = document.createElement("div");
|
let connectorContainer = document.createElement("div");
|
||||||
connectorContainer.classList.add("boxConnectorContainer");
|
connectorContainer.classList.add("boxConnectorContainer");
|
||||||
|
@ -64,22 +75,33 @@ class Box {
|
||||||
connectorContainer.appendChild(inputConnectorContainer);
|
connectorContainer.appendChild(inputConnectorContainer);
|
||||||
connectorContainer.appendChild(outputConnectorContainer);
|
connectorContainer.appendChild(outputConnectorContainer);
|
||||||
|
|
||||||
content.appendChild(connectorContainer);
|
this.content.appendChild(connectorContainer);
|
||||||
|
|
||||||
for (connector of this.inputs) {
|
for (let connector of this.inputs) {
|
||||||
inputConnectorContainer.appendChild(connector.element);
|
inputConnectorContainer.appendChild(connector.buildElement());
|
||||||
}
|
}
|
||||||
for (connector of this.outputs) {
|
for (let connector of this.outputs) {
|
||||||
outputConnectorContainer.appendChild(connector.element);
|
outputConnectorContainer.appendChild(connector.buildElement());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.updatePosition();
|
||||||
|
return this.element;
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePosition() {
|
updatePosition() {
|
||||||
|
if (!this.element) return;
|
||||||
|
|
||||||
this.element.style.left = (this.x - Camera.x) + "px";
|
this.element.style.left = (this.x - Camera.x) + "px";
|
||||||
this.element.style.top = (this.y - Camera.y) + "px";
|
this.element.style.top = (this.y - Camera.y) + "px";
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteBox() {
|
deleteBox() {
|
||||||
|
for (let connector of this.inputs) {
|
||||||
|
connector.disconnectBoth();
|
||||||
|
}
|
||||||
|
for (let connector of this.outputs) {
|
||||||
|
connector.disconnectBoth();
|
||||||
|
}
|
||||||
this.element.parentNode.removeChild(this.element);
|
this.element.parentNode.removeChild(this.element);
|
||||||
for (let i = 0; i < Box.instances.length; i++) {
|
for (let i = 0; i < Box.instances.length; i++) {
|
||||||
if (Box.instances[i] == this) {
|
if (Box.instances[i] == this) {
|
||||||
|
@ -89,9 +111,3 @@ class Box {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addElement(type) {
|
|
||||||
let box = new Box("test");
|
|
||||||
|
|
||||||
document.getElementById("playground").appendChild(box.element);
|
|
||||||
}
|
|
70
Connector.js
70
Connector.js
|
@ -2,41 +2,91 @@ class Connector {
|
||||||
static INPUT = 0;
|
static INPUT = 0;
|
||||||
static OUTPUT = 1;
|
static OUTPUT = 1;
|
||||||
|
|
||||||
type;
|
direction;
|
||||||
|
label;
|
||||||
|
|
||||||
|
connection;
|
||||||
|
|
||||||
element;
|
element;
|
||||||
|
circle;
|
||||||
|
|
||||||
constructor(type, label = "") {
|
listeners = [];
|
||||||
this.type = type;
|
|
||||||
|
constructor(direction, label = "") {
|
||||||
|
this.direction = direction;
|
||||||
this.element = "";
|
this.element = "";
|
||||||
this.label = label;
|
this.label = label;
|
||||||
|
|
||||||
if (this.label == "") {
|
if (this.label == "") {
|
||||||
switch (this.type) {
|
switch (this.direction) {
|
||||||
case Connector.INPUT:
|
case Connector.INPUT:
|
||||||
this.label = "Input";
|
this.label = "Input";
|
||||||
|
break;
|
||||||
case Connector.OUTPUT:
|
case Connector.OUTPUT:
|
||||||
this.label = "Output";
|
this.label = "Output";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.buildElement();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buildElement() {
|
buildElement() {
|
||||||
|
if (this.element) return this.element;
|
||||||
|
|
||||||
this.element = document.createElement("div");
|
this.element = document.createElement("div");
|
||||||
this.element.classList.add("connector");
|
this.element.classList.add("connector");
|
||||||
|
|
||||||
if (this.type == Connector.INPUT) {
|
if (this.direction == Connector.INPUT) {
|
||||||
this.element.classList.add("connectorInput");
|
this.element.classList.add("connectorInput");
|
||||||
}
|
}
|
||||||
if (this.type == Connector.OUTPUT) {
|
if (this.direction == Connector.OUTPUT) {
|
||||||
this.element.classList.add("connectorOutput");
|
this.element.classList.add("connectorOutput");
|
||||||
}
|
}
|
||||||
|
|
||||||
let circle = document.createElement("span");
|
this.circle = document.createElement("span");
|
||||||
circle.classList.add("connectorCircle");
|
this.circle.classList.add("connectorCircle");
|
||||||
|
|
||||||
let label = document.createElement("span");
|
let label = document.createElement("span");
|
||||||
|
label.innerText = this.label;
|
||||||
label.classList.add("connectorLabel");
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,9 +4,13 @@
|
||||||
<title>DataTools</title>
|
<title>DataTools</title>
|
||||||
<link rel="stylesheet" type="text/css" href="style.css">
|
<link rel="stylesheet" type="text/css" href="style.css">
|
||||||
<script src="Camera.js"></script>
|
<script src="Camera.js"></script>
|
||||||
|
<script src="Connector.js"></script>
|
||||||
<script src="Box.js"></script>
|
<script src="Box.js"></script>
|
||||||
|
<script src="TextBox.js"></script>
|
||||||
<script src="menu.js"></script>
|
<script src="menu.js"></script>
|
||||||
<script src="input-controller.js"></script>
|
<script src="input-controller.js"></script>
|
||||||
|
<script src="element-controller.js"></script>
|
||||||
|
<script src="draw-controller.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<canvas id="canvas"></canvas>
|
<canvas id="canvas"></canvas>
|
||||||
|
|
|
@ -2,9 +2,22 @@ let draggingBox = null;
|
||||||
let draggingCamera = false;
|
let draggingCamera = false;
|
||||||
let lastMousePos = {x: 0, y: 0};
|
let lastMousePos = {x: 0, y: 0};
|
||||||
|
|
||||||
|
class Mouse {
|
||||||
|
static position = {x: 0, y: 0};
|
||||||
|
static lastPosition = {x: 0, y: 0};
|
||||||
|
|
||||||
|
static updatePosition(x, y) {
|
||||||
|
this.lastPosition = this.position;
|
||||||
|
this.position = {x: x, y: y};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDelta() {
|
||||||
|
return {x : this.position.x - this.lastPosition.x, y : this.position.y - this.lastPosition.y};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener("mousedown", (e) => {
|
document.addEventListener("mousedown", (e) => {
|
||||||
let x = e.clientX;
|
Mouse.updatePosition(e.clientX, e.clientY);
|
||||||
let y = e.clientY;
|
|
||||||
|
|
||||||
if (e.button == 0) {
|
if (e.button == 0) {
|
||||||
if (e.target.classList.contains("boxDeleteButton")) return;
|
if (e.target.classList.contains("boxDeleteButton")) return;
|
||||||
|
@ -12,9 +25,10 @@ document.addEventListener("mousedown", (e) => {
|
||||||
let topBarRect = box.element.getElementsByClassName("boxTopBar")[0].getBoundingClientRect();
|
let topBarRect = box.element.getElementsByClassName("boxTopBar")[0].getBoundingClientRect();
|
||||||
box.element.classList.remove("dragging");
|
box.element.classList.remove("dragging");
|
||||||
|
|
||||||
if (isPointInRect(x, y, topBarRect.x, topBarRect.y, topBarRect.width, topBarRect.height)) {
|
if (isPointInRect(Mouse.position.x, Mouse.position.y, topBarRect.x, topBarRect.y, topBarRect.width, topBarRect.height)) {
|
||||||
draggingBox = box;
|
draggingBox = box;
|
||||||
box.element.classList.add("dragging");
|
box.element.classList.add("dragging");
|
||||||
|
e.preventDefault();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,16 +47,18 @@ document.addEventListener("mouseup", (e) => {
|
||||||
if (e.button == 1 || e.button == 2) {
|
if (e.button == 1 || e.button == 2) {
|
||||||
draggingCamera = false;
|
draggingCamera = false;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
document.addEventListener("mousemove", (e) => {
|
document.addEventListener("mousemove", (e) => {
|
||||||
|
Mouse.updatePosition(e.clientX, e.clientY);
|
||||||
|
|
||||||
let delta = {x : e.clientX - lastMousePos.x, y : e.clientY - lastMousePos.y};
|
let delta = Mouse.getDelta();
|
||||||
|
|
||||||
if (draggingBox != null) {
|
if (draggingBox != null) {
|
||||||
draggingBox.x += delta.x;
|
draggingBox.x += delta.x;
|
||||||
draggingBox.y += delta.y;
|
draggingBox.y += delta.y;
|
||||||
draggingBox.updatePosition();
|
draggingBox.updatePosition();
|
||||||
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (draggingCamera) {
|
if (draggingCamera) {
|
||||||
|
@ -53,10 +69,10 @@ document.addEventListener("mousemove", (e) => {
|
||||||
|
|
||||||
document.getElementById("canvas").style.backgroundPosition = (-Camera.x) + "px " + (-Camera.y) + "px";
|
document.getElementById("canvas").style.backgroundPosition = (-Camera.x) + "px " + (-Camera.y) + "px";
|
||||||
|
|
||||||
}
|
e.preventDefault();
|
||||||
|
|
||||||
lastMousePos = {x: e.clientX, y: e.clientY};
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
function isPointInRect(px, py, rx, ry, rw, rh) {
|
function isPointInRect(px, py, rx, ry, rw, rh) {
|
||||||
return px >= rx && px <= rx + rw && py >= ry && py <= ry + rh;
|
return px >= rx && px <= rx + rw && py >= ry && py <= ry + rh;
|
||||||
|
|
50
style.css
50
style.css
|
@ -125,3 +125,53 @@ textarea {
|
||||||
font-family: Monospace;
|
font-family: Monospace;
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.boxConnectorContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-left: -20px;
|
||||||
|
margin-right: -20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connector {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
--connectorCircleSize: 25px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connectorCircle {
|
||||||
|
display: block;
|
||||||
|
width: var(--connectorCircleSize);
|
||||||
|
height: var(--connectorCircleSize);
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 3px solid var(--bg);
|
||||||
|
border-radius: var(--connectorCircleSize);
|
||||||
|
background-color: var(--connectorCircleColor);
|
||||||
|
transition: scale 0.05s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connector.connectorInput {
|
||||||
|
flex-direction: row;
|
||||||
|
--connectorCircleColor: var(--blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.connector.connectorOutput {
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
--connectorCircleColor: var(--yellow);
|
||||||
|
}
|
||||||
|
|
||||||
|
.connector:hover .connectorCircle {
|
||||||
|
scale: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connector.connecting {
|
||||||
|
--connectorCircleColor: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connector.connected .connectorCircle {
|
||||||
|
border-color: white;
|
||||||
|
}
|
Loading…
Reference in New Issue