// ref // https://developer.mozilla.org/ja/docs/Web/API/MixingSynthesis import { MixingProps, MixingUpdate, } from './types' import { is, each, getFluidValue, FluidValue } from './utils' import { getSynthedType, getSynthed, setSynthed, Synthed } from './nodes' import {FrameValue} from './FrameValue' import {Synthesis} from './Synthesis' const initState = { } export class MixingValue extends FrameValue { key?: string synthesis = new Synthesis() queue: MixingUpdate[] = [] defaultProps = {} readonly _state = initState constructor (arg1: any, arg2?: any) { super() if (!is.und(arg1) || !is.und(arg2)) { const to = is.obj(arg1) ? {...arg1} : {...arg2, from: arg1} this.start(to) } } set (value: T | FluidValue) { this._stop() this._set(value) } advance () { const synth = this.synthesis each(synth.values, (node, i) => { // if (node.done) return }) } pause () { return this._update({pause: true}) } resume () { return this._update({pause: true}) } reset () { return this._update({reset: true}) } update (props: MixingUpdate) { (this.queue || (this.queue = [])).push(props) } start (to?: MixingUpdate, arg2?: MixingProps) { const queue = is.und(to) ? (this.queue || (this.queue = [])) : [is.obj(to)? to: {...arg2, to}] return Promise.all(queue.map(props => this._update(props))) } stop (cancel=false) { const synth = this.synthesis synth.pauseQueue.clear() synth.resumeQueue.clear() this._stop(synth.to, cancel) } protected _set (arg: T | FluidValue): Synthed | undefined { const value = getFluidValue(arg) if (is.und(value)) return getSynthed(this) const oldNode = getSynthed(this) if (oldNode && is(value, oldNode.get())) return const nodeType = getSynthedType(value) if (!oldNode || oldNode.constructor != nodeType) setSynthed(this, nodeType.create(value)) else oldNode?.set(value) } protected _start (...args: any) { const synth = this.synthesis getSynthed(this)!.reset(getFluidValue(synth.to)) } protected _stop (...args: any) { } protected _focus (value: any) { } protected _update (props: MixingProps) { const range = this._prepareNode(props) return new Promise(resolve => this._merge(range, props, resolve)) } protected _merge (range: any, props: any, resolve: any) { if (props.cancel) { this.stop(true) return resolve(getCancelledResult(this)) } const { key, defaultProps, synthesis: synth } = this const { to: prevTo, from: prevFrom } = synth let { to = prevTo, from = prevFrom } = range if (props.reverse) [to, from] = [from, to] from = getFluidValue(from) const isFromUndefined = !is.und(prevFrom), isToUndefined = !is.und(prevTo), hasFromChanged = !is(from, prevFrom), hasToChanged = !is(to, prevTo) if (hasToChanged) this._focus(to) if (hasFromChanged) synth.from = from } protected _prepareNode(props: any) { const key = this.key || '' let { to, from } = props from = is.obj(from)? from[key] : from to = is.obj(to)? to[key] : to if (from == null) from = undefined if (to == null || is.fun(to)) to = undefined const range = { to, from } this._set(getSynthed(this)? to: from) return range } }