修正時、尺調整してるときに、たま~に「コンポ尺より後ろにキーがあるけど、レイヤーをスライドさせて尺内に持ってくるのが大変」ということがあります。そんなときにお使いください。UIはありません。
以下のコードをテキストにコピーして、拡張子を.jsxにすれば完成です。
右上のマークをクリックすれば全文をコピーできます。
(function (aGbl) {
//----------------------------------------------------------------------------------------------------------------------
try{
mMoveHidingKeysToEnd();
}catch(e){
app.endUndoGroup();
alert(e.message + e.line);
}
//--------------------------------------------------------
function mMoveHidingKeysToEnd( ){
app.beginUndoGroup("MoveHidingKeysToEnd");
var mAi = app.project.activeItem;
var mSls = mAi.selectedLayers;
var mTimeAllF = mAi.time;
for( var k =0; k<mSls.length ; k++ ){
var mSl = mSls[k];
var mProps = mGetAllKeyProps(mSl);
if( mProps.length === 0 ){ continue;}
//コンポのアウト時間を得ておく。
var mCmpOutTime = mAi.duration - mAi.frameDuration;
//コンポのアウト時間より後にキーがあるプロップのみにする。
var mOutProps = [];
labelI:
for( var i =0; i<mProps.length ; i++ ){
var mProp = mProps[i];
for( var j = 1; j<=mProp.numKeys ; j++ ){
var mKeyTime = mProp.keyTime(j);
if( mCmpOutTime < mKeyTime ){
mOutProps.push( mProp );
continue labelI;
}
}
}
mProps = mOutProps;
if( mProps.length === 0 ){ continue;}
//ペーストするときの先頭時間を出す。
//コンポのアウト時間を基準位置として、そこから対象キー群の先頭~最後尺ぶんもどった時間位置。
//ついでに各キー時間が入った配列も作っておく。
var mKeyTimes = [];
var mKeyTimess = [];
for( var i =0; i<mProps.length ; i++ ){
var mProp = mProps[i];
var mKeyTimesTp = [];
for( var j = 1; j<=mProp.numKeys ; j++ ){
var mKeyTime = mProp.keyTime(j);
if( mCmpOutTime < mKeyTime ){
mKeyTimesTp.push( mKeyTime );
mKeyTimes.push( mKeyTime );
}
}
mKeyTimess.push( mKeyTimesTp );
}
mKeyTimes.sort( function( a , b ){ return a - b; } );
var mKeyTimeF = mKeyTimes[0];
var mKeyTimeL = mKeyTimes[mKeyTimes.length-1];
var mIndcTime = mCmpOutTime - ( mKeyTimeL - mKeyTimeF );
//プロップごとに処理する。
for( var i =0; i<mProps.length ; i++ ){
var mProp = mProps[i];
//コンポのアウト時間以降のキーの最初の番号と数を得る。
var mCntr = 0;
var mFstNum = null;
for( var j =1; j <= mProp.numKeys; j++ ){
if( mCmpOutTime < mProp.keyTime(j) ){
if( mCntr === 0 ){ mFstNum = j;}
mCntr++;
}
}
if(mFstNum === null ){ continue;}
//ペースト時間位置を割り出す。
//インジケータ基準時間+ ( 対象プロップ先頭キー時間 - 全先頭キーの時間)。
var mTgtTime = mIndcTime + ( mKeyTimess[i][0] - mKeyTimeF );
//移動させる。
mMoveKeys(mProp, mFstNum, mCntr, mTgtTime);
}
if(k === 0){
mTimeAllF = mIndcTime;
}else{
if( mTimeAllF > mIndcTime ){ mTimeAllF = mIndcTime;}
}
}
//インジケータを全最前キー時間に移動させる。
mAi.time = mTimeAllF;
app.endUndoGroup();
}
//----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------
//キーがあるプロパティを集める関数。
function mGetAllKeyProps(aSl){
var mSl = aSl;
var mProps = [];
for( var i = 1; i<=mSl.numProperties ; i++ ){ mFunc(mSl.property(i));}
function mFunc(aProp){
if( aProp.propertyType === PropertyType.PROPERTY ){
if(aProp.canVaryOverTime && aProp.numKeys !== 0 && !mIsHidden(aProp)){
mProps.push( aProp );
}
}else{
for( var i = 1; i<=aProp.numProperties ; i++ ){
mFunc(aProp.property(i));
}
}
}
return mProps;
}
//---------------------------------------------------------------
//hiddenかどうかを返す関数。キーを全て選択状態にしてしまうが、このスクリプトに関しては問題ない。
function mIsHidden(aProp){
try{
aProp.selected = aProp.selected;
return false;
}catch(e){
return(/hidden/.test(e.message));
}
}
//----------------------------------------------------------------------------------------------------------------------
function mMoveKeys(aProp, aKeyIdxF, aNum, aInsrtTime){
var mProp = aProp;
var mInsrtTimeF = aInsrtTime;
var mNumF = aKeyIdxF;
var mNumL = mNumF + aNum-1;
//動かす各キーのインサート時間を得る。
var mInsrtTimes = [];
var mStdTime = mProp.keyTime(mNumF);
for( var i = mNumF; i<=mNumL ; i++ ){
mInsrtTimes.push( (mProp.keyTime(i) - mStdTime) + mInsrtTimeF );
}
//消す前に情報を得ておく。
var mInfos = [];
for( var i = mNumF; i<=mNumL ; i++ ){
var mInfo = mCreateKeyInfoObj( i, mProp );
mInfos.push( mInfo );
}
//対象キーを消す。
for( var i = mNumL; i >=mNumF ; i-- ){
mProp.removeKey(i);
}
//キーを追加していく。//番号がズレる前に都度情報を入れる。
for( var i = 0; i<mInsrtTimes.length ; i++ ){
var mAddKeyIdx = mProp.addKey(mInsrtTimes[i]);
//上記のキー追加で取得した番号のキー情報を変える。
mApplyKeyInfoObj( mAddKeyIdx, mProp, mInfos[i] );
}
}
//----------------------------------------------------------------------------------------------------------------------
//キー番号から各種情報objを作る関数。
function mCreateKeyInfoObj( aIdx, aSp ){
var mSp = aSp;
var i = aIdx;
var mObj = {};
mObj.mVal = mSp.keyValue(i);
//時間補完法関連。
mObj.mTenEaseIO = [ mSp.keyInTemporalEase(i) , mSp.keyOutTemporalEase(i) ];
mObj.mTenCont = mSp.keyTemporalContinuous(i);
mObj.mTenAuto = mSp.keyTemporalAutoBezier(i);
//空間補完法関連&ロービング。
var mPropType = mSp.propertyValueType;
if( mPropType.propertyValueType === PropertyValueType.TwoD_SPATIAL
|| mPropType.propertyValueType === PropertyValueType.ThreeD_SPATIAL){
mObj.mSpaTngtIO = [ mSp.keyInSpatialTangent(i) , mSp.keyOutSpatialTangent(i) ] ;
mObj.mSpaCont = mSp.keySpatialContinuous(i);
mObj.mSpaAuto = mSp.keySpatialAutoBezier(i);
mObj.mRoving = mSp.keyRoving(i);
}
//キー補完種類。
mObj.mItpTypeIO = [ mSp.keyInInterpolationType(i) , mSp.keyOutInterpolationType(i) ];
return mObj;
}
//-------------------------------------------------------------
//キー番号のキーに各種情報objを適用する関数。
function mApplyKeyInfoObj( aIdx, aSp, aObj ){
var mSp = aSp;
var j = aIdx;
var mObj = aObj;
mSp.setValueAtKey( j, mObj.mVal );
//時間補完法関連。
mSp.setTemporalEaseAtKey(j, mObj.mTenEaseIO[0], mObj.mTenEaseIO[1]);
mSp.setTemporalContinuousAtKey(j, mObj.mTenCont);
mSp.setTemporalAutoBezierAtKey(j, mObj.mTenAuto);
//空間補完法関連&ロービング。
var mPropType = mSp.propertyValueType;
if( mPropType.propertyValueType === PropertyValueType.TwoD_SPATIAL
|| mPropType.propertyValueType === PropertyValueType.ThreeD_SPATIAL){
mSp.setSpatialTangentsAtKey(j, mObj.mSpaTngtIO[0], mObj.mSpaTngtIO[1]);
mSp.setSpatialContinuousAtKey(j, mObj.mSpaCont);
mSp.setSpatialAutoBezierAtKey(j, mObj.mSpaAuto);
mSp.setRovingAtKey(j, mObj.mRoving);
}
//キー補完種類は最後に適用する。
mSp.setInterpolationTypeAtKey(j, mObj.mItpTypeIO[0], mObj.mItpTypeIO[1]);
}
//----------------------------------------------------------------------------------------------------------------------
//キーフレーム関連プロパティ集。
/*
numKeys
selectedKeys
setValueAtKey()
nearestKeyIndex()
keyTime()
keyValue()
addKey()
removeKey()
ease関連一式
isInterpolationTypeValid()
setSelectedAtKey()
keySelected()
ease関連一式
setInterpolationTypeAtKey(keyIndex, inType, outType) //キーフレームの補間の種類を設定。
keyInInterpolationType(keyIndex) //キーフレームの「イン」側の補間方法を取得。
keyOutInterpolationType(keyIndex) //キーフレームの「アウト」側の補間方法を取得。
//プロパティが_SPATIALでないとエラーとなる。
setSpatialTangentsAtKey(keyIndex, inTangent, outTangent) // キーフレームの空間補間法のイン/アウトの接線のベクトルを設定。
keyInSpatialTangent(keyIndex) //キーフレームの空間補間法のイン/アウトの接線のベクトルを取得。
keyOutSpatialTangent(keyIndex) //キーフレームの空間補間法のアウト側の接線を取得。
//イーズは配列。
setTemporalEaseAtKey(keyIndex, inTemporalEase, outTemporalEase) //キーフレームの時間補間法のイージーイーズを設定。
keyInTemporalEase(keyIndex) //キーフレームの時間補間法のイン側のイージーイーズを取得。
keyOutTemporalEase(keyIndex) //キーフレームの時間補間法のアウト側のイージーイーズを取得。
setTemporalContinuousAtKey(keyIndex, newVal) //キーフレームの時間補間法の連続ベジェモードを設定。
keyTemporalContinuous(keyIndex) //キーフレームの時間補間法が連続ベジェモードになっているか。インアウトのInterpolationTypeがBEZIER でないと影響が無い。
setTemporalAutoBezierAtKey(keyIndex, newVal) //キーフレームの時間補間法の自動ベジェモードを設定。
keyTemporalAutoBezier(keyIndex) //キーフレームの時間補間法が自動ベジェモードになっているか。インアウトのInterpolationTypeがBEZIER でないと影響が無い。
//プロパティが_SPATIALでないとエラーとなる。
setSpatialContinuousAtKey(keyIndex, newVal) //キーフレームの空間補間法の連続ベジェモードを設定。
keySpatialContinuous(keyIndex) //キーフレームの空間補間法が連続ベジェモードになっているか。
setSpatialAutoBezierAtKey(keyIndex, newVal) // キーフレームの空間補間法の自動ベジェモードを設定。
keySpatialAutoBezier(keyIndex) // キーフレームの空間補間法が自動ベジェモードになっているか。keySpatialContinuousがtrueでないと影響が無い。
setRovingAtKey(keyIndex, newVal) //キーフレームの時間ロービングモードの設定。
keyRoving(keyIndex) //キーフレームが時間ロービングモードになっているか。
*/
//----------------------------------------------------------------------------------------------------------------------
})(this);
使い方
対象のレイヤー(複数可)を選び、スクリプトを起動させると、コンポ尺より後ろにある全てのキーがコンポの最後に移動します。
*もしもすでにコンポ内のラスト付近にキーがあると、そのキーを上書きする可能性があります。なので、コンポ外にあるキーぶんのスペースを確保しておいて実行してください。
解説
各レイヤーの対象キー中の、一番先頭キー時間をゼロとし、他のキー時間はそれとの差分(1次元ベクトル)として保存するのがポイントです。こうしておけば、他の時間位置にペーストする際に、その時間+ベクトルで処理できて便利です。今回はコンポの最後のとこにペーストしましたが、他にもインジケータ時間にペーストするスクリプトを作るときなども、このやり方だと直観的でわかりやすいかなと思います。
コードの最後にまとめてあるコメントは、プロパティオブジェクトのキーフレーム関連プロパティとメソッドをまとめたものです。