73 lines
3.7 KiB
JavaScript
73 lines
3.7 KiB
JavaScript
(function(root,factory){
|
|
const api=factory(root.BendFrameScheduler);
|
|
if(typeof module==='object'&&module.exports)module.exports=factory(require('./frame-scheduler.js'));
|
|
root.BendDragScheduler=api;
|
|
})(typeof globalThis!=='undefined'?globalThis:this,function(FrameScheduler){
|
|
'use strict';
|
|
|
|
const STATES=Object.freeze(['idle','armed','running','draining','settling','cancelled']);
|
|
|
|
function createDragScheduler(options={}){
|
|
if(!FrameScheduler?.createFrameScheduler)throw new TypeError('BendFrameScheduler is required');
|
|
if(typeof options.onFrame!=='function')throw new TypeError('Drag onFrame callback is required');
|
|
const maxSamples=Math.max(2,Number(options.maxSamples)||12);
|
|
const trim=typeof options.trim==='function'?options.trim:samples=>samples.splice(0,Math.max(0,samples.length-maxSamples));
|
|
let state='idle',pointerId=null,latest=null,logical=[],revision=0,visualRevision=0,logicalRevision=0;
|
|
const frame=FrameScheduler.createFrameScheduler({
|
|
interval:options.interval,
|
|
tolerance:options.tolerance,
|
|
watchdogDelay:options.watchdogDelay,
|
|
requestFrame:options.requestFrame,
|
|
cancelFrame:options.cancelFrame,
|
|
setDelay:options.setDelay,
|
|
clearDelay:options.clearDelay,
|
|
now:options.now,
|
|
onWatchdog:options.onWatchdog,
|
|
commit:(_signal,timestamp)=>options.onFrame(api,timestamp)
|
|
});
|
|
const assertState=next=>{if(!STATES.includes(next))throw new TypeError(`Unknown drag state: ${next}`);state=next};
|
|
const clearData=()=>{pointerId=null;latest=null;logical.length=0;revision=0;visualRevision=0;logicalRevision=0};
|
|
const arm=id=>{
|
|
if(id==null)throw new TypeError('Drag pointerId is required');
|
|
frame.cancel({resetCadence:true});clearData();pointerId=id;assertState('armed');return api;
|
|
};
|
|
const push=(sample,{schedule=true}={})=>{
|
|
if(!sample||sample.pointerId==null)return false;
|
|
if(state==='idle'||state==='cancelled'||state==='settling')arm(sample.pointerId);
|
|
if(sample.pointerId!==pointerId||state==='draining')return false;
|
|
latest=sample;logical.push(sample);trim(logical,maxSamples);revision++;
|
|
if(state==='armed')assertState('running');
|
|
if(schedule)frame.push(revision);
|
|
return revision;
|
|
};
|
|
const requestFrame=()=>{if(latest&&state!=='idle'&&state!=='cancelled')frame.push(revision)};
|
|
const beginDrain=sample=>{
|
|
if(sample)push(sample,{schedule:false});
|
|
if(state==='idle'||state==='cancelled')return false;
|
|
frame.cancel();assertState('draining');return true;
|
|
};
|
|
const beginSettling=()=>{if(state==='draining'||state==='running'||state==='armed')assertState('settling');frame.cancel();return state==='settling'};
|
|
const settle=()=>{frame.cancel({resetCadence:true});clearData();assertState('idle')};
|
|
const cancel=()=>{frame.cancel({resetCadence:true});clearData();assertState('cancelled')};
|
|
const takeLogical=max=>{
|
|
const count=Math.max(0,Math.min(logical.length,Number(max)||1));
|
|
return logical.splice(0,count);
|
|
};
|
|
const drainLogical=()=>logical.splice(0);
|
|
const markVisual=()=>{visualRevision=revision};
|
|
const markLogical=()=>{if(!logical.length)logicalRevision=revision};
|
|
const inspect=()=>Object.freeze({
|
|
state,pointerId,latest,logicalCount:logical.length,revision,visualRevision,logicalRevision,
|
|
freshVisual:visualRevision!==revision,freshLogical:logicalRevision!==revision
|
|
});
|
|
const api=Object.freeze({
|
|
arm,push,requestFrame,beginDrain,beginSettling,settle,cancel,takeLogical,drainLogical,
|
|
latest:()=>latest,
|
|
hasLogical:()=>logical.length>0,
|
|
markVisual,markLogical,inspect
|
|
});
|
|
return api;
|
|
}
|
|
|
|
return Object.freeze({STATES,createDragScheduler});
|
|
});
|