UNPKG

@gravity-ui/graph

Version:

Modern graph editor component

88 lines (87 loc) 3.17 kB
// TODO: throtled with leading need test import { scheduler } from "../../lib/Scheduler"; const getNowTime = () => performance.now(); export class FrameDebouncer { constructor() { this.nextFrameFns = []; this.tmpFns = []; this.mapOriginalToBindedFn = new WeakMap(); } run(frameTime) { const start = getNowTime(); if (this.nextFrameFns.length === 0) return; for (let i = 0; i < this.nextFrameFns.length; i += 1) { this.nextFrameFns[i](frameTime + getNowTime() - start); } this.nextFrameFns = this.tmpFns; this.tmpFns = []; } add(fn, options = {}) { const bindedFn = this.getBindedFunction(fn, options); this.mapOriginalToBindedFn.set(fn, bindedFn); return (...args) => { if (!bindedFn.inOrder) { this.nextFrameFns.push(bindedFn); bindedFn.inOrder = true; } bindedFn.args = args; bindedFn.delay = options.throttle || options.leading ? bindedFn.delay : options.delay; }; } delete(fn) { const bindedFn = this.mapOriginalToBindedFn.get(fn); const i = this.nextFrameFns.indexOf(bindedFn); if (i !== -1) { this.nextFrameFns.splice(i, 1); bindedFn.inOrder = false; } } getBindedFunction(fn, options) { const bindedFn = this.createBindedFunction(fn, options); bindedFn.delay = options.delay; bindedFn.args = []; return bindedFn; } createBindedFunction(fn, options) { const bindedFn = (frameTime) => { const hardFrame = options.lightFrame ? frameTime > 16 : frameTime > options.frameTime; const skip = options.leading ? bindedFn.delay < options.delay : bindedFn.delay > 0; if (hardFrame || skip) { // skip original function if (options.leading) { bindedFn.delay += 1; if (hardFrame || bindedFn.delay < options.delay) { this.tmpFns.push(bindedFn); } else { bindedFn.inOrder = false; } } else { this.tmpFns.push(bindedFn); bindedFn.delay -= 1; } return; } const run = options.leading ? bindedFn.delay >= options.delay : bindedFn.delay < 1; if (run) { // perform original function fn(...bindedFn.args); if (options.throttle) { bindedFn.delay = options.delay; } if (options.leading) { bindedFn.delay = 0; this.tmpFns.push(bindedFn); } else { bindedFn.inOrder = false; } } }; return bindedFn; } } export const frameDebouncer = new FrameDebouncer(); scheduler.addScheduler({ performUpdate: frameDebouncer.run.bind(frameDebouncer) }, 4);