Tag object

Fixes #1
This commit is contained in:
Ian Gulliver
2019-07-14 20:44:07 +00:00
parent d47cec70c1
commit 07e26a2a6c
11 changed files with 248 additions and 3 deletions

View File

@@ -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" -->

View File

@@ -104,6 +104,8 @@ class EditorEntryBase extends ListenUtils {
return EditorLink.unserialize(ser);
case 'node':
return EditorNode.unserialize(ser);
case 'tag':
return EditorTag.unserialize(ser);
}
}
}

View File

@@ -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
View 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();
}
}

View File

@@ -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
View 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;
}
}

View File

@@ -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);
}

View File

@@ -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" -->

View File

@@ -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
View 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;
}
}

View File

@@ -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;