💥 Graph.deserialize is now async

This commit is contained in:
2019-06-26 14:19:58 +02:00
parent 404cf14aee
commit 713a900ca6
6 changed files with 101 additions and 42 deletions

View File

@@ -18,17 +18,19 @@ export default class Graph {
})); }));
} }
static deserialize(nodes) { static async deserialize(nodes) {
const graph = new Graph(); const graph = new Graph();
graph.nodes = createNodes(nodes); graph.nodes = await createNodes(nodes);
for (let {node} of graph.nodes) { for (let {node} of graph.nodes) {
node.subject.on('running', (isRunning) => { node.subject.on('running', (isRunning) => {
graph.__nodesActive += isRunning ? 1 : -1; graph.__nodesActive += isRunning ? 1 : -1;
clearTimeout(graph.__nodesActiveDebounce); clearTimeout(graph.__nodesActiveDebounce);
graph.__nodesActiveDebounce = setTimeout(() => { graph.__nodesActiveDebounce = setTimeout(() => {
if (graph.__nodesActive > 0) { if (graph.__nodesActive > 0) {
console.log('running');
graph.subject.next('running'); graph.subject.next('running');
} else { } else {
console.log('stopped');
graph.subject.next('stopped'); graph.subject.next('stopped');
} }
}, 16); }, 16);
@@ -65,31 +67,31 @@ export default class Graph {
export const createNode = ({name, options, id}) => { export const createNode = async ({name, options, id}) => {
try { try {
const node = new nodes[name](options); const node = new nodes[name](options);
node.deserialize({id, options}); await node.deserialize({id, options});
return node; return node;
} catch (err) { } catch (err) {
console.error('Failed to create node', name, err) console.error('Failed to create node', name, err)
} }
} }
export const createNodes = (nodes) => { export const createNodes = async (nodes) => {
nodes = nodes.map(({node, x, y}) => { nodes = (await Promise.all(nodes.map(async ({node, x, y}) => {
const nodeInstance = createNode(node); const nodeInstance = await createNode(node);
return ({ return ({
node: nodeInstance, node: nodeInstance,
x, y, x, y,
connect(outputs) { async connect(outputs) {
try { try {
nodeInstance.reconnect(node, outputs); await nodeInstance.reconnect(node, outputs);
} catch(err) { } catch(err) {
console.error('Can\'t recoonect', nodeInstance, err); console.error('Can\'t recoonect', nodeInstance, err);
} }
} }
}); });
}).filter(({node}) => node); }))).filter(({node}) => node);
const outputsById = nodes const outputsById = nodes
.map(({node}) => Object.values(node.out.__values)) .map(({node}) => Object.values(node.out.__values))
@@ -99,8 +101,8 @@ export const createNode = ({name, options, id}) => {
return acc; return acc;
}, {}); }, {});
return nodes.map(({node, x, y, connect}) => { return await Promise.all(nodes.map(async ({node, x, y, connect}) => {
connect(outputsById); await connect(outputsById);
return {node,x,y}; return {node,x,y};
}) }))
} }

View File

@@ -61,27 +61,14 @@ export default class Resize extends Canvas2d {
/** /**
* *
* @param {{name: string, url: string, fontface: FontFace}} font * @param {{name: string, url: string, fontface: FontFace, type: 'font'}} font
*/ */
async loadFont(font) { async loadFont(font) {
if (typeof font === 'string') { if (typeof font === 'string') {
return font return font;
} else if (!font) { } else if (!font) {
return; return;
} } else {
if (font.name && !font.url && !font.fontface) {
return name;
}
if (font.name && font.url && isEmpty(font.fontface)) {
font.fontface = new FontFace(font.name, font.url);
}
if (font.fontface) {
await font.fontface.load();
if (!document.fonts.has(font.fontface)) {
await document.fonts.add(font.fontface)
}
return font.name; return font.name;
} }
} }
@@ -91,6 +78,7 @@ export default class Resize extends Canvas2d {
canvas.height = height; canvas.height = height;
ctx.font = `${fontStyle} ${fontSize}px "${(await this.loadFont(font)) || ''}"`; ctx.font = `${fontStyle} ${fontSize}px "${(await this.loadFont(font)) || ''}"`;
// ctx.font = `${fontStyle} ${fontSize}px "Arial"`;
ctx.fillStyle = color; ctx.fillStyle = color;
ctx.textAlign = textAlign; ctx.textAlign = textAlign;
const x = textAlign === 'center' ? canvas.width /2 : const x = textAlign === 'center' ? canvas.width /2 :

View File

@@ -20,11 +20,9 @@ export default class Node {
__update(changes) { __update(changes) {
if (!this.__scheduledUpdate && !this._stopped) { if (!this.__scheduledUpdate && !this._stopped) {
this._running = true;
this.__scheduledUpdate = true; this.__scheduledUpdate = true;
this.__currentUpdate = this.__currentUpdate this.__currentUpdate = this.__currentUpdate
.then(() => {
this._running = true;
})
.then(async () => { .then(async () => {
const startTag =`graphfx-update-start:${this.uid}`; const startTag =`graphfx-update-start:${this.uid}`;
const endTag = `graphfx-update-end:${this.uid}` const endTag = `graphfx-update-end:${this.uid}`
@@ -35,10 +33,10 @@ export default class Node {
performance.measure(`GraphFX<${this.name}>`, startTag, endTag) performance.measure(`GraphFX<${this.name}>`, startTag, endTag)
}) })
.then(() => { .then(() => {
this._running = false; this._running = this.__scheduledUpdate;
}) })
.catch((err) => { .catch((err) => {
this._running = false; this._running = this.__scheduledUpdate;
throw err; throw err;
}); });
} }
@@ -84,11 +82,11 @@ export default class Node {
} }
} }
deserialize({id, options}) { async deserialize({id, options}) {
this.id = id || uuidv4(); this.id = id || uuidv4();
} }
reconnect({options}, outputs) { async reconnect({options}, outputs) {
for (let name of Object.keys(options.in)) { for (let name of Object.keys(options.in)) {
const {output} = options.in[name]; const {output} = options.in[name];
if (output) { if (output) {
@@ -96,10 +94,10 @@ export default class Node {
} }
} }
for (let name of Object.keys(options.out)) { for (let name of Object.keys(options.out)) {
this.out[name].deserialize(options.out[name]); await this.out[name].deserialize(options.out[name]);
} }
for (let name of Object.keys(options.in)) { for (let name of Object.keys(options.in)) {
this.in[name].deserialize(options.in[name]); await this.in[name].deserialize(options.in[name]);
} }
} }

57
src/nodes/Synchronize.js Normal file
View File

@@ -0,0 +1,57 @@
import Node from './Node';
export default class Numbers extends Node {
constructor() {
super('Synchronize', {
first: {
type: 'Image',
default: 0,
},
second: {
type: 'Image',
default: 0,
},
}, {
first: {
type: 'Image',
default: 0,
},
second: {
type: 'Image',
default: 0,
},
}, {});
this.__changed = {
first: false,
second: false,
};
this.in.first.onchange((value) => {
if (value) {
console.log('first hit', value)
this.__changed.first = true;
}
});
this.in.second.onchange((value) => {
if (value) {
console.log('second hit', value)
this.__changed.second = true;
}
});
}
async _update() {
const {first, second} = this.__changed;
if (first && second) {
console.log('synced')
this.out.first.value = this.in.first.value;
this.out.second.value = this.in.second.value;
this.__changed = {
first: false,
second: false,
};
} else {
console.log('not synced')
}
}
}

View File

@@ -51,8 +51,8 @@ export default class Input extends AbstractIO {
} }
} }
deserialize({value, label}) { async deserialize({value, label}) {
const deserializedValue = deserialize(value); const deserializedValue = await deserialize(value);
if (deserializedValue) { if (deserializedValue) {
this.value = deserializedValue; this.value = deserializedValue;
} }

View File

@@ -16,8 +16,22 @@ const deserializeImage = ({src}) => {
return img; return img;
} }
export const deserialize = (value) => { const deserializeFont = async (font) => {
try {
font.fontface = new FontFace(font.name, font.url);
await font.fontface.load();
if (!document.fonts.has(font.fontface)) {
await document.fonts.add(font.fontface)
}
} catch(err) {
console.warn('Failed to load font', err)
}
return font;
}
export const deserialize = async (value) => {
return isNil(value) ? value : return isNil(value) ? value :
value.type === 'image' ? deserializeImage(value) : value.type === 'image' ? await deserializeImage(value) :
value.type === 'font' ? await deserializeFont(value) :
value; value;
} }