so much faster keyframe adding

This commit is contained in:
themancalledjakob 2024-03-05 17:12:18 +01:00
parent d95ec3d965
commit f18bafc543
4 changed files with 85 additions and 176 deletions

View file

@ -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 = () => {
});
});
}
};

View file

@ -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();
});

View file

@ -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 = () => {

View file

@ -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,
}