This commit is contained in:
trading_peter 2025-02-12 00:11:18 +01:00
parent 30c9a9425f
commit e43b8c3b1a
14 changed files with 1677 additions and 40 deletions

27
demo/.gowebbuild.json Normal file
View File

@ -0,0 +1,27 @@
{
"Watch": {
"Path": "./src"
},
"Serve": {
"Path": "./dist"
},
"Copy": [
{
"Src": "./index.html",
"Dest": "./dist"
}
],
"ESBuild": {
"EntryPoints": [
"./src/demo.js"
],
"Outdir": "./dist",
"Sourcemap": 1,
"Format": 3,
"Splitting": true,
"Platform": 0,
"Bundle": true,
"Write": true,
"LogLevel": 3
}
}

992
demo/dist/demo.js vendored Normal file

File diff suppressed because one or more lines are too long

27
demo/dist/index.html vendored Normal file
View File

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Demo</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Source+Code+Pro&display=swap" rel="stylesheet">
<script type="module" src="./demo.js"></script>
<style>
body {
font-family: 'Source Code Pro', monospace;
color: #cccccc;
background: #1d1d1d;
font-size: 16px;
margin: 0;
}
</style>
</head>
<body>
<demo-app></demo-app>
</body>
</html>

27
demo/index.html Normal file
View File

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Demo</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Source+Code+Pro&display=swap" rel="stylesheet">
<script type="module" src="./demo.js"></script>
<style>
body {
font-family: 'Source Code Pro', monospace;
color: #cccccc;
background: #1d1d1d;
font-size: 16px;
margin: 0;
}
</style>
</head>
<body>
<demo-app></demo-app>
</body>
</html>

86
demo/src/demo.js Normal file
View File

@ -0,0 +1,86 @@
/**
@license
Copyright (c) 2022 trading_peter
This program is available under Apache License Version 2.0
*/
import '../../tp-logic-canvas.js';
import './simple-block.js';
import { LitElement, html, css } from 'lit';
class DemoApp extends LitElement {
static get styles() {
return [
css`
:host {
display: block;
padding: 20px;
}
tp-logic-canvas {
width: 1200px;
height: 800px;
background: #040a13;
}
`
];
}
render() {
const { blocks, connections } = this;
return html`
<tp-logic-canvas .connections=${connections}>
${blocks.map(block => this.renderBlock(block))}
</tp-logic-canvas>
`;
}
renderBlock(block) {
switch (block.type) {
case 'simple-block':
return html`
<simple-block .title=${block.id} .left=${block.left} .top=${block.top} .inputs=${block.inputs} .outputs=${block.outputs}></simple-block>
`;
}
}
static get properties() {
return {
blocks: { type: Array },
connections: { type: Array },
};
}
constructor() {
super();
this.blocks = [
{
id: 'block1',
type: 'simple-block',
left: 200,
top: 200,
inputs: [
{ name: 'inputA' },
{ name: 'inputB' }
],
},
{
id: 'block2',
type: 'simple-block',
left: 40,
top: 40,
outputs: [
{ name: 'outputA' },
],
}
];
this.connections = [
{ srcBlock: 'block2', srcOutput: 'outputA', destBlock: 'block1', destInput: 'inputB' }
]
}
}
window.customElements.define('demo-app', DemoApp);

43
demo/src/simple-block.js Normal file
View File

@ -0,0 +1,43 @@
/**
@license
Copyright (c) 2022 trading_peter
This program is available under Apache License Version 2.0
*/
import { TpLcBlock } from '../../tp-lc-block';
import { html, css } from 'lit';
class SimpleBlock extends TpLcBlock {
static get styles() {
return [
...TpLcBlock.blockStyles,
css`
:host {
display: block;
background: #11406b;
border-radius: 4px;
}
`
];
}
renderContent() {
const { title } = this;
return html`
${title}<br>
${title}<br>
${title}<br>
${title}<br>
${title}<br>
`;
}
static get properties() {
return {
title: { type: String },
};
}
}
window.customElements.define('simple-block', SimpleBlock);

97
package-lock.json generated Normal file
View File

@ -0,0 +1,97 @@
{
"name": "@tp/tp-element",
"version": "0.0.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@tp/tp-element",
"version": "0.0.1",
"license": "Apache-2.0",
"dependencies": {
"lit": "^2.2.2"
}
},
"node_modules/@lit/reactive-element": {
"version": "1.3.1",
"resolved": "https://verdaccio.codeblob.work/@lit%2freactive-element/-/reactive-element-1.3.1.tgz",
"integrity": "sha512-nOJARIr3pReqK3hfFCSW2Zg/kFcFsSAlIE7z4a0C9D2dPrgD/YSn3ZP2ET/rxKB65SXyG7jJbkynBRm+tGlacw==",
"license": "BSD-3-Clause"
},
"node_modules/@types/trusted-types": {
"version": "2.0.2",
"resolved": "https://verdaccio.codeblob.work/@types%2ftrusted-types/-/trusted-types-2.0.2.tgz",
"integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==",
"license": "MIT"
},
"node_modules/lit": {
"version": "2.2.2",
"resolved": "https://verdaccio.codeblob.work/lit/-/lit-2.2.2.tgz",
"integrity": "sha512-eN3+2QRHn/erxYB88AXiiRgQA6RltE9MhzySCwX+ACOxA/MLWN3VdXvcbZD9PN09zmUwlgzDvW3T84YWj2Sa0A==",
"license": "BSD-3-Clause",
"dependencies": {
"@lit/reactive-element": "^1.3.0",
"lit-element": "^3.2.0",
"lit-html": "^2.2.0"
}
},
"node_modules/lit-element": {
"version": "3.2.0",
"resolved": "https://verdaccio.codeblob.work/lit-element/-/lit-element-3.2.0.tgz",
"integrity": "sha512-HbE7yt2SnUtg5DCrWt028oaU4D5F4k/1cntAFHTkzY8ZIa8N0Wmu92PxSxucsQSOXlODFrICkQ5x/tEshKi13g==",
"license": "BSD-3-Clause",
"dependencies": {
"@lit/reactive-element": "^1.3.0",
"lit-html": "^2.2.0"
}
},
"node_modules/lit-html": {
"version": "2.2.2",
"resolved": "https://verdaccio.codeblob.work/lit-html/-/lit-html-2.2.2.tgz",
"integrity": "sha512-cJofCRXuizwyaiGt9pJjJOcauezUlSB6t87VBXsPwRhbzF29MgD8GH6fZ0BuZdXAAC02IRONZBd//VPUuU8QbQ==",
"license": "BSD-3-Clause",
"dependencies": {
"@types/trusted-types": "^2.0.2"
}
}
},
"dependencies": {
"@lit/reactive-element": {
"version": "1.3.1",
"resolved": "https://verdaccio.codeblob.work/@lit%2freactive-element/-/reactive-element-1.3.1.tgz",
"integrity": "sha512-nOJARIr3pReqK3hfFCSW2Zg/kFcFsSAlIE7z4a0C9D2dPrgD/YSn3ZP2ET/rxKB65SXyG7jJbkynBRm+tGlacw=="
},
"@types/trusted-types": {
"version": "2.0.2",
"resolved": "https://verdaccio.codeblob.work/@types%2ftrusted-types/-/trusted-types-2.0.2.tgz",
"integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg=="
},
"lit": {
"version": "2.2.2",
"resolved": "https://verdaccio.codeblob.work/lit/-/lit-2.2.2.tgz",
"integrity": "sha512-eN3+2QRHn/erxYB88AXiiRgQA6RltE9MhzySCwX+ACOxA/MLWN3VdXvcbZD9PN09zmUwlgzDvW3T84YWj2Sa0A==",
"requires": {
"@lit/reactive-element": "^1.3.0",
"lit-element": "^3.2.0",
"lit-html": "^2.2.0"
}
},
"lit-element": {
"version": "3.2.0",
"resolved": "https://verdaccio.codeblob.work/lit-element/-/lit-element-3.2.0.tgz",
"integrity": "sha512-HbE7yt2SnUtg5DCrWt028oaU4D5F4k/1cntAFHTkzY8ZIa8N0Wmu92PxSxucsQSOXlODFrICkQ5x/tEshKi13g==",
"requires": {
"@lit/reactive-element": "^1.3.0",
"lit-html": "^2.2.0"
}
},
"lit-html": {
"version": "2.2.2",
"resolved": "https://verdaccio.codeblob.work/lit-html/-/lit-html-2.2.2.tgz",
"integrity": "sha512-cJofCRXuizwyaiGt9pJjJOcauezUlSB6t87VBXsPwRhbzF29MgD8GH6fZ0BuZdXAAC02IRONZBd//VPUuU8QbQ==",
"requires": {
"@types/trusted-types": "^2.0.2"
}
}
}
}

View File

@ -1,18 +1,18 @@
{
"name": "@tp/tp-element",
"version": "0.0.1",
"name": "@tp/tp-logic-canvas",
"version": "1.0.0",
"description": "",
"main": "tp-element.js",
"main": "tp-logic-canvas.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://gitea.codeblob.work/tp-elements/tp-element.git"
"url": "https://gitea.codeblob.work/tp-elements/tp-logic-canvas.git"
},
"author": "trading_peter",
"license": "Apache-2.0",
"dependencies": {
"lit": "^2.2.0"
"lit": "^2.2.2"
}
}

View File

@ -1,35 +0,0 @@
/**
@license
Copyright (c) 2022 trading_peter
This program is available under Apache License Version 2.0
*/
import { LitElement, html, css } from 'lit';
class TpElement extends LitElement {
static get styles() {
return [
css`
:host {
display: block;
}
`
];
}
render() {
const { } = this;
return html`
`;
}
static get properties() {
return { };
}
}
window.customElements.define('tp-element', TpElement);

104
tp-lc-block.js Normal file
View File

@ -0,0 +1,104 @@
/**
@license
Copyright (c) 2022 trading_peter
This program is available under Apache License Version 2.0
*/
import './tp-lc-in.js';
import './tp-lc-out.js';
import { LitElement, html, css } from 'lit';
export class TpLcBlock extends LitElement {
static get blockStyles() {
return [
css`
:host {
display: block;
position: absolute;
padding: 10px;
}
.wrap {
display: flex;
}
.inputs, .outputs {
display: flex;
flex-direction: column;
justify-content: space-evenly;
}
.inputs {
margin-right: 20px;
}
.outputs {
margin-left: 20px;
}
tp-lc-in + tp-lc-in,
tp-lc-out + tp-lc-out {
margin-top: 10px;
}
`
];
}
render() {
const { } = this;
const inputs = this.inputs || [];
const outputs = this.outputs || [];
return html`
<div class="wrap">
${inputs.length > 0 ? html`
<div class="inputs">
${inputs.map(input => html`
<tp-lc-in .name=${input.name}></tp-lc-in>
`)}
</div>
` : null}
<div class="inner">
${this.renderContent()}
</div>
<div class="outputs">
${outputs.length > 0 ? html`
${outputs.map(input => html`
<tp-lc-out .name=${input.name}></tp-lc-out>
`)}
</div>
` : null}
</div>
`;
}
static get properties() {
return {
left: { type: Number },
top: { type: Number },
inputs: { type: Array },
output: { type: Array },
};
}
constructor() {
super();
this.inputs = [];
this.outputs = [];
}
shouldUpdate(changes) {
super.shouldUpdate(changes);
if (changes.has('left') || changes.has('top')) {
this.style.left = `${this.left || 0}px`;
this.style.top = `${this.top || 0}px`;
}
return true;
}
}
window.customElements.define('tp-lc-block', TpLcBlock);

53
tp-lc-in.js Normal file
View File

@ -0,0 +1,53 @@
/**
@license
Copyright (c) 2022 trading_peter
This program is available under Apache License Version 2.0
*/
import { LitElement, html, css } from 'lit';
class TpLcIn extends LitElement {
static get styles() {
return [
css`
:host {
display: flex;
align-items: center;
}
.circle {
border-radius: 50px;
border: 3px solid green;
width: 10px;
height: 10px;
cursor: pointer;
}
.circle:hover {
background: green;
}
label {
margin-left: 5px;
}
`
];
}
render() {
const { name } = this;
return html`
<div class="circle"></div>
<label>${name}</label>
`;
}
static get properties() {
return {
name: { type: String },
};
}
}
window.customElements.define('tp-lc-in', TpLcIn);

55
tp-lc-line.js Normal file
View File

@ -0,0 +1,55 @@
/**
@license
Copyright (c) 2022 trading_peter
This program is available under Apache License Version 2.0
*/
import { LitElement, html, css } from 'lit';
class TpLcLine extends LitElement {
static get styles() {
return [
css`
:host {
display: block;
padding: 0;
margin: 0;
height: 4px;
background: blue;
position: absolute;
line-height: 1px;
border-radius: 10px;
z-index: 99;
}
`
];
}
static get properties() {
return {
thickness: { type: Number },
};
}
constructor() {
super();
this.thickness = 4;
}
coords(x1, y1, x2, y2) {
// distance
const length = Math.sqrt(((x2-x1) * (x2-x1)) + ((y2-y1) * (y2-y1)));
// center
const cx = ((x1 + x2) / 2) - (length / 2);
const cy = ((y1 + y2) / 2) - (this.thickness / 2);
// angle
const angle = Math.atan2((y1-y2),(x1-x2))*(180/Math.PI);
// make hr
this.style.left = `${cx}px`
this.style.top = `${cy}px`;
this.style.width = `${length}px`;
this.style.transform = `rotate(${angle}deg)`;
}
}
window.customElements.define('tp-lc-line', TpLcLine);

64
tp-lc-out.js Normal file
View File

@ -0,0 +1,64 @@
/**
@license
Copyright (c) 2022 trading_peter
This program is available under Apache License Version 2.0
*/
import { LitElement, html, css } from 'lit';
class TpLcOut extends LitElement {
static get styles() {
return [
css`
:host {
display: flex;
align-items: center;
}
.circle {
border-radius: 50px;
border: 3px solid green;
width: 10px;
height: 10px;
cursor: pointer;
}
.circle:hover,
:host([isDragging]) .circle {
background: green;
}
label {
margin-right: 5px;
}
`
];
}
render() {
const { name } = this;
return html`
<label>${name}</label>
<div class="circle" @mousedown=${this.startDrag}></div>
`;
}
static get properties() {
return {
name: { type: String },
isDragging: { type: Boolean, reflect: true },
};
}
startDrag(e) {
this.isDragging = true;
window.addEventListener('mouseup', () => {
this.isDragging = false;
}, { once: true });
this.dispatchEvent(new CustomEvent('start-drag', { detail: e, bubbles: true, composed: true }));
}
}
window.customElements.define('tp-lc-out', TpLcOut);

97
tp-logic-canvas.js Normal file
View File

@ -0,0 +1,97 @@
/**
@license
Copyright (c) 2022 trading_peter
This program is available under Apache License Version 2.0
*/
import './tp-lc-line.js';
import { LitElement, html, css } from 'lit';
class TpLogicCanvas extends LitElement {
static get styles() {
return [
css`
:host {
display: block;
position: relative;
overflow: auto;
}
:host([isDragging]) {
user-select: none;
}
.block {
background-color: violet;
}
.block2 {
background-color: orange;
}
`
];
}
render() {
const { } = this;
return html`
<tp-lc-line></tp-lc-line>
<slot></slot>
`;
}
static get properties() {
return {
blocks: { type: Array },
isDragging: { type: Boolean, reflect: true },
connections: { type: Array },
};
}
constructor() {
super();
this.onDragStart = this.onDragStart.bind(this);
this.onMove = this.onMove.bind(this);
}
firstUpdated() {
this.addEventListener('start-drag', this.onDragStart);
this.addEventListener('mousemove', this.onMove);
}
shouldUpdate(changes) {
if (changes.has('connections')) {
}
return true;
}
onDragStart(e) {
this.isDragging = true;
window.addEventListener('mouseup', () => {
this.isDragging = false;
}, { once: true });
this.startCoords = this.getOffset(e.detail.target);
}
onMove(e) {
if (!this.isDragging) return;
this.shadowRoot.querySelector('tp-lc-line').coords(this.startCoords.left, this.startCoords.top, e.pageX, e.pageY);
}
getOffset(el) {
var rect = el.getBoundingClientRect();
return {
left: (rect.left - 5 - (el.offsetWidth / 2)) + window.pageXOffset,
top: (rect.top - 5 - (el.offsetHeight / 2)) + window.pageYOffset,
};
}
}
window.customElements.define('tp-logic-canvas', TpLogicCanvas);