UNPKG

superfly-timeline

Version:

Resolver for defining objects with temporal boolean logic relationships on a timeline

115 lines 5.04 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.StateHandler = void 0; const instance_1 = require("./lib/instance"); const lib_1 = require("./lib/lib"); const performance_1 = require("./lib/performance"); const timeline_1 = require("./lib/timeline"); class StateHandler { getState(resolvedTimeline, time, eventLimit = 0) { const toc = (0, performance_1.tic)('getState'); const state = { time: time, layers: {}, nextEvents: resolvedTimeline.nextEvents.filter((e) => e.time > time), }; if (eventLimit) state.nextEvents = state.nextEvents.slice(0, eventLimit); for (const obj of Object.values(resolvedTimeline.objects)) { if (!(0, timeline_1.objHasLayer)(obj)) continue; // Note: We can assume that it is not a keyframe here, because keyframes don't have layers for (const instance of obj.resolved.instances) { if ((0, instance_1.instanceIsActive)(instance, time)) { let contentIsOriginal = true; const objInstance = { ...obj, instance, }; /* istanbul ignore if */ if (state.layers[`${obj.layer}`]) { // There is already an object on this layer! console.error(`layer "${obj.layer}": ${JSON.stringify(state.layers[`${obj.layer}`])}`); console.error(`object "${objInstance.id}": ${JSON.stringify(objInstance)}`); throw new Error(`Internal Error: There is already an object on layer "${obj.layer}"!`); } state.layers[`${obj.layer}`] = objInstance; // Now, apply keyframes: const objectKeyframes = obj.keyframes ? obj.keyframes.map((kf) => resolvedTimeline.objects[kf.id]) : []; for (const keyframe of this.getActiveKeyframeInstances(objectKeyframes, time)) { if (contentIsOriginal) { // We don't want to modify the original content, so we deep-clone it before modifying it: objInstance.content = (0, lib_1.clone)(obj.content); contentIsOriginal = false; } StateHandler.applyKeyframeContent(objInstance.content, keyframe.content); } } } } toc(); return state; } /** * Apply keyframe content onto its parent content. * The keyframe content is deeply-applied onto the parent content. */ static applyKeyframeContent(parentContent, keyframeContent) { const toc = (0, performance_1.tic)(' applyKeyframeContent'); for (const [attr, value] of Object.entries(keyframeContent)) { if ((0, lib_1.isObject)(value)) { if ((0, lib_1.isArray)(value)) { // Value is an array if (!Array.isArray(parentContent[attr])) parentContent[attr] = []; this.applyKeyframeContent(parentContent[attr], value); parentContent[attr].splice(value.length, Infinity); } else { // Value is an object if (!(0, lib_1.isObject)(parentContent[attr]) || Array.isArray(parentContent[attr])) parentContent[attr] = {}; this.applyKeyframeContent(parentContent[attr], value); } } else { parentContent[attr] = value; } } toc(); } getActiveKeyframeInstances(keyframes, time) { const keyframeInstances = []; for (const keyframe of keyframes) { for (const instance of keyframe.resolved.instances) { if ((0, instance_1.instanceIsActive)(instance, time)) { keyframeInstances.push({ ...keyframe, instance, }); } } } keyframeInstances.sort((a, b) => { // Highest priority is applied last: const aPriority = a.priority ?? 0; const bPriority = b.priority ?? 0; if (aPriority < bPriority) return -1; if (aPriority > bPriority) return 1; // Last start time is applied last: if (a.instance.start < b.instance.start) return -1; if (a.instance.start > b.instance.start) return 1; /* istanbul ignore next */ return 0; }); return keyframeInstances; } } exports.StateHandler = StateHandler; //# sourceMappingURL=StateHandler.js.map