From f18bafc5438e5ec0fa692b1488e003af7fecb166 Mon Sep 17 00:00:00 2001 From: themancalledjakob Date: Tue, 5 Mar 2024 17:12:18 +0100 Subject: [PATCH] so much faster keyframe adding --- bin/em/variabletime/web/js/main.js | 3 +- bin/em/variabletime/web/js/record.js | 4 +- bin/em/variabletime/web/js/theatre-play.js | 241 ++++++--------------- bin/em/variabletime/web/js/utils.js | 13 ++ 4 files changed, 85 insertions(+), 176 deletions(-) diff --git a/bin/em/variabletime/web/js/main.js b/bin/em/variabletime/web/js/main.js index adec14d..a3b2d3b 100644 --- a/bin/em/variabletime/web/js/main.js +++ b/bin/em/variabletime/web/js/main.js @@ -430,7 +430,7 @@ window.getLayers = () => { return layers; }; -window.getLayer = (layerID) => { +window.getLayer = (layerID = tp.studio.selection[0].address.objectKey) => { if (layerID === 'artboard') { return artboard; } else { @@ -610,5 +610,4 @@ const initPanels = () => { }); }); } - }; diff --git a/bin/em/variabletime/web/js/record.js b/bin/em/variabletime/web/js/record.js index 6d841d8..5e50c68 100644 --- a/bin/em/variabletime/web/js/record.js +++ b/bin/em/variabletime/web/js/record.js @@ -431,7 +431,7 @@ const Record = function(tp) { console.log('Record::startRecording', `whoops input_clone for ${propTitle} is null`); } }); - tp.sheet.sequence.position = 0; + //tp.sheet.sequence.position = 0; tp.sheet.sequence.play(); }); isRecording = RECORDING; @@ -502,7 +502,7 @@ const Record = function(tp) { const kf = clone(keyframes); promises.push(() => { return new Promise((subResolve) => { - tp.setKeyframes(layer, keyframes).then(() => { + tp.addKeyframes(layer, keyframes).then(() => { layer.updateValuesViaTheatre(true); subResolve(); }); diff --git a/bin/em/variabletime/web/js/theatre-play.js b/bin/em/variabletime/web/js/theatre-play.js index 19d6a1d..3114556 100644 --- a/bin/em/variabletime/web/js/theatre-play.js +++ b/bin/em/variabletime/web/js/theatre-play.js @@ -8,6 +8,7 @@ import { getParents, arraysEqual, sequencialPromises, + getNestedProperty, } from './utils.js'; //import { @@ -141,177 +142,90 @@ const TheatrePlay = function(autoInit = false) { } return t.parentElement.querySelector('[title="Sequence this prop"]'); }; - const isSequenced = (path) => { - return getSequenceButton(path) === null; - }; - - const setSequenced = (propTitle, sequenced, metaResolve = false) => { - const f = (resolve) => { - const propIsSequenced = isSequenced(propTitle); - const somethingToDo = sequenced !== propIsSequenced; - - if (somethingToDo) { - const contextItem = sequenced ? 'sequence' : 'make static'; - const antiContextItem = sequenced ? 'make static' : 'sequence'; - - const finishedSequencedEvent = (e) => { - // only care about events from our prop - if (propTitle === e.detail.prop.join('.')) { - // if we un-sequence, we listen to stateEditors' event - if (!sequenced && e.detail.origin === 'stateEditors.ts' && e.detail.sequenced === sequenced) { - window.removeEventListener('sequenceEvent', finishedSequencedEvent); - resolve(true); - - // if we sequence, then we wait until the track is there - } else if (sequenced && e.detail.origin === 'BasicKeyframedTrack.tsx' && e.detail.sequenced === sequenced) { - window.removeEventListener('sequenceEvent', finishedSequencedEvent); - resolve(true); - } else { - // pretty verbose - //console.log('TheatrePlayu::setSequenced', 'ignored event', e, e.detail); - } - } - }; - - let counter = 0; - const clickContextMenu = (e) => { - let done = false; - if (e.target !== null) { - e.target.removeEventListener('contextmenu', clickContextMenu); - } - tp.shadowRoot.querySelectorAll('ul li span').forEach((s) => { - if (s.innerHTML.toLowerCase() === contextItem.toLowerCase()) { - window.addEventListener('sequenceEvent', finishedSequencedEvent); - s.click(); - done = true; - } else if (s.innerHTML.toLowerCase() === antiContextItem.toLowerCase()) { - done = true; - resolve(false); - } - }); - if (!done) { - setTimeout(() => { - if (counter < 4) { - clickContextMenu(e); - counter++; - } else { - setSequenced(propTitle, sequenced, resolve); - } - }, 100); - } - }; - - getPanelPropTitle(propTitle).addEventListener('contextmenu', clickContextMenu); - getPanelPropTitle(propTitle).dispatchEvent(new Event('contextmenu')); - } else { - resolve(); - } - }; - if (!metaResolve) { - return new Promise((resolve) => { - f(resolve); - }); - } else { - f(metaResolve); + const isSequenced = (path, layer = getLayer()) => { + if (!Array.isArray(path)) { + path = path.split('.'); } + const prop = getNestedProperty(layer.theatreObject.props, path); + return studio.__experimental.__experimental_isPropSequenced(prop); + // is this better than this? + //return getSequenceButton(path) === null; }; + const setSequenced = (path, sequenced = true, layer = getLayer()) => { + if (!Array.isArray(path)) { + path = path.split('.'); + } + return new Promise((resolve) => { + if(isSequenced(path, layer) === sequenced) { + resolve(true); + } else { + const prop = getNestedProperty(layer.theatreObject.props, path); + if (sequenced) { + tp.studio.__experimental.__experimental_setPropAsSequenced(prop); + } else { + tp.studio.__experimental.__experimental_setPropAsStatic(prop); + } + let count = 0; + const interval = setInterval(() => { + if (isSequenced(path, layer) === sequenced) { + clearInterval(interval); + resolve(true); + } else if (count >= 10) { + clearInterval(interval); + resolve(false); + } + count++; + }, 10); + } + }); + }; + + /* + * layer = getLayer() + * keyframes = [ + * { + * path: ['fontVariationAxes','Weight'], + * keyframes: [ + * { + * "id": "yHFP-HCINm", // not sure if used when sent back + * "position": 0, + * "connectedRight": true, // optional + * "handles": [ 0.5, 1, 0.5, 0 ], // optional + * "type": "bezier", // optional + * "value": 200 + * }, ... + * ] + * }, ... + * ] + */ const addKeyframes = (layer, keyframes) => { return new Promise((resolve) => { - if (!Array.isArray(keyframes)) { - resolve(false); - return false; - } - const existingKeyframes = getKeyframes(layer); const promises = []; - const ms = 0; //config.tp.addKeyframesTimeout_s * 1000; keyframes.forEach((k) => { - let prop = layer.theatreObject.props; - for (let i = 0; i < k.path.length; i++) { - prop = prop[k.path[i]]; - } - const position = tp.sheet.sequence.position; promises.push(() => { return new Promise((subResolve) => { - setTimeout(() => { - if (layer.isSelected()) { - setSequenced(k.path.join('.'), true) - .then(() => { - subResolve(); - }); - } else { - // we cannot select layers without pseudoclicking - // so let's wait for a happy 'injected' event that - // closes off the selection - // - // first, the listener callback - const f = () => { - tp.getPanel().removeEventListener('injected', f); - setSequenced(k.path.join('.'), true) - .then(() => { - subResolve(); - }); - }; - // then add it - tp.getPanel().addEventListener('injected', f); - // and fire the click - layer.select(); - } - }, ms); // * promises.length); - }) - }); - let propHasKeyframesAt = -1; - if (existingKeyframes !== null && - existingKeyframes !== false && - typeof existingKeyframes !== 'undefined' && - Array.isArray(existingKeyframes)) { - existingKeyframes.forEach((existingK, existingKI) => { - if (arraysEqual(k.path, existingK.path)) { - propHasKeyframesAt = existingKI; + let prop = layer.theatreObject.props; + for (let i = 0; i < k.path.length; i++) { + prop = prop[k.path[i]]; } - }); - } - k.keyframes.forEach((keyframe) => { - let alreadyThere = false; - if (propHasKeyframesAt >= 0) { - existingKeyframes[propHasKeyframesAt].keyframes.forEach((kf) => { - if (keyframe.position === kf.position && - keyframe.value === kf.value) { - alreadyThere = true; - } - }); - } - if (!alreadyThere) { - promises.push(() => { - return new Promise((subResolve) => { - setTimeout(() => { - tp.sheet.sequence.position = keyframe.position; - this.studio.transaction(({ - set - }) => { - set(prop, keyframe.value); - subResolve(); - }); - }, ms); // * promises.length); - }) - }); - } - }); - promises.push(() => { - return new Promise((subResolve) => { - setTimeout(() => { - tp.sheet.sequence.position = position; + setSequenced(k.path, true, layer).then(() => { + tp.studio.transaction(({ + __experimental_addKeyframes + }) => { + __experimental_addKeyframes(prop, k.keyframes); + }); subResolve(); - }, ms); // * promises.length); - }) + }); + }); }); }); sequencialPromises(promises, resolve); - //Promise.all(promises).then(() => { - //resolve(); - //}); }); }; + + // NOTE: instead of setting proptitle static and then sequenced again, + // we could simply delete all keyframes. but hey, pfff... const setKeyframes = (layer, keyframes) => { return new Promise((resolve) => { if (!Array.isArray(keyframes)) { @@ -1228,17 +1142,13 @@ const TheatrePlay = function(autoInit = false) { console.log('TheatrePlay::loadProject'); this.isProjectLoaded = false; return new Promise((resolve) => { - console.log('this is happening'); if (projectId === false) { projectId = this.sheet.project.address.projectId; - console.log('this is happening'); } if (project === false) { project = this.getProject(projectId, true); - console.log('this is happening'); } if (project !== false) { // if project is not saved yet, create new - console.log('this is happening'); // get all objects const objects = project .theatre @@ -1282,17 +1192,12 @@ const TheatrePlay = function(autoInit = false) { .filter((e) => e.indexOf('layer-') === 0) .forEach((layerId) => { window.project_fontsHashMap = project.fontsHashMap; - console.log(layerId, objects[layerId]); layerPromises.push(window.addExistingLayer(layerId, objects[layerId])); }); - console.log('this is happening'); - console.log({layerPromises}); Promise.all(layerPromises).then(() => { - console.log('this is happening'); window.layerOrder.set(project.layerOrder); this.duration = this.core.val(this.sheet.sequence.pointer.length); if (project.layerOrder.length > 0) { - console.log('this is happening'); getLayers().forEach((layer) => { if (layer.id() === project.layerOrder[project.layerOrder.length - 1]) { layer.select(); @@ -1308,37 +1213,29 @@ const TheatrePlay = function(autoInit = false) { }); } resolve(); - console.log('RESOLVED'); this.isProjectLoaded = true; }); } else { - console.log('this is happening'); if (getLayers().length === 0 && config.layer.autoCreateFirstLayer) { - console.log('this is happening'); getFontsAndAxes().then((newFontsAndAxes) => { - console.log('this is happening'); const autoInitLayer = false; const layer = addLayer(autoInitLayer); layer.init().then(() => { layer.select(); this.duration = this.core.val(this.sheet.sequence.pointer.length); resolve(); - console.log('RESOLVED'); this.isProjectLoaded = true; }); }); } else { - console.log('this is happening'); const layers = getLayers(); if (layers.length > 0) { } this.duration = this.core.val(this.sheet.sequence.pointer.length); resolve(); - console.log('RESOLVED'); this.isProjectLoaded = true; } } - console.log('this is happening and there was no resolve?'); }); }; this.startNewProject = () => { diff --git a/bin/em/variabletime/web/js/utils.js b/bin/em/variabletime/web/js/utils.js index 166753c..473bd37 100644 --- a/bin/em/variabletime/web/js/utils.js +++ b/bin/em/variabletime/web/js/utils.js @@ -472,6 +472,18 @@ const deFlattenObject = (o, ignoreKeys = [], pathSymbol = '.') => { }); }; +const getNestedProperty = (o, a, verify = false) => { + if (verify && (!Array.isArray(a) || typeof o !== "object" || !o.hasOwnProperty(a[0]))) { + return false; + } + let b = clone(a); + if (b.length > 1) { + o = o[b.shift()]; + return getNestedProperty(o, b, verify); + } + return o[b[0]]; +}; + ///////////////////////////////////// // you can test these functions in // the browser like so: @@ -507,4 +519,5 @@ export { renameProperty, flattenObject, deFlattenObject, + getNestedProperty, }