35
Editor.js
35
Editor.js
@@ -8,6 +8,7 @@ class Editor extends List {
|
||||
[EditorNode, [0, Number.POSITIVE_INFINITY]],
|
||||
[EditorGroup, [0, Number.POSITIVE_INFINITY]],
|
||||
[EditorLink, [0, Number.POSITIVE_INFINITY]],
|
||||
[EditorTag, [0, Number.POSITIVE_INFINITY]],
|
||||
[EditorLabel, [0, 1]],
|
||||
[EditorHelp, [0, Number.POSITIVE_INFINITY]],
|
||||
]);
|
||||
@@ -143,6 +144,24 @@ class Editor extends List {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
addTagAfter(...rest) {
|
||||
if (this.mayAdd(EditorTag)) {
|
||||
return EditorTag.addAfter(this.container_, this.getSelected(),
|
||||
this.queryEntries('.highlight', EditorNode),
|
||||
...rest);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
addTagBefore(...rest) {
|
||||
if (this.mayAdd(EditorTag)) {
|
||||
return EditorTag.addBefore(this.container_, this.getSelected(),
|
||||
this.queryEntries('.highlight', EditorNode),
|
||||
...rest);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
onKeyDown(e) {
|
||||
switch (e.key) {
|
||||
@@ -202,6 +221,21 @@ class Editor extends List {
|
||||
}
|
||||
return;
|
||||
|
||||
case 't':
|
||||
case '#':
|
||||
if (this.addTagAfter()) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
return;
|
||||
|
||||
case 'T':
|
||||
if (this.addTagBefore()) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
return;
|
||||
|
||||
case '?':
|
||||
if (this.addHelpAfter()) {
|
||||
e.stopPropagation();
|
||||
@@ -233,3 +267,4 @@ class Editor extends List {
|
||||
<!--# include file="EditorLabel.js" -->
|
||||
<!--# include file="EditorLink.js" -->
|
||||
<!--# include file="EditorNode.js" -->
|
||||
<!--# include file="EditorTag.js" -->
|
||||
|
||||
@@ -104,6 +104,8 @@ class EditorEntryBase extends ListenUtils {
|
||||
return EditorLink.unserialize(ser);
|
||||
case 'node':
|
||||
return EditorNode.unserialize(ser);
|
||||
case 'tag':
|
||||
return EditorTag.unserialize(ser);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,8 +31,10 @@ class EditorHelp extends EditorEntryBase {
|
||||
this.addText('Label');
|
||||
|
||||
this.addLine();
|
||||
this.addKey('t');
|
||||
this.addText('Tag ');
|
||||
this.addKey('?');
|
||||
this.addText('Help ');
|
||||
this.addText('Help ');
|
||||
|
||||
this.addLine();
|
||||
this.addKey('⇧');
|
||||
|
||||
39
EditorTag.js
Normal file
39
EditorTag.js
Normal file
@@ -0,0 +1,39 @@
|
||||
class EditorTag extends EditorSublistBase {
|
||||
constructor(id, entries) {
|
||||
super(id, '#', 'tag', [
|
||||
[EditorNode, [1, Number.POSITIVE_INFINITY]],
|
||||
[EditorLabel, [0, 1]],
|
||||
]);
|
||||
|
||||
if (entries && entries.length) {
|
||||
for (let entry of entries) {
|
||||
this.nodes_.addNodeAfter(entry.getLabel());
|
||||
}
|
||||
} else {
|
||||
this.nodes_.addNodeAfter();
|
||||
}
|
||||
}
|
||||
|
||||
serialize() {
|
||||
return super.serialize({
|
||||
type: 'tag',
|
||||
members: this.nodes_.serialize(EditorNode),
|
||||
});
|
||||
}
|
||||
|
||||
getNodes() {
|
||||
return this.nodes_.getEntries(EditorNode);
|
||||
}
|
||||
|
||||
static unserialize(ser) {
|
||||
let tag = new EditorTag(ser.id);
|
||||
tag.nodes_.clear();
|
||||
if (ser.label != null) {
|
||||
tag.setLabel(ser.label, ser.labelObj.id);
|
||||
tag.getLabelObj().setHighlight(ser.labelObj.highlight);
|
||||
}
|
||||
tag.setHighlight(ser.highlight);
|
||||
tag.nodes_.unserialize(ser.members);
|
||||
return tag.getElement();
|
||||
}
|
||||
}
|
||||
22
Graph.js
22
Graph.js
@@ -6,12 +6,14 @@ class Graph {
|
||||
this.groups = [];
|
||||
this.links = [];
|
||||
this.nodes = [];
|
||||
this.tags = [];
|
||||
this.label = null;
|
||||
|
||||
this.processList(def.editor);
|
||||
this.removeSoftNodes();
|
||||
this.resolveLinks();
|
||||
this.resolveGroups();
|
||||
this.resolveTags();
|
||||
this.flattenNodes();
|
||||
this.setPageRank();
|
||||
this.setSubgraph();
|
||||
@@ -41,6 +43,10 @@ class Graph {
|
||||
case 'node':
|
||||
this.processNode(item, soft);
|
||||
break;
|
||||
|
||||
case 'tag':
|
||||
this.processTag(item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +85,15 @@ class Graph {
|
||||
getOrSet(this.nodesByLabel, node.label, []).push(node);
|
||||
}
|
||||
|
||||
processTag(item) {
|
||||
let tag = GraphTag.process(item);
|
||||
if (!tag) {
|
||||
return;
|
||||
}
|
||||
this.tags.push(tag);
|
||||
this.processList(item.members, true);
|
||||
}
|
||||
|
||||
removeSoftNodes() {
|
||||
for (let nodes of this.nodesByLabel.values()) {
|
||||
for (let i = nodes.length - 1; i >= 0 && nodes.length > 1; --i) {
|
||||
@@ -101,6 +116,12 @@ class Graph {
|
||||
}
|
||||
}
|
||||
|
||||
resolveTags() {
|
||||
for (let tag of this.tags) {
|
||||
tag.resolve(this.nodesByLabel);
|
||||
}
|
||||
}
|
||||
|
||||
flattenNodes() {
|
||||
for (let nodes of this.nodesByLabel.values()) {
|
||||
this.nodes.push(...nodes);
|
||||
@@ -139,3 +160,4 @@ class Graph {
|
||||
<!--# include file="GraphGroup.js" -->
|
||||
<!--# include file="GraphLink.js" -->
|
||||
<!--# include file="GraphNode.js" -->
|
||||
<!--# include file="GraphTag.js" -->
|
||||
|
||||
31
GraphTag.js
Normal file
31
GraphTag.js
Normal file
@@ -0,0 +1,31 @@
|
||||
class GraphTag {
|
||||
constructor() {
|
||||
this.nodes = [];
|
||||
}
|
||||
|
||||
resolve(nodesByLabel) {
|
||||
for (let label of this.nodeLabels.values()) {
|
||||
for (let node of nodesByLabel.get(label)) {
|
||||
this.nodes.push(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static process(item) {
|
||||
let tag = new GraphTag();
|
||||
tag.id = item.id;
|
||||
tag.label = item.label;
|
||||
tag.labelId = item.labelObj ? item.labelObj.id : null;
|
||||
tag.nodeLabels = new Set();
|
||||
for (let member of item.members) {
|
||||
if (member.label == '') {
|
||||
continue;
|
||||
}
|
||||
tag.nodeLabels.add(member.label);
|
||||
}
|
||||
if (tag.nodeLabels.size == 0) {
|
||||
return null;
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
7
Grid.js
7
Grid.js
@@ -46,7 +46,7 @@ class Grid {
|
||||
break;
|
||||
|
||||
case 'node':
|
||||
this.drawNode(step.id, step.label, step.pos);
|
||||
this.drawNode(step.id, step.label, step.pos, step.tags);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -134,7 +134,7 @@ class Grid {
|
||||
this.linkToEditor(elem, id, true);
|
||||
}
|
||||
|
||||
drawNode(id, label, pos) {
|
||||
drawNode(id, label, pos, tags) {
|
||||
let node = document.createElement('div');
|
||||
this.container_.appendChild(node);
|
||||
node.classList.add('gridNode');
|
||||
@@ -142,6 +142,9 @@ class Grid {
|
||||
node.innerText = label;
|
||||
node.style.gridColumn = pos[0] + 1;
|
||||
node.style.gridRow = pos[1] + 1;
|
||||
for (let tag of tags) {
|
||||
node.classList.add('tag' + tag);
|
||||
}
|
||||
this.linkToEditor(node, id, true);
|
||||
}
|
||||
|
||||
|
||||
11
Layout.js
11
Layout.js
@@ -12,6 +12,7 @@ class Layout {
|
||||
this.setInitialPositions();
|
||||
this.resolveGroups();
|
||||
this.resolveLinks();
|
||||
this.resolveTags();
|
||||
this.setAffinity();
|
||||
while (this.iterate());
|
||||
this.addGroupPos();
|
||||
@@ -74,6 +75,15 @@ class Layout {
|
||||
}
|
||||
}
|
||||
|
||||
resolveTags() {
|
||||
this.tags_ = [];
|
||||
for (let i = 0; i < this.graph_.tags.length; ++i) {
|
||||
let tag = this.graph_.tags[i];
|
||||
let nodes = this.nodesFromGraphNodes(tag.nodes);
|
||||
this.tags_.push(new LayoutTag(tag, nodes, i));
|
||||
}
|
||||
}
|
||||
|
||||
setAffinity() {
|
||||
for (let node of this.nodes_) {
|
||||
node.setAffinity(this.nodesByGraphNode_);
|
||||
@@ -298,3 +308,4 @@ class Layout {
|
||||
<!--# include file="LayoutGroup.js" -->
|
||||
<!--# include file="LayoutLink.js" -->
|
||||
<!--# include file="LayoutNode.js" -->
|
||||
<!--# include file="LayoutTag.js" -->
|
||||
|
||||
@@ -5,6 +5,7 @@ class LayoutNode {
|
||||
this.pos = pos;
|
||||
|
||||
this.groups = new Set();
|
||||
this.tags = new Set();
|
||||
this.affinity_ = [];
|
||||
|
||||
this.label = this.graphNode_.label;
|
||||
@@ -161,6 +162,7 @@ class LayoutNode {
|
||||
pos: this.pos,
|
||||
id: this.graphNode_.id,
|
||||
label: this.graphNode_.label,
|
||||
tags: Array.from(this.tags),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
20
LayoutTag.js
Normal file
20
LayoutTag.js
Normal file
@@ -0,0 +1,20 @@
|
||||
class LayoutTag {
|
||||
constructor(graphTag, nodes, idx) {
|
||||
this.graphTag_ = graphTag;
|
||||
this.nodes_ = new Set(nodes);
|
||||
this.idx_ = idx;
|
||||
|
||||
this.label = this.graphTag_ ? this.graphTag_.label : null;
|
||||
|
||||
const NUM_TAGS = 6;
|
||||
|
||||
for (let node of this.nodes_) {
|
||||
node.tags.add(this.idx_ % NUM_TAGS);
|
||||
}
|
||||
}
|
||||
|
||||
getSteps() {
|
||||
let steps = [];
|
||||
return steps;
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,13 @@
|
||||
--input: rgba(0,0,0,0.1);
|
||||
--input-focus: rgba(255,0,0,0.2);
|
||||
--line: #000000;
|
||||
|
||||
--tag0: hsl(180, 100%, 75%);
|
||||
--tag1: hsl(240, 100%, 75%);
|
||||
--tag2: hsl(300, 100%, 75%);
|
||||
--tag3: hsl( 0, 100%, 75%);
|
||||
--tag4: hsl( 60, 100%, 75%);
|
||||
--tag5: hsl(120, 100%, 75%);
|
||||
}
|
||||
|
||||
.theme-dark {
|
||||
@@ -40,6 +47,13 @@
|
||||
--input: rgba(255,255,255,0.2);
|
||||
--input-focus: rgba(255,0,0,0.2);
|
||||
--line: #ffffff;
|
||||
|
||||
--tag0: hsl(180, 100%, 25%);
|
||||
--tag1: hsl(240, 100%, 25%);
|
||||
--tag2: hsl(300, 100%, 25%);
|
||||
--tag3: hsl( 0, 100%, 25%);
|
||||
--tag4: hsl( 60, 100%, 25%);
|
||||
--tag5: hsl(120, 100%, 25%);
|
||||
}
|
||||
|
||||
:root {
|
||||
@@ -256,6 +270,70 @@ body {
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.gridNode.tag0 {
|
||||
background: var(--tag0);
|
||||
}
|
||||
|
||||
.gridNode.tag1 {
|
||||
background: var(--tag1);
|
||||
}
|
||||
|
||||
.gridNode.tag2 {
|
||||
background: var(--tag2);
|
||||
}
|
||||
|
||||
.gridNode.tag3 {
|
||||
background: var(--tag3);
|
||||
}
|
||||
|
||||
.gridNode.tag4 {
|
||||
background: var(--tag4);
|
||||
}
|
||||
|
||||
.gridNode.tag5 {
|
||||
background: var(--tag5);
|
||||
}
|
||||
|
||||
.gridNode.highlight {
|
||||
border-color: var(--focus);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.gridGraphLabel {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
font-size: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.gridGraphLabel.highlight {
|
||||
color: var(--focus);
|
||||
}
|
||||
|
||||
.gridGroup {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--group-background);
|
||||
justify-content: flex-start;
|
||||
border: 1px dashed var(--line);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.gridGroup.highlight {
|
||||
border-color: var(--focus);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.gridGroupLabel {
|
||||
max-width: 90%;
|
||||
max-height: 90%;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
overflow: hidden;
|
||||
overflow-wrap: anywhere;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.gridNode.highlight {
|
||||
border-color: var(--focus);
|
||||
border-width: 3px;
|
||||
|
||||
Reference in New Issue
Block a user