Files
architype/Architype.js

179 lines
4.3 KiB
JavaScript
Raw Normal View History

2019-07-03 01:42:17 +00:00
'use strict';
class Architype {
constructor(container) {
this.container_ = container;
this.container_.classList.add('architype');
// TODO: make theme selectable
this.container_.classList.add('dark');
addEventListener('resize', (e) => { this.onResize(e); });
let editorElem = document.createElement('ul');
this.container_.appendChild(editorElem);
this.editor_ = new Editor(editorElem);
this.grid_ = document.createElement('div');
this.grid_.classList.add('grid');
this.container_.appendChild(this.grid_);
2019-07-03 22:10:36 +00:00
this.generation_ = 0;
2019-07-03 22:23:41 +00:00
this.renderGeneration_ = -1;
2019-07-03 22:10:36 +00:00
this.drawGeneration_ = -1;
2019-07-03 22:23:41 +00:00
this.render_ = [];
for (let i = 0; i < navigator.hardwareConcurrency; ++i) {
let render = new Worker('render.js');
render.addEventListener('message', (e) => { this.onRender(e); });
this.render_.push(render);
}
2019-07-03 22:10:36 +00:00
2019-07-03 01:42:17 +00:00
this.unserialize(JSON.parse(localStorage.getItem('currentState')));
2019-07-03 01:51:13 +00:00
this.observer_ = new MutationObserver(e => { this.onChange(e); });
this.observer_.observe(editorElem, {
2019-07-03 01:42:17 +00:00
attributes: true,
attributeFilter: ['data-arch-value'],
2019-07-03 01:51:13 +00:00
childList: true,
2019-07-03 01:42:17 +00:00
subtree: true,
});
2019-07-03 01:51:13 +00:00
this.onChange();
2019-07-03 01:42:17 +00:00
}
serialize() {
return {
version: 1,
2019-07-03 22:23:41 +00:00
generation: ++this.generation_,
2019-07-03 01:42:17 +00:00
editor: this.editor_.serialize(),
};
}
unserialize(ser) {
if (!ser) {
return;
}
switch (ser.version) {
case 1:
2019-07-03 22:10:36 +00:00
this.generation_ = ser.generation;
2019-07-03 01:42:17 +00:00
this.editor_.unserialize(ser.editor);
break;
default:
console.log('unrecognized localStorage.currentState version', ser);
break;
}
}
2019-07-03 01:51:13 +00:00
onChange(e) {
2019-07-03 22:10:36 +00:00
this.serialized_ = this.serialize();
2019-07-03 22:23:41 +00:00
this.startRender();
2019-07-03 22:10:36 +00:00
localStorage.setItem('currentState', JSON.stringify(this.serialized_));
}
onRender(e) {
2019-07-03 22:23:41 +00:00
this.render_.push(e.target);
2019-07-03 22:10:36 +00:00
if (e.data.generation > this.drawGeneration_) {
2019-07-03 22:23:41 +00:00
// Received newer than we've drawn; redraw
this.drawGeneration_ = e.data.generation;
2019-07-03 22:10:36 +00:00
this.draw(e.data.steps);
this.fixSizes();
}
2019-07-03 22:23:41 +00:00
this.startRender();
2019-07-03 22:10:36 +00:00
}
startRender() {
2019-07-03 22:23:41 +00:00
if (this.generation_ == this.renderGeneration_) {
// Already sent this generation for rendering
return;
}
let render = this.render_.pop();
if (!render) {
// Ran out of workers
return;
}
this.renderGeneration_ = this.serialized_.generation;
render.postMessage(this.serialized_);
2019-07-03 01:42:17 +00:00
}
onResize(e) {
2019-07-03 20:00:05 +00:00
this.fixSizes();
2019-07-03 01:42:17 +00:00
}
draw(steps) {
this.grid_.innerHTML = '';
this.gridNodes_ = [];
2019-07-03 01:42:17 +00:00
for (let step of steps) {
switch (step.type) {
case 'size':
this.drawGrid(step.size);
break;
2019-07-03 01:42:17 +00:00
case 'node':
this.drawGridNode(step.label, step.pos);
break;
2019-07-03 01:42:17 +00:00
}
}
}
drawGrid(size) {
2019-07-03 01:42:17 +00:00
this.grid_.style.gridTemplateColumns =
'repeat(' + size[0] + ',1fr)';
2019-07-03 01:42:17 +00:00
this.grid_.style.gridTemplateRows =
'repeat(' + size[1] +
2019-07-03 01:42:17 +00:00
',minmax(0, calc((100vw - var(--editor-width)) / ' +
size[0] + ')))';
}
2019-07-03 01:42:17 +00:00
drawGridNode(label, pos) {
let node = document.createElement('div');
node.classList.add('gridNode');
this.grid_.appendChild(node);
node.innerText = label;
node.style.gridColumn = pos[0] + 1;
node.style.gridRow = pos[1] + 1;
2019-07-03 18:35:24 +00:00
this.gridNodes_.push(node);
2019-07-03 01:42:17 +00:00
}
fixSizes() {
for (let node of this.gridNodes_) {
node.style.fontSize = null;
for (let size = 20;
size && (node.scrollWidth > node.clientWidth ||
node.scrollHeight > node.clientHeight);
--size) {
node.style.fontSize = size + 'px';
}
}
}
2019-07-04 04:40:46 +00:00
addLine(pos, cls) {
let svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.classList.add('gridLines');
svg.style.gridColumn = pos[0] + 1;
svg.style.gridRow = pos[1] + 1;
this.grid_.appendChild(svg);
let use = document.createElementNS('http://www.w3.org/2000/svg', 'use');
svg.appendChild(use);
use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '#' + cls);
2019-07-03 01:42:17 +00:00
}
}
<!--# include file="Editor.js" -->
<!--# include file="EditorEntryBase.js" -->
<!--# include file="EditorGroup.js" -->
<!--# include file="EditorLink.js" -->
<!--# include file="EditorNode.js" -->
<!--# include file="utils.js" -->
new Architype(document.getElementById('architype'));