Refactoring
This commit is contained in:
parent
d039c391e7
commit
2865f8eb07
285
src/main.js
285
src/main.js
@ -1,290 +1,7 @@
|
||||
import {demoConfig} from "./demo-config";
|
||||
import "@vanillawc/wc-codemirror";
|
||||
|
||||
import {
|
||||
LitElement,
|
||||
html,
|
||||
css,
|
||||
svg,
|
||||
property
|
||||
} from "lit-element";
|
||||
|
||||
import {
|
||||
mdiCallSplit,
|
||||
mdiAbTesting,
|
||||
mdiCheck,
|
||||
mdiClose,
|
||||
mdiChevronRight,
|
||||
mdiExclamation,
|
||||
mdiTimerOutline,
|
||||
mdiTrafficLight,
|
||||
mdiRefresh,
|
||||
mdiArrowUp,
|
||||
mdiCodeJson,
|
||||
mdiCheckBoxOutline,
|
||||
mdiCheckboxBlankOutline,
|
||||
mdiAsterisk,
|
||||
} from "@mdi/js";
|
||||
|
||||
|
||||
const SIZE = 35;
|
||||
const BORDER = 5;
|
||||
const R = SIZE/2;
|
||||
const DIST = 20;
|
||||
|
||||
const ICONS = {
|
||||
choose: mdiCallSplit,
|
||||
chooseChoice: mdiCheckBoxOutline,
|
||||
chooseDefault: mdiCheckboxBlankOutline,
|
||||
condition: mdiAbTesting,
|
||||
TRUE: mdiCheck,
|
||||
FALSE: mdiClose,
|
||||
service: mdiChevronRight,
|
||||
event: mdiExclamation,
|
||||
delay: mdiTimerOutline,
|
||||
wait: mdiTrafficLight,
|
||||
loop: mdiRefresh,
|
||||
loopReturn: mdiArrowUp,
|
||||
YAML: mdiCodeJson,
|
||||
};
|
||||
|
||||
class ScriptGraph extends LitElement {
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
tree: {},
|
||||
selected: {},
|
||||
};
|
||||
}
|
||||
|
||||
_select(idx) {
|
||||
this.selected = idx;
|
||||
const ev = new CustomEvent("selected", {detail: idx});
|
||||
this.dispatchEvent(ev);
|
||||
}
|
||||
|
||||
_draw_node(x, y, node, idx) {
|
||||
const selected = (Array.isArray(this.selected)
|
||||
? (this.selected[0] === idx)
|
||||
: false
|
||||
) || (idx === this.selected);
|
||||
return svg`
|
||||
<circle
|
||||
cx=${x}
|
||||
cy=${y + SIZE/2}
|
||||
r=${R}
|
||||
stroke-width=${BORDER}
|
||||
stroke="black"
|
||||
fill="white"
|
||||
class="${selected ? 'selected' : ''}"
|
||||
@click=${() => this._select(idx)}
|
||||
/>
|
||||
<g style="pointer-events: none">
|
||||
${node in ICONS
|
||||
? svg`
|
||||
<g transform="translate(${x-12} ${y+R-12})">
|
||||
<path d="${ICONS[node]}"/>
|
||||
</g>
|
||||
`
|
||||
: svg`
|
||||
<text
|
||||
x=${x}
|
||||
y=${y+R}
|
||||
text-anchor="middle"
|
||||
dominant-baseline="middle"
|
||||
>${node}</text>
|
||||
`}
|
||||
</g>
|
||||
`;
|
||||
}
|
||||
_draw_connector(x1, y1, x2, y2) {
|
||||
return svg`
|
||||
<line
|
||||
x1=${x1}
|
||||
y1=${y1}
|
||||
x2=${x2}
|
||||
y2=${y2}
|
||||
stroke-width=${BORDER}
|
||||
stroke="black"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
draw_tree(tree) {
|
||||
if(!tree) return {svg: svg``, width: 1, height: 1};
|
||||
let nodes = [];
|
||||
let connections = [];
|
||||
if(!Array.isArray(tree)) {
|
||||
const selected = tree.idx == this.selected;
|
||||
if(tree.type === "loop") {
|
||||
const seq = this.draw_tree(tree.sequence);
|
||||
const sep = seq.width + DIST;
|
||||
const left = -(seq.width + SIZE + DIST)/2 + SIZE/2;
|
||||
const right = left+DIST+seq.width/2 + SIZE/2;
|
||||
return {
|
||||
svg: svg`
|
||||
${this._draw_connector(
|
||||
0, R,
|
||||
left, SIZE + DIST + R
|
||||
)}
|
||||
${this._draw_connector(
|
||||
0, R,
|
||||
right, SIZE + DIST + R
|
||||
)}
|
||||
${this._draw_connector(
|
||||
right, SIZE + DIST + seq.height - R,
|
||||
0, SIZE + DIST + seq.height + DIST
|
||||
)}
|
||||
${this._draw_connector(
|
||||
left, SIZE + DIST + seq.height - R,
|
||||
0, SIZE + DIST + seq.height + DIST
|
||||
)}
|
||||
${this._draw_connector(
|
||||
left, SIZE + DIST + R,
|
||||
left, SIZE + DIST + seq.height - R
|
||||
)}
|
||||
${this._draw_node(0, 0, "loop", tree.idx)}
|
||||
${this._draw_node(left, SIZE+DIST+seq.height/2-R, "loopReturn", tree.idx)}
|
||||
<g transform="translate(${right} ${SIZE + DIST})">
|
||||
${seq.svg}
|
||||
</g>
|
||||
`,
|
||||
height: SIZE + DIST + seq.height + DIST,
|
||||
width: seq.width + SIZE,
|
||||
}
|
||||
}
|
||||
if(tree.type === "condition") {
|
||||
const sep = SIZE + DIST;
|
||||
return {
|
||||
svg: svg`
|
||||
${this._draw_connector(
|
||||
0, R,
|
||||
-sep/2, SIZE + DIST + R
|
||||
)}
|
||||
${this._draw_connector(
|
||||
0, R,
|
||||
sep/2, SIZE + DIST + R
|
||||
)}
|
||||
${this._draw_connector(
|
||||
-sep/2, SIZE + DIST + R,
|
||||
0, SIZE + DIST + SIZE + DIST,
|
||||
)}
|
||||
${this._draw_node(0, 0, "condition", tree.idx)}
|
||||
${this._draw_node(-sep/2, SIZE+DIST, "TRUE", tree.idx)}
|
||||
${this._draw_node(sep/2, SIZE+DIST, "FALSE", tree.idx)}
|
||||
`,
|
||||
height: SIZE + DIST + SIZE + DIST,
|
||||
width: SIZE + DIST + SIZE,
|
||||
}
|
||||
}
|
||||
|
||||
if(tree.type === "choose") {
|
||||
const choices = tree.choices.map(x => this.draw_tree(x));
|
||||
const maxHeight = choices.reduce((a,i) => Math.max(a, i.height), 0);
|
||||
const sep = SIZE + DIST;
|
||||
const totWidth = choices.reduce((a,i) => a+i.width, 0)+DIST*(choices.length-1);
|
||||
const offset = choices.map((sum => value => sum += value.width)(0));
|
||||
return {
|
||||
svg: svg`
|
||||
${choices.map((choice, idx) => this._draw_connector(
|
||||
0,
|
||||
R,
|
||||
-totWidth/2+idx*DIST + (idx?offset[idx-1]:0) + choice.width/2,
|
||||
SIZE + DIST + R,
|
||||
))}
|
||||
${choices.map((choice, idx) => this._draw_connector(
|
||||
-totWidth/2+idx*DIST + (idx?offset[idx-1]:0)+ choice.width/2,
|
||||
SIZE + DIST + R,
|
||||
-totWidth/2+idx*DIST + (idx?offset[idx-1]:0)+ choice.width/2,
|
||||
SIZE + DIST + R + DIST,
|
||||
))}
|
||||
${choices.map((choice, idx) => svg`
|
||||
${this._draw_connector(
|
||||
-totWidth/2+idx*DIST + (idx?offset[idx-1]:0) + choice.width/2,
|
||||
SIZE + DIST + R + DIST + choice.height,
|
||||
-totWidth/2+idx*DIST + (idx?offset[idx-1]:0) + choice.width/2,
|
||||
SIZE + DIST + R + DIST + maxHeight + DIST
|
||||
)}
|
||||
${this._draw_connector(
|
||||
-totWidth/2+idx*DIST + (idx?offset[idx-1]:0) + choice.width/2,
|
||||
SIZE + DIST + R + DIST + maxHeight + DIST,
|
||||
0,
|
||||
SIZE + DIST + R + DIST + maxHeight + DIST + SIZE + DIST
|
||||
)}
|
||||
`)}
|
||||
${this._draw_node(0, 0, tree.type, tree.idx)}
|
||||
${choices.map((choice, idx) => svg`
|
||||
<g transform="translate(
|
||||
${-totWidth/2+idx*DIST + (idx?offset[idx-1]:0) + choice.width/2}
|
||||
${SIZE + DIST + R + DIST})">
|
||||
${choice.svg}
|
||||
</g>
|
||||
`)}
|
||||
`,
|
||||
height: SIZE + DIST + R + DIST + maxHeight + DIST + SIZE + DIST,
|
||||
width: totWidth,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
svg: this._draw_node(0, 0, tree.type, tree.idx),
|
||||
height: SIZE,
|
||||
width: SIZE,
|
||||
}
|
||||
}
|
||||
let height = 0;
|
||||
let width = 0;
|
||||
for (const [idx, node] of tree.entries()) {
|
||||
const n = this.draw_tree(node);
|
||||
if(idx) {
|
||||
nodes.splice(nodes.length-1, 0, this._draw_connector(
|
||||
0,
|
||||
height-DIST,
|
||||
0,
|
||||
height+DIST
|
||||
));
|
||||
}
|
||||
nodes.push(svg`<g transform="translate(0 ${height})">${n.svg}</g>`);
|
||||
height += n.height+DIST;
|
||||
width = Math.max(width, n.width);
|
||||
}
|
||||
height = height-DIST;
|
||||
return {
|
||||
svg: svg`${nodes.map((node, idx) => node)}`,
|
||||
height,
|
||||
width,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
let processed_tree = this.draw_tree(this.tree);
|
||||
return html`
|
||||
<style>
|
||||
circle, line {
|
||||
stroke: rgb(3, 169, 244);
|
||||
}
|
||||
circle.selected {
|
||||
stroke: rgb(255, 152, 0);
|
||||
}
|
||||
svg {
|
||||
font-family: Roboto, Noto, sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
<svg width=${processed_tree.width + SIZE} height=${processed_tree.height + BORDER}>
|
||||
<g transform="translate(${processed_tree.width/2 + BORDER/2} ${BORDER/2})">
|
||||
${processed_tree.svg}
|
||||
</g>
|
||||
</svg>
|
||||
`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
customElements.define("script-graph", ScriptGraph);
|
||||
import "./script-graph";
|
||||
|
||||
let index_counter = 0;
|
||||
let nodes = [];
|
||||
|
282
src/script-graph.js
Normal file
282
src/script-graph.js
Normal file
@ -0,0 +1,282 @@
|
||||
import {
|
||||
LitElement,
|
||||
html,
|
||||
css,
|
||||
svg,
|
||||
property
|
||||
} from "lit-element";
|
||||
import {
|
||||
mdiCallSplit,
|
||||
mdiAbTesting,
|
||||
mdiCheck,
|
||||
mdiClose,
|
||||
mdiChevronRight,
|
||||
mdiExclamation,
|
||||
mdiTimerOutline,
|
||||
mdiTrafficLight,
|
||||
mdiRefresh,
|
||||
mdiArrowUp,
|
||||
mdiCodeJson,
|
||||
mdiCheckBoxOutline,
|
||||
mdiCheckboxBlankOutline,
|
||||
mdiAsterisk,
|
||||
} from "@mdi/js";
|
||||
|
||||
const SIZE = 35;
|
||||
const BORDER = 5;
|
||||
const R = SIZE/2;
|
||||
const DIST = 20;
|
||||
|
||||
const ICONS = {
|
||||
choose: mdiCallSplit,
|
||||
chooseChoice: mdiCheckBoxOutline,
|
||||
chooseDefault: mdiCheckboxBlankOutline,
|
||||
condition: mdiAbTesting,
|
||||
TRUE: mdiCheck,
|
||||
FALSE: mdiClose,
|
||||
service: mdiChevronRight,
|
||||
event: mdiExclamation,
|
||||
delay: mdiTimerOutline,
|
||||
wait: mdiTrafficLight,
|
||||
loop: mdiRefresh,
|
||||
loopReturn: mdiArrowUp,
|
||||
YAML: mdiCodeJson,
|
||||
};
|
||||
|
||||
class ScriptGraph extends LitElement {
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
tree: {},
|
||||
selected: {},
|
||||
};
|
||||
}
|
||||
|
||||
_select(idx) {
|
||||
this.selected = idx;
|
||||
const ev = new CustomEvent("selected", {detail: idx});
|
||||
this.dispatchEvent(ev);
|
||||
}
|
||||
|
||||
_draw_node(x, y, node, idx) {
|
||||
const selected = (Array.isArray(this.selected)
|
||||
? (this.selected[0] === idx)
|
||||
: false
|
||||
) || (idx === this.selected);
|
||||
return svg`
|
||||
<circle
|
||||
cx=${x}
|
||||
cy=${y + SIZE/2}
|
||||
r=${R}
|
||||
stroke-width=${BORDER}
|
||||
stroke="black"
|
||||
fill="white"
|
||||
class="${selected ? 'selected' : ''}"
|
||||
@click=${() => this._select(idx)}
|
||||
/>
|
||||
<g style="pointer-events: none">
|
||||
${node in ICONS
|
||||
? svg`
|
||||
<g transform="translate(${x-12} ${y+R-12})">
|
||||
<path d="${ICONS[node]}"/>
|
||||
</g>
|
||||
`
|
||||
: svg`
|
||||
<text
|
||||
x=${x}
|
||||
y=${y+R}
|
||||
text-anchor="middle"
|
||||
dominant-baseline="middle"
|
||||
>${node}</text>
|
||||
`}
|
||||
</g>
|
||||
`;
|
||||
}
|
||||
_draw_connector(x1, y1, x2, y2) {
|
||||
return svg`
|
||||
<line
|
||||
x1=${x1}
|
||||
y1=${y1}
|
||||
x2=${x2}
|
||||
y2=${y2}
|
||||
stroke-width=${BORDER}
|
||||
stroke="black"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
draw_tree(tree) {
|
||||
if(!tree) return {svg: svg``, width: 1, height: 1};
|
||||
let nodes = [];
|
||||
let connections = [];
|
||||
if(!Array.isArray(tree)) {
|
||||
const selected = tree.idx == this.selected;
|
||||
if(tree.type === "loop") {
|
||||
const seq = this.draw_tree(tree.sequence);
|
||||
const sep = seq.width + DIST;
|
||||
const left = -(seq.width + SIZE + DIST)/2 + SIZE/2;
|
||||
const right = left+DIST+seq.width/2 + SIZE/2;
|
||||
return {
|
||||
svg: svg`
|
||||
${this._draw_connector(
|
||||
0, R,
|
||||
left, SIZE + DIST + R
|
||||
)}
|
||||
${this._draw_connector(
|
||||
0, R,
|
||||
right, SIZE + DIST + R
|
||||
)}
|
||||
${this._draw_connector(
|
||||
right, SIZE + DIST + seq.height - R,
|
||||
0, SIZE + DIST + seq.height + DIST
|
||||
)}
|
||||
${this._draw_connector(
|
||||
left, SIZE + DIST + seq.height - R,
|
||||
0, SIZE + DIST + seq.height + DIST
|
||||
)}
|
||||
${this._draw_connector(
|
||||
left, SIZE + DIST + R,
|
||||
left, SIZE + DIST + seq.height - R
|
||||
)}
|
||||
${this._draw_node(0, 0, "loop", tree.idx)}
|
||||
${this._draw_node(left, SIZE+DIST+seq.height/2-R, "loopReturn", tree.idx)}
|
||||
<g transform="translate(${right} ${SIZE + DIST})">
|
||||
${seq.svg}
|
||||
</g>
|
||||
`,
|
||||
height: SIZE + DIST + seq.height + DIST,
|
||||
width: seq.width + SIZE,
|
||||
}
|
||||
}
|
||||
if(tree.type === "condition") {
|
||||
const sep = SIZE + DIST;
|
||||
return {
|
||||
svg: svg`
|
||||
${this._draw_connector(
|
||||
0, R,
|
||||
-sep/2, SIZE + DIST + R
|
||||
)}
|
||||
${this._draw_connector(
|
||||
0, R,
|
||||
sep/2, SIZE + DIST + R
|
||||
)}
|
||||
${this._draw_connector(
|
||||
-sep/2, SIZE + DIST + R,
|
||||
0, SIZE + DIST + SIZE + DIST,
|
||||
)}
|
||||
${this._draw_node(0, 0, "condition", tree.idx)}
|
||||
${this._draw_node(-sep/2, SIZE+DIST, "TRUE", tree.idx)}
|
||||
${this._draw_node(sep/2, SIZE+DIST, "FALSE", tree.idx)}
|
||||
`,
|
||||
height: SIZE + DIST + SIZE + DIST,
|
||||
width: SIZE + DIST + SIZE,
|
||||
}
|
||||
}
|
||||
|
||||
if(tree.type === "choose") {
|
||||
const choices = tree.choices.map(x => this.draw_tree(x));
|
||||
const maxHeight = choices.reduce((a,i) => Math.max(a, i.height), 0);
|
||||
const sep = SIZE + DIST;
|
||||
const totWidth = choices.reduce((a,i) => a+i.width, 0)+DIST*(choices.length-1);
|
||||
const offset = choices.map((sum => value => sum += value.width)(0));
|
||||
return {
|
||||
svg: svg`
|
||||
${choices.map((choice, idx) => this._draw_connector(
|
||||
0,
|
||||
R,
|
||||
-totWidth/2+idx*DIST + (idx?offset[idx-1]:0) + choice.width/2,
|
||||
SIZE + DIST + R,
|
||||
))}
|
||||
${choices.map((choice, idx) => this._draw_connector(
|
||||
-totWidth/2+idx*DIST + (idx?offset[idx-1]:0)+ choice.width/2,
|
||||
SIZE + DIST + R,
|
||||
-totWidth/2+idx*DIST + (idx?offset[idx-1]:0)+ choice.width/2,
|
||||
SIZE + DIST + R + DIST,
|
||||
))}
|
||||
${choices.map((choice, idx) => svg`
|
||||
${this._draw_connector(
|
||||
-totWidth/2+idx*DIST + (idx?offset[idx-1]:0) + choice.width/2,
|
||||
SIZE + DIST + R + DIST + choice.height,
|
||||
-totWidth/2+idx*DIST + (idx?offset[idx-1]:0) + choice.width/2,
|
||||
SIZE + DIST + R + DIST + maxHeight + DIST
|
||||
)}
|
||||
${this._draw_connector(
|
||||
-totWidth/2+idx*DIST + (idx?offset[idx-1]:0) + choice.width/2,
|
||||
SIZE + DIST + R + DIST + maxHeight + DIST,
|
||||
0,
|
||||
SIZE + DIST + R + DIST + maxHeight + DIST + SIZE + DIST
|
||||
)}
|
||||
`)}
|
||||
${this._draw_node(0, 0, tree.type, tree.idx)}
|
||||
${choices.map((choice, idx) => svg`
|
||||
<g transform="translate(
|
||||
${-totWidth/2+idx*DIST + (idx?offset[idx-1]:0) + choice.width/2}
|
||||
${SIZE + DIST + R + DIST})">
|
||||
${choice.svg}
|
||||
</g>
|
||||
`)}
|
||||
`,
|
||||
height: SIZE + DIST + R + DIST + maxHeight + DIST + SIZE + DIST,
|
||||
width: totWidth,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
svg: this._draw_node(0, 0, tree.type, tree.idx),
|
||||
height: SIZE,
|
||||
width: SIZE,
|
||||
}
|
||||
}
|
||||
let height = 0;
|
||||
let width = 0;
|
||||
for (const [idx, node] of tree.entries()) {
|
||||
const n = this.draw_tree(node);
|
||||
if(idx) {
|
||||
nodes.splice(nodes.length-1, 0, this._draw_connector(
|
||||
0,
|
||||
height-DIST,
|
||||
0,
|
||||
height+DIST
|
||||
));
|
||||
}
|
||||
nodes.push(svg`<g transform="translate(0 ${height})">${n.svg}</g>`);
|
||||
height += n.height+DIST;
|
||||
width = Math.max(width, n.width);
|
||||
}
|
||||
height = height-DIST;
|
||||
return {
|
||||
svg: svg`${nodes.map((node, idx) => node)}`,
|
||||
height,
|
||||
width,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
let processed_tree = this.draw_tree(this.tree);
|
||||
return html`
|
||||
<style>
|
||||
circle, line {
|
||||
stroke: rgb(3, 169, 244);
|
||||
}
|
||||
circle.selected {
|
||||
stroke: rgb(255, 152, 0);
|
||||
}
|
||||
svg {
|
||||
font-family: Roboto, Noto, sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
<svg width=${processed_tree.width + SIZE} height=${processed_tree.height + BORDER}>
|
||||
<g transform="translate(${processed_tree.width/2 + BORDER/2} ${BORDER/2})">
|
||||
${processed_tree.svg}
|
||||
</g>
|
||||
</svg>
|
||||
`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
customElements.define("script-graph", ScriptGraph);
|
Loading…
x
Reference in New Issue
Block a user