Allow editing graph name

This commit is contained in:
Ladd Hoffman 2023-07-11 22:44:05 -05:00
parent 52aacec792
commit 8fdde5aeb4
5 changed files with 74 additions and 47 deletions

View File

@ -22,8 +22,11 @@ export class Box {
} }
} }
flex() { flex({ center = false } = {}) {
this.addClass('flex'); this.addClass('flex');
if (center) {
this.addClass('flex-center');
}
return this; return this;
} }

View File

@ -42,10 +42,11 @@ export class Button extends FormElement {
export class TextField extends FormElement { export class TextField extends FormElement {
constructor(name, form, opts) { constructor(name, form, opts) {
super(name, form, opts); super(name, form, opts);
this.flex({ center: true });
this.label = document.createElement('label'); this.label = document.createElement('label');
this.labelDiv = document.createElement('div'); this.labelDiv = document.createElement('div');
this.label.appendChild(this.labelDiv); this.label.appendChild(this.labelDiv);
this.labelDiv.innerHTML = name; this.labelDiv.innerHTML = opts.label || name;
this.input = document.createElement('input'); this.input = document.createElement('input');
this.input.disabled = !!opts.disabled; this.input.disabled = !!opts.disabled;
this.input.defaultValue = opts.defaultValue || ''; this.input.defaultValue = opts.defaultValue || '';
@ -99,9 +100,10 @@ export class FileInput extends FormElement {
this.input = document.createElement('input'); this.input = document.createElement('input');
this.input.type = 'file'; this.input.type = 'file';
this.input.accept = 'application/json'; this.input.accept = 'application/json';
// this.input.classList.add('visually-hidden') this.input.classList.add('visually-hidden');
this.label = document.createElement('label'); this.label = document.createElement('label');
this.label.innerHTML = name; this.button = form.button({ name, cb: () => this.input.click() }).lastItem;
this.label.appendChild(this.button.el);
this.label.appendChild(this.input); this.label.appendChild(this.input);
this.el.appendChild(this.label); this.el.appendChild(this.label);
} }
@ -148,7 +150,7 @@ export class Form extends Box {
} }
fileInput(opts) { fileInput(opts) {
this.items.push(new FileInput(opts.label || opts.name, this, opts)); this.items.push(new FileInput(opts.name, this, opts));
return this; return this;
} }

View File

@ -144,14 +144,14 @@ export class Vertex {
}); });
doc.remark('<h3>New Edge</h3>', { parentEl: form.el }); doc.remark('<h3>New Edge</h3>', { parentEl: form.el });
const { subForm } = form.subForm({ name: 'newEdge' }).lastItem; const newEdgeForm = doc.form({ name: 'newEdge' }).lastElement;
subForm.textField({ name: 'to' }); newEdgeForm.textField({ name: 'to' });
subForm.textField({ name: 'type' }); newEdgeForm.textField({ name: 'type' });
subForm.textField({ name: 'weight' }); newEdgeForm.textField({ name: 'weight' });
subForm.button({ newEdgeForm.submit({
name: 'Save', name: 'Save',
cb: ({ form: { value: { to, type, weight } } }) => { cb: ({ form: { value: { to, type, weight } } }) => {
graph.addEdge(type, vertex, to, weight, null); graph.setEdgeWeight(type, vertex, to, weight, null);
doc.clear(); doc.clear();
Edge.prepareEditorDocument(graph, doc, vertex.id, to); Edge.prepareEditorDocument(graph, doc, vertex.id, to);
}, },
@ -162,6 +162,7 @@ export class Vertex {
id: 'cancel', id: 'cancel',
name: 'Cancel', name: 'Cancel',
cb: () => graph.resetEditor(), cb: () => graph.resetEditor(),
parentEl: doc.el,
}); });
return doc; return doc;

View File

@ -119,22 +119,29 @@ export class WeightedDirectedGraph {
this.scene?.withSectionFlowchart(); this.scene?.withSectionFlowchart();
this.flowchart = this.scene?.lastFlowchart; this.flowchart = this.scene?.lastFlowchart;
if (this.editable) { if (this.editable) {
this.controlDoc = new Document('WDGControl', this.flowchart.box.el, { prepend: true });
this.editorDoc = new Document('WDGEditor', this.flowchart.box.el); this.editorDoc = new Document('WDGEditor', this.flowchart.box.el);
this.errorDoc = new Document('WDGErrors', this.flowchart.box.el); this.errorDoc = new Document('WDGErrors', this.flowchart.box.el);
this.controlDoc = new Document('WDGControl', this.flowchart.box.el, { prepend: true });
this.resetEditor(); this.resetEditor();
} }
return this; return this;
} }
resetEditor() { prepareControlDoc() {
this.editorDoc.clear();
this.controlDoc.clear();
Vertex.prepareEditorDocument(this, this.editorDoc);
const form = this.controlDoc.form({ name: 'controlForm' }).lastElement; const form = this.controlDoc.form({ name: 'controlForm' }).lastElement;
form.button({ const { subForm: graphPropertiesForm } = form.subForm({ name: 'graphPropsForm' }).lastItem;
name: 'Download', graphPropertiesForm.flex()
label: 'Export', .textField({ name: 'name', label: 'Graph name', defaultValue: this.name })
.submit({
name: 'Save',
cb: (({ form: { value: { name } } }) => {
this.name = name;
}),
});
const { subForm: exportImportForm } = form.subForm({ name: 'exportImportForm' }).lastItem;
exportImportForm.flex()
.button({
name: 'Export',
cb: () => { cb: () => {
const a = window.document.createElement('a'); const a = window.document.createElement('a');
const json = JSON.stringify(this.toJSON(), null, 2); const json = JSON.stringify(this.toJSON(), null, 2);
@ -144,12 +151,14 @@ export class WeightedDirectedGraph {
a.download = `wdg_${this.name}_${currentTime}.json`; a.download = `wdg_${this.name}_${currentTime}.json`;
a.click(); a.click();
}, },
}); })
form.fileInput({ .fileInput({
label: 'Import', name: 'Import',
cb: ({ input: { files: [file] } }) => { cb: ({ input: { files: [file] } }) => {
const reader = new FileReader(); const reader = new FileReader();
reader.onload = ({ target: { result: text } }) => { reader.onload = ({ target: { result: text } }) => {
console.log('imported file', { file });
// this.flowchart?.log(`%% Imported file ${file}`)
const data = JSON.parse(text); const data = JSON.parse(text);
this.fromJSON(data); this.fromJSON(data);
}; };
@ -158,6 +167,13 @@ export class WeightedDirectedGraph {
}); });
} }
resetEditor() {
this.editorDoc.clear();
this.controlDoc.clear();
this.prepareControlDoc();
Vertex.prepareEditorDocument(this, this.editorDoc);
}
addVertex(type, id, data, label, options) { addVertex(type, id, data, label, options) {
// Supports simple case of auto-incremented numeric ids // Supports simple case of auto-incremented numeric ids
if (typeof id === 'object') { if (typeof id === 'object') {
@ -220,10 +236,10 @@ export class WeightedDirectedGraph {
addEdge(type, from, to, weight, data, options) { addEdge(type, from, to, weight, data, options) {
from = from instanceof Vertex ? from : this.getVertex(from); from = from instanceof Vertex ? from : this.getVertex(from);
to = to instanceof Vertex ? to : this.getVertex(to); to = to instanceof Vertex ? to : this.getVertex(to);
const existingEdges = this.getEdges(type, from, to);
if (this.getEdge(type, from, to)) { if (this.getEdge(type, from, to)) {
throw new Error(`Edge ${type} from ${from.id} to ${to.id} already exists`); throw new Error(`Edge ${type} from ${from.id} to ${to.id} already exists`);
} }
const existingEdges = this.getEdges(null, from, to);
const edge = this.setEdgeWeight(type, from, to, weight, data, options); const edge = this.setEdgeWeight(type, from, to, weight, data, options);
from.edges.from.push(edge); from.edges.from.push(edge);
to.edges.to.push(edge); to.edges.to.push(edge);

View File

@ -26,6 +26,9 @@ a:visited {
.flex { .flex {
display: flex; display: flex;
} }
.flex-center {
align-items: center;
}
.monospace { .monospace {
font-family: monospace; font-family: monospace;
} }
@ -44,8 +47,8 @@ a:visited {
} }
.scene-controls { .scene-controls {
position: relative; position: relative;
left: 15em; left: 12em;
top: -1em; top: -0.5em;
} }
svg { svg {
width: 800px; width: 800px;
@ -61,19 +64,20 @@ td {
fill: #216262 !important; fill: #216262 !important;
} }
button { button {
margin: 5px;
margin-top: 1em;
background-color: #c6f4ff; background-color: #c6f4ff;
border-color: #b6b6b6; border-color: #b6b6b6;
border-radius: 5px; }
input {
margin: 1pt;
}
button, input[type=file] {
border-radius: 4pt;
margin: 4pt;
} }
button:disabled { button:disabled {
background-color: #2a535e; background-color: #2a535e;
color: #919191; color: #919191;
} }
label > input {
margin-left: 1em;
}
label { label {
font-family: monospace; font-family: monospace;
font-weight: bold; font-weight: bold;
@ -82,7 +86,8 @@ label {
} }
label > div { label > div {
display: inline-block; display: inline-block;
min-width: 50px; min-width: 5em;
margin-right: 4pt;
} }
table { table {
width: 100%; width: 100%;