More generalized version of tree

This commit is contained in:
Thomas Lovén 2020-08-21 19:57:27 +02:00
parent 8378b34263
commit b6cbc975cb
4 changed files with 245 additions and 0 deletions

View File

@ -15,6 +15,7 @@
padding: 16px;
font-family: Roboto, Noto, sans-serif;
font-size: 14px;
vertical-align: top;
}
code {
display: block;
@ -34,6 +35,8 @@
<div>
<div class="card" id="graph">
</div>
<div class="card" id="graph2">
</div>
<div class="card" id="code">
<code>
</code>

View File

@ -2,6 +2,9 @@ import {demoConfig} from "./demo-config";
import "@vanillawc/wc-codemirror";
import "./script-graph";
import "./script-graph2";
import { mdiAsterisk, mdiArrowUp, mdiArrowDown } from "@mdi/js";
let index_counter = 0;
let nodes = [];
@ -47,6 +50,70 @@ const structure_tree = (inp) => {
}
const structure_tree2 = () => {
return [
{
icon: mdiAsterisk,
clickCallback: () => console.log("Number 1"),
},
{
icon: mdiAsterisk,
clickCallback: () => console.log("Number 2"),
},
{
icon: mdiAsterisk,
clickCallback: () => console.log("Number 3"),
},
{
icon: mdiAsterisk,
clickCallback: () => console.log("Number 4"),
children: [
[
{
icon: mdiAsterisk,
clickCallback: () => console.log("Number A1"),
},
{
icon: mdiAsterisk,
clickCallback: () => console.log("Number A2"),
},
],
{
icon: mdiAsterisk,
clickCallback: () => console.log("Number B"),
end: false,
},
{
icon: mdiAsterisk,
clickCallback: () => console.log("Number B"),
},
{
icon: mdiAsterisk,
clickCallback: () => console.log("Number B"),
},
]
},
{
icon: mdiAsterisk,
clickCallback: () => console.log("Number 4"),
children: [
{
icon: mdiArrowUp,
clickCallback: () => console.log("Return"),
},
{
icon: mdiArrowDown,
clickCallback: () => console.log("Return"),
},
],
},
{
icon: mdiAsterisk,
clickCallback: () => console.log("Number 1"),
},
];
}
window.onload = () => {
let src = demoConfig;
@ -65,6 +132,11 @@ window.onload = () => {
const graph = document.createElement("script-graph");
graph.tree = structure_tree(src);
const graph2 = document.createElement("script-graph2");
graph2.tree = structure_tree2(src);
document.querySelector("#graph2").appendChild(graph2);
graph.addEventListener("selected", (ev) => {
const idx = ev.detail;
const code = document.querySelector("code");

View File

@ -50,6 +50,7 @@ class ScriptGraph extends LitElement {
* Tree Node Structure
* {
* icon: svg,
* styles:
* end: false
* children: [[TreeNode],...]
* click: callback,undefined

169
src/script-graph2.ts Normal file
View File

@ -0,0 +1,169 @@
import {
LitElement,
html,
css,
svg,
property
} from "lit-element";
const SIZE = 35;
const DIST = 20;
interface TreeNode {
icon: String;
styles: String;
end?: Boolean;
children?: (TreeNode | TreeNode[])[];
clickCallback?: any;
addCallback?: any;
}
class ScriptGraph2 extends LitElement {
@property() selected = null;
@property() tree: [TreeNode];
@property() nodeSize = SIZE;
@property() nodeSeparation = DIST;
private _draw_node(x, y, node) {
return svg`
<circle
cx="${x}"
cy="${y + this.nodeSize/2}"
r="${this.nodeSize/2}"
class="node"
@click=${node.clickCallback}
/>
<g style="pointer-events: none" transform="translate(${x - 12} ${y + this.nodeSize/2 - 12})">
<path d="${node.icon}"/>
</g>
`;
}
private _draw_connector(x1, y1, x2, y2) {
return svg`
<line
x1=${x1}
y1=${y1}
x2=${x2}
y2=${y2}
/>
`;
}
private _draw_tree(tree: TreeNode | TreeNode[]) {
if(!tree) return {svg: `Hello`, width: 0, height: 0};
if(!Array.isArray(tree)) {
let height = this.nodeSize;
let width = this.nodeSize;
let pieces = [];
if(tree.children) {
const childTrees = tree.children.map((c) =>this._draw_tree(c));
height += childTrees.reduce((a,i) => Math.max(a, i.height), 0);
width = childTrees.reduce((a,i) => a+i.width, 0) + this.nodeSeparation*(tree.children.length - 1);
const offsets = childTrees.map((sum => value => sum += value.width + this.nodeSeparation)(0));
let bottomConnectors = false;
for (const [idx, child] of childTrees.entries()) {
const x = -width/2 + (idx? offsets[idx-1] : 0) + child.width/2;
// Draw top connectors
pieces.push(this._draw_connector(
0,
this.nodeSize/2,
x,
this.nodeSize + this.nodeSeparation
));
let endNode = tree.children[idx];
if(Array.isArray(endNode)) endNode = endNode[endNode.length -1];
if(endNode.end !== false) {
// Draw bottom fill
pieces.push(this._draw_connector(
x,
this.nodeSeparation + child.height,
x,
this.nodeSeparation + height
));
// Draw bottom connectors
pieces.push(this._draw_connector(
x,
this.nodeSeparation + height,
0,
this.nodeSeparation + height + this.nodeSize/2 + this.nodeSeparation
));
bottomConnectors = true;
}
// Draw child tree
pieces.push(svg`
<g class="a" transform="translate(${x} ${this.nodeSize + this.nodeSeparation})">
${child.svg}
</g>
`);
}
if(bottomConnectors)
height += this.nodeSize + this.nodeSeparation;
}
if(tree.end !== false) {
// Draw bottom connector
pieces.push(this._draw_connector(
0,
height,
0,
height + this.nodeSeparation
));
height += this.nodeSeparation;
}
// Draw the node itself
pieces.push(this._draw_node(0, 0, tree));
return {svg: pieces, width, height};
}
// Array of trees
let pieces = [];
let height = 0;
const children = tree.map((n) => this._draw_tree(n));
const width = children.reduce((a,i) => Math.max(a, i.width), 0);
for (const [_, node] of children.entries()) {
pieces.push(svg`
<g class="b" transform="translate(0, ${height})">
${node.svg}
</g>
`);
height += node.height;
}
// TODO TEMPORARY
return {svg: pieces, width, height};
}
render() {
let tree = this._draw_tree(this.tree);
return html`
<style>
circle, line {
stroke: rgb(3, 169, 244);
stroke-width: 5;
fill: white;
}
</style>
<svg width=${tree.width + 32} height=${tree.height + 32}>
<g transform="translate(${tree.width/2 + 16} 16)">
${tree.svg}
</g>
</svg>
`;
}
}
customElements.define("script-graph2", ScriptGraph2);