Bypass the rendering pipeline for highlighting to reduce (eliminate) latency
Fixes #15
This commit is contained in:
35
Architype.js
35
Architype.js
@@ -47,19 +47,18 @@ class Architype {
|
||||
this.addDefaultEntries();
|
||||
}
|
||||
|
||||
this.observer_ = new MutationObserver(e => { this.onChange(e); });
|
||||
this.observer2_ = new MutationObserver(e => { this.snapshot(e); });
|
||||
this.observer_ = new MutationObserver(e => { this.onChange(); });
|
||||
this.observer2_ = new MutationObserver(e => { this.snapshot(false); });
|
||||
this.observe();
|
||||
|
||||
this.saveAndRender();
|
||||
|
||||
history.replaceState('first', null, '#' + btoa(this.serializedStr_));
|
||||
this.render();
|
||||
this.snapshot(true);
|
||||
}
|
||||
|
||||
observe() {
|
||||
this.observer_.observe(this.editorElem_, {
|
||||
attributes: true,
|
||||
attributeFilter: ['data-arch-refresh'],
|
||||
attributeFilter: ['data-arch-render'],
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
@@ -130,7 +129,7 @@ class Architype {
|
||||
this.editor_.clear();
|
||||
this.unserialize(ser);
|
||||
this.observe();
|
||||
this.saveAndRender();
|
||||
this.render();
|
||||
}
|
||||
|
||||
onHashChange() {
|
||||
@@ -145,19 +144,25 @@ class Architype {
|
||||
|
||||
onChange() {
|
||||
++this.generation_;
|
||||
this.saveAndRender();
|
||||
this.render();
|
||||
}
|
||||
|
||||
snapshot() {
|
||||
history.pushState(null, null, '#' + btoa(this.serializedStr_));
|
||||
this.first_ = false;
|
||||
}
|
||||
|
||||
saveAndRender() {
|
||||
snapshot(first) {
|
||||
this.serialized_ = this.serialize();
|
||||
this.startRender();
|
||||
this.serializedStr_ = JSON.stringify(this.serialized_);
|
||||
localStorage.setItem('currentState', this.serializedStr_);
|
||||
this.first_ = first || false;
|
||||
let hash = '#' + btoa(this.serializedStr_);
|
||||
if (first) {
|
||||
history.replaceState('first', null, hash);
|
||||
} else {
|
||||
history.pushState(null, null, hash);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
this.serialized_ = this.serialize();
|
||||
this.startRender();
|
||||
}
|
||||
|
||||
addDefaultEntries() {
|
||||
|
||||
@@ -196,10 +196,8 @@ class Editor extends List {
|
||||
case '`':
|
||||
if (!this.container_.parentElement.xArchObj) {
|
||||
for (let entry of this.queryEntries('.highlight')) {
|
||||
entry.getElement().classList.toggle('highlight', false);
|
||||
entry.setHighlight(false);
|
||||
}
|
||||
this.container_.setAttribute('data-arch-refresh', '');
|
||||
this.container_.setAttribute('data-arch-snapshot', '');
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
return;
|
||||
|
||||
@@ -13,6 +13,12 @@ class EditorEntryBase extends ListenUtils {
|
||||
this.elem_.xArchObj = this;
|
||||
}
|
||||
|
||||
serialize(base) {
|
||||
base.id = this.getId();
|
||||
base.highlight = this.elem_.classList.contains('highlight');
|
||||
return base;
|
||||
}
|
||||
|
||||
remove() {
|
||||
if (document.activeElement == this.elem_ ||
|
||||
document.activeElement == document.body) {
|
||||
@@ -42,11 +48,31 @@ class EditorEntryBase extends ListenUtils {
|
||||
return this.elem_.id;
|
||||
}
|
||||
|
||||
setHighlight(highlight) {
|
||||
this.elem_.classList.toggle('highlight', highlight);
|
||||
for (let elem of document.getElementsByClassName('grid-' + this.getId())) {
|
||||
elem.classList.toggle('highlight', highlight);
|
||||
}
|
||||
// Do NOT refresh: this bypasses the rendering pipeline
|
||||
this.elem_.setAttribute('data-arch-snapshot', '');
|
||||
}
|
||||
|
||||
toggleHighlight() {
|
||||
this.setHighlight(!this.elem_.classList.contains('highlight'));
|
||||
}
|
||||
|
||||
onElemFocus() {
|
||||
this.elem_.scrollIntoView({block: 'nearest'});
|
||||
}
|
||||
|
||||
onKeyDown() {
|
||||
onKeyDown(e) {
|
||||
switch (e.key) {
|
||||
case ' ':
|
||||
this.toggleHighlight();
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
afterDomAdd() {
|
||||
|
||||
@@ -29,13 +29,11 @@ class EditorGroup extends EditorEntryBase {
|
||||
}
|
||||
|
||||
serialize() {
|
||||
return {
|
||||
return super.serialize({
|
||||
type: 'group',
|
||||
id: this.getId(),
|
||||
label: this.getLabel(),
|
||||
members: this.nodes_.serialize(EditorNode),
|
||||
highlight: this.elem_.classList.contains('highlight'),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
getNodes() {
|
||||
@@ -57,10 +55,6 @@ class EditorGroup extends EditorEntryBase {
|
||||
}
|
||||
}
|
||||
|
||||
setHighlight(highlight) {
|
||||
this.elem_.classList.toggle('highlight', highlight);
|
||||
}
|
||||
|
||||
onKeyDown(e) {
|
||||
super.onKeyDown(e);
|
||||
|
||||
@@ -72,14 +66,6 @@ class EditorGroup extends EditorEntryBase {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
this.elem_.classList.toggle('highlight');
|
||||
this.elem_.setAttribute('data-arch-refresh', '');
|
||||
this.elem_.setAttribute('data-arch-snapshot', '');
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -117,10 +117,9 @@ class EditorHelp extends EditorEntryBase {
|
||||
}
|
||||
|
||||
serialize() {
|
||||
return {
|
||||
return super.serialize({
|
||||
type: 'help',
|
||||
id: this.getId(),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
static unserialize(ser) {
|
||||
|
||||
@@ -21,7 +21,7 @@ class EditorInputBase extends EditorEntryBase {
|
||||
}
|
||||
|
||||
serialize(base) {
|
||||
base.id = this.getId();
|
||||
super.serialize(base);
|
||||
base.label = this.getLabel();
|
||||
return base;
|
||||
}
|
||||
@@ -41,7 +41,7 @@ class EditorInputBase extends EditorEntryBase {
|
||||
}
|
||||
|
||||
onInput() {
|
||||
this.elem_.setAttribute('data-arch-refresh', '');
|
||||
this.elem_.setAttribute('data-arch-render', '');
|
||||
}
|
||||
|
||||
onBlur() {
|
||||
|
||||
@@ -9,25 +9,13 @@ class EditorLabel extends EditorInputBase {
|
||||
serialize() {
|
||||
return super.serialize({
|
||||
type: 'label',
|
||||
id: this.getId(),
|
||||
});
|
||||
}
|
||||
|
||||
onKeyDown(e) {
|
||||
super.onKeyDown(e);
|
||||
|
||||
switch (e.key) {
|
||||
case ' ':
|
||||
// We don't support highlighting, but stop propagation
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static unserialize(ser) {
|
||||
let label = new EditorLabel(ser.id);
|
||||
label.setLabel(ser.label);
|
||||
label.setHighlight(ser.highlight);
|
||||
return label.getElement();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,14 +26,12 @@ class EditorLink extends EditorEntryBase {
|
||||
}
|
||||
|
||||
serialize() {
|
||||
return {
|
||||
return super.serialize({
|
||||
type: 'link',
|
||||
id: this.getId(),
|
||||
label: this.getLabel(),
|
||||
from: this.getFrom().serialize(),
|
||||
to: this.getTo().serialize(),
|
||||
highlight: this.elem_.classList.contains('highlight'),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
getFrom() {
|
||||
@@ -59,10 +57,6 @@ class EditorLink extends EditorEntryBase {
|
||||
}
|
||||
}
|
||||
|
||||
setHighlight(highlight) {
|
||||
this.elem_.classList.toggle('highlight', highlight);
|
||||
}
|
||||
|
||||
flip() {
|
||||
let entries = this.nodes_.getEntries(EditorNode);
|
||||
let fromElem = entries[0].getElement();
|
||||
@@ -91,14 +85,6 @@ class EditorLink extends EditorEntryBase {
|
||||
e.preventDefault();
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
this.elem_.classList.toggle('highlight');
|
||||
this.elem_.setAttribute('data-arch-refresh', '');
|
||||
this.elem_.setAttribute('data-arch-snapshot', '');
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
this.flip();
|
||||
e.stopPropagation();
|
||||
|
||||
@@ -9,14 +9,9 @@ class EditorNode extends EditorInputBase {
|
||||
serialize() {
|
||||
return super.serialize({
|
||||
type: 'node',
|
||||
highlight: this.elem_.classList.contains('highlight'),
|
||||
});
|
||||
}
|
||||
|
||||
setHighlight(highlight) {
|
||||
this.elem_.classList.toggle('highlight', highlight);
|
||||
}
|
||||
|
||||
isSoft() {
|
||||
// Nested nodes are presumed to be references to other nodes if they exist
|
||||
for (let iter = this.elem_.parentElement; iter; iter = iter.parentElement) {
|
||||
@@ -27,20 +22,6 @@ class EditorNode extends EditorInputBase {
|
||||
return false;
|
||||
}
|
||||
|
||||
onKeyDown(e) {
|
||||
super.onKeyDown(e);
|
||||
|
||||
switch (e.key) {
|
||||
case ' ':
|
||||
this.elem_.classList.toggle('highlight');
|
||||
this.elem_.setAttribute('data-arch-snapshot', '');
|
||||
this.onInput();
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static unserialize(ser) {
|
||||
let node = new EditorNode(ser.id);
|
||||
node.setLabel(ser.label);
|
||||
|
||||
@@ -28,7 +28,6 @@ class GraphGroup {
|
||||
let group = new GraphGroup();
|
||||
group.id = item.id;
|
||||
group.label = item.label;
|
||||
group.highlight = item.highlight;
|
||||
group.nodeLabels = new Set();
|
||||
for (let member of item.members) {
|
||||
if (member.label == '') {
|
||||
|
||||
@@ -11,13 +11,11 @@ class GraphLink {
|
||||
to: to,
|
||||
id: this.id,
|
||||
label: this.label,
|
||||
highlight: this.highlight,
|
||||
});
|
||||
to.linksIn.push({
|
||||
from: from,
|
||||
id: this.id,
|
||||
label: this.label,
|
||||
highlight: this.highlight,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -35,7 +33,6 @@ class GraphLink {
|
||||
link.label = item.label;
|
||||
link.fromLabel = item.from.label;
|
||||
link.toLabel = item.to.label;
|
||||
link.highlight = item.highlight;
|
||||
if (link.fromLabel == '' || link.toLabel == '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ class GraphNode {
|
||||
node.id = item.id;
|
||||
node.label = item.label;
|
||||
node.soft = soft;
|
||||
node.highlight = item.highlight;
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
42
Grid.js
42
Grid.js
@@ -22,7 +22,7 @@ class Grid {
|
||||
break;
|
||||
|
||||
case 'arrow':
|
||||
this.drawArrow(step.id, step.pos, step.cls, step.highlight);
|
||||
this.drawArrow(step.id, step.pos, step.cls);
|
||||
break;
|
||||
|
||||
case 'graphLabel':
|
||||
@@ -30,12 +30,11 @@ class Grid {
|
||||
break;
|
||||
|
||||
case 'group':
|
||||
this.drawGroup(step.id, step.min, step.max, step.label,
|
||||
step.highlight);
|
||||
this.drawGroup(step.id, step.min, step.max, step.label);
|
||||
break;
|
||||
|
||||
case 'line':
|
||||
this.drawLine(step.id, step.pos, step.cls, step.highlight);
|
||||
this.drawLine(step.id, step.pos, step.cls);
|
||||
break;
|
||||
|
||||
case 'linkLabel':
|
||||
@@ -43,7 +42,7 @@ class Grid {
|
||||
break;
|
||||
|
||||
case 'node':
|
||||
this.drawNode(step.id, step.label, step.pos, step.highlight);
|
||||
this.drawNode(step.id, step.label, step.pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -60,14 +59,14 @@ class Grid {
|
||||
size[0] + ')))';
|
||||
}
|
||||
|
||||
drawArrow(id, pos, cls, highlight) {
|
||||
drawArrow(id, pos, cls) {
|
||||
let svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||||
this.container_.appendChild(svg);
|
||||
svg.classList.add('gridArrow');
|
||||
svg.classList.add('grid-' + id);
|
||||
this.maybeHighlight(svg, id);
|
||||
svg.style.gridColumn = pos[0] + 1;
|
||||
svg.style.gridRow = pos[1] + 1;
|
||||
svg.classList.toggle('highlight', highlight);
|
||||
|
||||
let use = document.createElementNS('http://www.w3.org/2000/svg', 'use');
|
||||
svg.appendChild(use);
|
||||
@@ -79,26 +78,29 @@ class Grid {
|
||||
this.container_.appendChild(elem);
|
||||
elem.classList.add('gridGraphLabel');
|
||||
elem.classList.add('grid-' + id);
|
||||
this.maybeHighlight(elem, id);
|
||||
elem.style.gridColumn = (min[0] + 1) + ' / ' + (max[0] + 2);
|
||||
elem.style.gridRow = (min[1] + 1) + ' / ' + (max[1] + 2);
|
||||
elem.innerText = label;
|
||||
this.toSize_.push(elem);
|
||||
}
|
||||
|
||||
drawGroup(id, min, max, label, highlight) {
|
||||
drawGroup(id, min, max, label) {
|
||||
let group = document.createElement('div');
|
||||
this.container_.appendChild(group);
|
||||
group.classList.add('gridGroup');
|
||||
group.classList.add('grid-' + id);
|
||||
this.maybeHighlight(group, id);
|
||||
group.style.gridColumn = (min[0] + 1) + ' / ' + (max[0] + 2);
|
||||
group.style.gridRow = (min[1] + 1) + ' / ' + (max[1] + 2);
|
||||
group.classList.toggle('highlight', highlight);
|
||||
|
||||
if (label != '') {
|
||||
// TODO: split this into its own draw step type
|
||||
let labelNode = document.createElement('div');
|
||||
this.container_.appendChild(labelNode);
|
||||
labelNode.classList.add('gridGroupLabel');
|
||||
labelNode.classList.add('grid-' + id);
|
||||
this.maybeHighlight(labelNode, id);
|
||||
labelNode.innerText = label;
|
||||
labelNode.style.gridColumn = (min[0] + 1) + ' / ' + (max[0] + 2);
|
||||
labelNode.style.gridRow = min[1] + 1;
|
||||
@@ -106,14 +108,14 @@ class Grid {
|
||||
}
|
||||
}
|
||||
|
||||
drawLine(id, pos, cls, highlight) {
|
||||
drawLine(id, pos, cls) {
|
||||
let svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||||
this.container_.appendChild(svg);
|
||||
svg.classList.add('gridLines');
|
||||
svg.classList.add('grid-' + id);
|
||||
this.maybeHighlight(svg, id);
|
||||
svg.style.gridColumn = pos[0] + 1;
|
||||
svg.style.gridRow = pos[1] + 1;
|
||||
svg.classList.toggle('highlight', highlight);
|
||||
|
||||
let use = document.createElementNS('http://www.w3.org/2000/svg', 'use');
|
||||
svg.appendChild(use);
|
||||
@@ -125,27 +127,35 @@ class Grid {
|
||||
this.container_.appendChild(elem);
|
||||
elem.classList.add('gridLinkLabel');
|
||||
elem.classList.add('grid-' + id);
|
||||
this.maybeHighlight(elem, id);
|
||||
elem.innerText = label;
|
||||
elem.style.gridColumn = pos[0] + 1;
|
||||
elem.style.gridRow = pos[1] + 1;
|
||||
this.toSize_.push(elem);
|
||||
}
|
||||
|
||||
drawNode(id, label, pos, highlight) {
|
||||
drawNode(id, label, pos) {
|
||||
let node = document.createElement('div');
|
||||
this.container_.appendChild(node);
|
||||
node.classList.add('gridNode');
|
||||
node.classList.add('grid-' + id);
|
||||
this.maybeHighlight(node, id);
|
||||
node.innerText = label;
|
||||
node.classList.toggle('highlight', highlight);
|
||||
node.style.gridColumn = pos[0] + 1;
|
||||
node.style.gridRow = pos[1] + 1;
|
||||
this.toSize_.push(node);
|
||||
}
|
||||
|
||||
node.addEventListener('click', () => {
|
||||
maybeHighlight(elem, id) {
|
||||
let source = document.getElementById(id);
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
elem.classList.toggle('highlight', source.classList.contains('highlight'));
|
||||
|
||||
elem.addEventListener('click', () => {
|
||||
let editorElem = document.getElementById(id);
|
||||
editorElem.classList.toggle('highlight');
|
||||
editorElem.setAttribute('data-arch-refresh', '');
|
||||
editorElem.xArchObj.toggleHighlight();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -227,7 +227,6 @@ class Layout {
|
||||
to: link.to,
|
||||
id: link.id,
|
||||
label: link.label,
|
||||
highlight: link.highlight,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -240,7 +239,6 @@ class Layout {
|
||||
for (let link of links) {
|
||||
this.links_.push(
|
||||
new LayoutLink(link.from, link.to, link.id, link.label,
|
||||
link.highlight,
|
||||
this.nodesByPos_, this.linksByPos_,
|
||||
this.labelsByPos_));
|
||||
}
|
||||
|
||||
@@ -92,7 +92,6 @@ class LayoutGroup {
|
||||
max: max,
|
||||
id: this.graphGroup_.id,
|
||||
label: this.graphGroup_.label,
|
||||
highlight: this.graphGroup_.highlight,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
class LayoutLink {
|
||||
constructor(from, to, id, label, highlight, nodesByPos, linksByPos, labelsByPos) {
|
||||
constructor(from, to, id, label, nodesByPos, linksByPos, labelsByPos) {
|
||||
this.from_ = from;
|
||||
this.to_ = to;
|
||||
this.id_ = id;
|
||||
this.label_ = label;
|
||||
this.highlight_ = highlight;
|
||||
this.nodesByPos_ = nodesByPos;
|
||||
this.linksByPos_ = linksByPos;
|
||||
this.labelsByPos_ = labelsByPos;
|
||||
@@ -229,7 +228,6 @@ class LayoutLink {
|
||||
id: this.id_,
|
||||
pos: Array.from(this.path[0]),
|
||||
cls: 's' + this.getOutPoint(this.path[0], this.path[1]),
|
||||
highlight: this.highlight_,
|
||||
});
|
||||
|
||||
for (let i = 1; i < this.path.length - 1; ++i) {
|
||||
@@ -240,7 +238,6 @@ class LayoutLink {
|
||||
id: this.id_,
|
||||
pos: Array.from(this.path[i]),
|
||||
cls: `i${inPoint}o${outPoint}`,
|
||||
highlight: this.highlight_,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -252,7 +249,6 @@ class LayoutLink {
|
||||
id: this.id_,
|
||||
pos: Array.from(this.path[this.path.length - 1]),
|
||||
cls: 's' + endInPoint,
|
||||
highlight: this.highlight_,
|
||||
});
|
||||
|
||||
steps.push({
|
||||
@@ -260,7 +256,6 @@ class LayoutLink {
|
||||
id: this.id_,
|
||||
pos: Array.from(this.path[this.path.length - 1]),
|
||||
cls: 'a' + endInPoint,
|
||||
highlight: this.highlight_,
|
||||
});
|
||||
|
||||
if (this.labelPos_) {
|
||||
|
||||
@@ -21,7 +21,6 @@ class LayoutNode {
|
||||
to: nodesByGraphNode.get(link.to),
|
||||
id: link.id,
|
||||
label: link.label,
|
||||
highlight: link.highlight,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -161,7 +160,6 @@ class LayoutNode {
|
||||
pos: this.pos,
|
||||
id: this.graphNode_.id,
|
||||
label: this.graphNode_.label,
|
||||
highlight: this.graphNode_.highlight,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,6 +141,14 @@ body {
|
||||
background-color: var(--label);
|
||||
}
|
||||
|
||||
.editor li.label.highlight {
|
||||
background: repeating-linear-gradient(
|
||||
-45deg,
|
||||
transparent 0 10px,
|
||||
rgba(255,0,0,0.3) 10px 20px
|
||||
), var(--label);
|
||||
}
|
||||
|
||||
.editor li.help {
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
@@ -260,6 +268,10 @@ body {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.gridGraphLabel.highlight {
|
||||
color: var(--focus);
|
||||
}
|
||||
|
||||
.gridGroup {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -283,14 +295,12 @@ body {
|
||||
overflow: hidden;
|
||||
overflow-wrap: anywhere;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.gridLines {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
--line-color: var(--line);
|
||||
}
|
||||
|
||||
@@ -307,7 +317,6 @@ body {
|
||||
z-index: 3;
|
||||
border-radius: 4px;
|
||||
padding: 3px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.gridArrow {
|
||||
|
||||
Reference in New Issue
Block a user