✨ running/stopped event
This commit is contained in:
17
src/graph.js
17
src/graph.js
@@ -1,10 +1,14 @@
|
||||
import * as nodes from './nodes';
|
||||
import {MultiSubject} from './helpers/listener';
|
||||
|
||||
|
||||
export default class Graph {
|
||||
|
||||
constructor() {
|
||||
this.nodes = [];
|
||||
this.__nodesActive = 0;
|
||||
this.__nodesActiveDebounce = null;
|
||||
this.subject = new MultiSubject(['running', 'stopped']);
|
||||
}
|
||||
|
||||
serialize() {
|
||||
@@ -17,6 +21,19 @@ export default class Graph {
|
||||
static deserialize(nodes) {
|
||||
const graph = new Graph();
|
||||
graph.nodes = createNodes(nodes);
|
||||
for (let {node} of graph.nodes) {
|
||||
node.subject.on('running', (isRunning) => {
|
||||
graph.__nodesActive += isRunning ? 1 : -1;
|
||||
clearTimeout(graph.__nodesActiveDebounce);
|
||||
graph.__nodesActiveDebounce = setTimeout(() => {
|
||||
if (graph.__nodesActive > 0) {
|
||||
graph.subject.next('running');
|
||||
} else {
|
||||
graph.subject.next('stopped');
|
||||
}
|
||||
}, 16);
|
||||
});
|
||||
}
|
||||
return graph;
|
||||
}
|
||||
|
||||
|
||||
69
src/helpers/listener.js
Normal file
69
src/helpers/listener.js
Normal file
@@ -0,0 +1,69 @@
|
||||
export class Subject {
|
||||
|
||||
constructor() {
|
||||
this.__listeners = [];
|
||||
}
|
||||
|
||||
next(val) {
|
||||
for (let listener of this.__listeners) {
|
||||
listener(val);
|
||||
}
|
||||
}
|
||||
|
||||
once() {
|
||||
return new Promise((resolve) => {
|
||||
const done = (val) => {
|
||||
resolve(val);
|
||||
this.off(done);
|
||||
};
|
||||
this.on(done);
|
||||
})
|
||||
}
|
||||
|
||||
on(fn) {
|
||||
this.__listeners.push(fn);
|
||||
}
|
||||
|
||||
off(fn) {
|
||||
this.__listeners = this.__listeners.filter((listener) => listener !== fn);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.__listeners = [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export class MultiSubject {
|
||||
|
||||
constructor(types) {
|
||||
this.__subjects = {};
|
||||
for (let type of types) {
|
||||
this.__subjects[type] = new Subject();
|
||||
}
|
||||
}
|
||||
|
||||
next(type, val) {
|
||||
this.__subjects[type].next(val);
|
||||
}
|
||||
|
||||
once(type) {
|
||||
return this.__subjects[type].once();
|
||||
}
|
||||
|
||||
on(type, fn) {
|
||||
return this.__subjects[type].on(fn);
|
||||
}
|
||||
|
||||
off(type, fn) {
|
||||
this.__subjects[type].off(fn);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
for (let type of Object.keys(this.__subjects)) {
|
||||
this.__subjects[type].destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,6 +130,10 @@ export default class Compose extends Canvas2d {
|
||||
if (!width || !height) {
|
||||
return;
|
||||
}
|
||||
if (!this.bg && !this.fg) {
|
||||
return;
|
||||
}
|
||||
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {Inputs, Outputs} from './io';
|
||||
import uuidv4 from 'uuid/v4';
|
||||
import {MultiSubject} from '../helpers/listener';
|
||||
|
||||
export default class Node {
|
||||
|
||||
@@ -12,13 +13,18 @@ export default class Node {
|
||||
this.__in.update = (name) => this.__update([name]);
|
||||
this.__scheduledUpdate = false;
|
||||
this.__currentUpdate = Promise.resolve();
|
||||
this.__running = false;
|
||||
this._stopped = false;
|
||||
this.subject = new MultiSubject(['running']);
|
||||
}
|
||||
|
||||
__update(changes) {
|
||||
if (!this.__scheduledUpdate && !this._stopped) {
|
||||
this.__scheduledUpdate = true;
|
||||
this.__currentUpdate = this.__currentUpdate
|
||||
.then(() => {
|
||||
this._running = true;
|
||||
})
|
||||
.then(async () => {
|
||||
const startTag =`graphfx-update-start:${this.uid}`;
|
||||
const endTag = `graphfx-update-end:${this.uid}`
|
||||
@@ -27,6 +33,13 @@ export default class Node {
|
||||
await this._update();
|
||||
performance.mark(endTag)
|
||||
performance.measure(`GraphFX<${this.name}>`, startTag, endTag)
|
||||
})
|
||||
.then(() => {
|
||||
this._running = false;
|
||||
})
|
||||
.catch((err) => {
|
||||
this._running = false;
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -35,6 +48,17 @@ export default class Node {
|
||||
throw new Error('_update method not implemented');
|
||||
}
|
||||
|
||||
get _running() {
|
||||
return this.__running;
|
||||
}
|
||||
|
||||
set _running(val) {
|
||||
if (this.__running !== val) {
|
||||
this.__running = val;
|
||||
this.subject.next('running', this.__running);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Input getters
|
||||
*/
|
||||
|
||||
@@ -4,7 +4,7 @@ import WebGL from './WebGl';
|
||||
export default class Channels extends WebGL {
|
||||
|
||||
constructor() {
|
||||
super('Greyscale by channel', {
|
||||
super('Channels', {
|
||||
red: {
|
||||
type: 'Number',
|
||||
default: 1,
|
||||
|
||||
@@ -153,17 +153,8 @@ export default class WebGL extends Node {
|
||||
_passes() {
|
||||
return [
|
||||
(gl, program, image) => {
|
||||
console.log('pass1')
|
||||
this._setParams(gl, program);
|
||||
},
|
||||
(gl, program, image) => {
|
||||
console.log('pass2')
|
||||
this._setParams(gl, program);
|
||||
},
|
||||
(gl, program, image) => {
|
||||
console.log('pass3')
|
||||
this._setParams(gl, program);
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -186,7 +177,9 @@ export default class WebGL extends Node {
|
||||
async _update() {
|
||||
|
||||
const image = this.in.image.value;
|
||||
if (!image) return;
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
if (image.acquire) {
|
||||
image.acquire();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user