javaScript :ブラウザに表示されたことの検知

●表示されてからアニメ

今回はanime.jsの勉強ではありませんが、内容的には前回の続きです。
前回作成した文字アニメは表示されてから開始するようにしたいです。cssの追加/削除で完結する場合は以下のライブラリが便利だと思います。しかし今回はanime.jsを利用するので、ビューポートに入ったら指定のfunctionを実行する部分を自作しようと思います。

→参考:要素がビューポートに表示されたか判定する -Emergence.js
 
 

●各種パラメータの取得

まずは表示している要素のY座標とスクロールしたときの表示範囲(Y座標)を取得しました。

要素位置と表示位置の取得
http://jquerystudy.info/anime/3_text/04_scroll.html/

 
まずアニメさせたい要素(今回はclass属性がanimeText)のY座標を以下のように取得しています。scrollTopの位置はブラウザによって書き方が変わるのが少し面倒です。

var elms = document.querySelectorAll('.animeText');
elms.forEach(function (elm){
	var elmRect = elm.getBoundingClientRect();	
	var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
	var elmY = elmRect.top + scrollTop;
	elm.innerHTML = elmY;
});

そして表示領域は以下のように記述しました。
スクロール時だけでなくリサイズ時にも取得します。

function setDebugText (){
	var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
	var scrollBottom = scrollTop + window.innerHeight;			
	document.getElementById('debug').innerHTML = scrollTop + ' - ' + scrollBottom;
}

 
 

●classの着脱

アニメを設定する前に表示領域には言ったらclassを追加するサンプルを作成しました。表示領域ギリギリに設定するとclassの着脱が確認できないので100pxのマージンを設定しています。

表示領域に入ったら赤くする
http://jquerystudy.info/anime/3_text/05_check.html/
function checkPos(_min,_max){
	var elms = document.querySelectorAll('.animeText');
	elms.forEach(function (elm){
		var elmRect = elm.getBoundingClientRect() ;
		var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
		var elmY = elmRect.top + scrollTop;		
		var _margin = 100;
		if (elmY > (_min + _margin) && elmY < (_max - _margin)){
			elm.classList.add('vis');
		}else{
			elm.classList.remove('vis');			
		}
	});
}

上記の青字の部分でclassを着脱しています。この処理に関連してaddがclassを重複して追加しないことを確認しました。

var test = document.getElementById('at1').classList.length;
console.log(test);
document.getElementById('at1').classList.add('vis');
document.getElementById('at1').classList.add('vis');
document.getElementById('at1').classList.add('vis');
var test = document.getElementById('at1').classList.length;
console.log(test);

前述のサンプルは最初から表示されている要素は赤くなりません。スクロールかリサイズで初めて判定され赤くなります。これは良くないので、最初に表示されている要素はスクロールしなくても赤くなるようにしました。とはいっても、最初にsetDebugTextを実行するだけです。

setDebugText();//----初期化

 
 

●アニメを付ける

ではアニメを付けていきます。
 

・表示されたときに1度だけアニメ

まずは最初に表示されるときにだけアニメさせるサンプルを作成しました。これはフラグ管理など必要なく、再再生が効かないplayメソッドを利用するだけで完成します。

最初に表示されるときに1回だけ再生
http://jquerystudy.info/anime/3_text/07_inAnime.html/
if (elmY > (_min + _margin) && elmY < (_max - _margin)){
	animeObjList[elm.id].play();//---restartではないので再度再生されることはありません
}

 

・範囲外に出たら逆再生

cssの着脱と同じロジックで簡単に実現できると思ったら躓いた。

逆再生のタイミングがバグってる…
http://jquerystudy.info/anime/3_text/08_reverse_ng.html/
var _margin = 100;
if (elmY > (_min + _margin) && elmY < (_max - _margin)){
	animeObjList[elm.id].play();
}else{
	animeObjList[elm.id].reverse();
}

 
reverseの挙動に疑問を持ったので代わりにseek(0)を利用してリセットするだけにした。これだと正常に機能しているように見える。

範囲外に出たらアニメをリセットする
http://jquerystudy.info/anime/3_text/09_seek0.html/
var _margin = 100;
if (elmY > (_min + _margin) && elmY < (_max - _margin)){
	animeObjList[elm.id].play();
}else{
	animeObjList[elm.id].seek(0);//---範囲外に出たら最初に戻す
}

 
しかしseek(0)ではなくreverseでアニメを戻したい。ということでcssをフラグのように利用して再挑戦。しかし失敗。reverseメソッドは私が考えているような使い方はできないのかもしれない…。

フラグを使ったけどダメでした…
http://jquerystudy.info/anime/3_text/10_reverse_flg.html/
if (elmY > (_min + _margin) && elmY < (_max - _margin)){
	if (elm.classList.contains('vis') == false){
		elm.classList.add('vis');
		animeObjList[elm.id].restart();
	}
}else{
	if (elm.classList.contains('vis') == true){
		elm.classList.remove('vis');
		animeObjList[elm.id].pause();
		animeObjList[elm.id].reverse();
	}
}

 
上記のサンプルではclassの着脱はflgとして利用しているので、視覚的にフラグの状態が分かる。ロジックは正しいのにreverseが処理されない…。ということでreverseを利用しない方向に変更。そもそも逆再生でアニメを戻す方法は融通が利かない、表示するときと消すときは別々のアニメを設定できるようにしたほうが実用的だと思う。
 
ということで最終形。

必要の都度、アニメを設定
http://jquerystudy.info/anime/3_text/11_outAnime.html/

 
上記のサンプルでは、アニメが重複しないようにremoveメソッドで事前のアニメは削除しています。ということで一応removeメソッドの動作を確認。animeオブジェクトをremoveするとアニメはリセットされるのではなく、その場で停止する。この仕様は好都合。

 
おしまい。
とりあえず学びたいことはすべて学んだ感じなので、
ひとまず更新は停止。
また学びたいことができたら再開します。
 
 

anime.js(11):テキストアニメ

anime.jsを選択した理由の1つは以下のサンプルが素敵だったことにあります。しかしソースを確認すると、いろいろな要素が複雑に構成されており、解読する気になれませんでした…。なので1から独自に作っていこうと思います。
→参考:Letter Effects with anime.js
 

●1文字づつ分ける

今回は文字を個別に操作したいので、まずは1文字ずつspanタグで囲むことにしました。以下のサンプルでボタンをタップすると文字をspanで区切ります。区切ったことが分かるように1文字づつ色を変更しました。

function spanningFunc (_target){
	var elms = document.querySelectorAll(_target);
	elms.forEach(function (elm){
		var myText = elm.textContent;
		elm.innerHTML = null;
		myText.split('').forEach(function (c) {
			elm.innerHTML += ''+c+'';
		});
	});
}

1文字づつ区切るのでカーニングが外れてしまいますが、これは仕方ないですね(手動で調整もできますが、工数対効果は低そうです)。
 

●フェードアニメ

位置を移動させるアニメはcss的に面倒になると思うので、まずは位置の変わらないフェードアニメを作成しました。ボタンをタップすると下段のdivに文字列が表示されていきます。

var animObj_2 = anime({targets:'#at2 .anime',opacity:[0,1],easing:'linear',
	autoplay:false,duration:300,
	delay:function(elm,index, ln){
		return index*50;
	}
});

操作しているプロパティはopacityで初期値を設定する構文を利用しています。初期値が0なので最初は表示されませんが、アニメを開始すると値が1になるので表示されていくわけです。表示タイミングをずらすのはdelayでfunctionを設定して実現しています。
 
 

●移動アニメ

以下サンプルでボタンをタップすると、下段のdiv要素に文字が移動しながら表示されます。

 
移動に利用するプロパティは相対的に位置を設定できるtranslate系が良いでしょう(絶対値指定であればleftやtopも利用できます)。
 
spanはデフォルトでinline要素のためtranslateで位置を設定できません。なので、まずはアニメを設定する要素のdisplay属性をinline-blockに変更しました。

.anime{
	display:inline-block;
}

これでtranslateを使って位置を変更できるようになったので、普通にanimeオブジェクトを作成できます。opacityと同じように初期値を設定する構文を使いました。最初は200に設定しているので、初期位置から200px下に配置されます。そして目的値が0なのでアニメで初期位置に戻ってくるわけです。

var animObj_2 = anime({targets:'#at2 .anime',
	translateY:[200,0],
	opacity:[0,1],
	autoplay:false,duration:1000,
	delay:function(elm,index, ln){
		return index*50;
	}
});

このサンプルは正常に機能しているように見えますが、半角スペースが無視されてしまっています。なので次項で修正したいと思います。
 
 

●span処理の改造

display属性をinline-blockに変更にしたら半角スペースが無視されるようになってしまいました。なのでspanで区切る処理で半角スペースを検知し、特殊文字(&nbsp;)で置きかえるようにしました。下記サンプルは半角スペースが問題なく表示されていると思います。

文字をフェードイン(半角スペースの処理追加)
http://jquerystudy.info/anime/3_text/02b_move.html/
function spanningFunc (_target){
	var elms = document.querySelectorAll(_target);
	elms.forEach(function (elm){
		var myText = elm.textContent;
		elm.innerHTML = null;
		myText.split('').forEach(function (c) {
			if (c == ' '){
				elm.innerHTML += '&nbsp;';
			}else{
				elm.innerHTML += ''+c+'';
			}
		});
	});
}

 
あとは同じ要領でanimeオブジェクトを作成するだけです。色々なプロパティを操作して演出を試行錯誤してみようと思います。

回転と拡大も加えたサンプル
http://jquerystudy.info/anime/3_text/03_sample.html/

 
今回はここまで
次回はボタンを押したらアニメするのではなく
ブラウザのviewに表示されたら自動でアニメを再生するようにします。
 
 

anime.js(10):Filterと補足

●Filterの利用

cssのfilterについても試して見ました。
→参考:can i use : filter
→参考:CSS3のfilterプロパティを使って画像に色々な効果を加えてみた

#fil_bright {
	filter:brightness(20%);
	transition:filter 300ms 0s ease;
}
#fil_bright:hover {
	filter:brightness(200%);
}

anime.jsはtranslateには対応していますが、filterには対応していません。なので以下のサンプルは機能しません。

var animeObj = anime({
	targets: '#fil_bright',
	brightness:'100%',
	duration: 6000,
	elasticity:800,
	autoplay:false
});

filterはcssでの操作で十分だと思うのですが、勉強ですので無理矢理anime.jsで制御してみました。anime.jsはobjectオブジェクトを操作できるので、それを操作し、その値を利用してfiterの値を変更しました。
→参考:JavaScript Object properties

object値を操作してfilterを操作
http://jquerystudy.info/anime/2_etc/12_filter_js.html/
var myObject = {
	myBright:'0%'//---%文字が利用できて便利
}
var animeObj = anime({
	targets: myObject,
	myBright:'100%',
	duration: 3000,
	elasticity:800,
	autoplay:false,
	run:runFunc,
});
function runFunc(){
	document.getElementById('fil_bright').style.filter = "brightness("+myObject.myBright+")";
}

上記のようにobject値を利用すればcssが対応している演出はほとんど実現できると思います(大抵はcssのみの操作で十分だと思いますが…)。
 
 

●Helperの確認

使う機会は少ないと思いますが、Helperとして用意された機能を確認しておきます。animeオブジェクト(インスタンス)に利用するのではなくstaticなメソッドやプロパティです。
→参考:Helper

・anime.speed

anime.jsを利用してるページ内すべてのアニメの速度を一律に変更するプロパティ。デフォルトは1で0.5を指定すれば半分の速度になる。注意点は1以上は設定できないこと(つまりデフォルトが最速設定)。

anime.speed = 0.5;

 

・anime.running

anime.jsを利用してるページ内すべてのアニメの情報を配列で返します。返される配列は複雑で扱いにくい。tweenMaxのisTweening()のように引数で対象を指定できたら便利なのに…。
→参考:tweenMax.isTweening()
→参考:.isActive()

var animeList = anime.running;

とはいえ、tweenMaxのisActive似た機能はあり(メソッドとプロパティの違いはあるものの)以前の記事で説明しました。
→参考:Check if the animation has finished with myAnimation.completed.

 

・anime.remove(target)

引数で指定した要素に設定されたanimeオブジェクトを削除します。アニメは停止しrestartもできなくなります。
前述のrunningも、これみたくtargetを指定できるようにすべきだと思う。

anime.remove('.item-2');

 

・anime.getValue(target, property)

指定したtargetのとpropertyを取得するメソッド。使いそうだけど以外と使わないかな?

anime.getValue('div', 'translateX');

 

・anime.path(pathEl)

これはパスモーションで利用したメソッドですね。公式サイトの例では第2引数が設定されているのですが説明がありません。どういう風に使うのだろう?
→参考:公式サイト-anime.path(pathEl)

var path = anime.path('svg path', 'translateX');

 

・anime.timeline()

これはタイムラインで利用したメソッドですね。私がjavaScriptのアニメライブラリを利用するのはシーケンシャルなアニメを作成するためなので利用頻度は高くなりそうです。

var timeline = anime.timeline();
timeline.add([instance1, instance2, ...]);

 

・anime.random(x, y)

指定範囲の乱数を取得するメソッドです。

anime.random(10, 40);

  
これで公式サイトの内容はだいたい学べたと思う。
 
 
 

anime.js(9):transformを利用した変形

●3D transformアニメ

css3のtransformプロパティを操作して立体的な(以前学んだkete.jsのような)アニメを作成できるか確認してみました。
→参考:CSS3リファレンス- transform
→参考:perspectiveプロパティとtransform:perspective関数の違い
 

・パース

 
cssの対応だけでパースをかけられるか試行錯誤していたのですが、予想以上に難航しました。しかし以下のサンプルを発見してなんとか実現できました。ポイントだったのはperspectiveの設定を回転させる要素ではなくコンテナ側に設定することでした。
→参考:3d perspective & anime.js

.container {
	height: 200px;
	width: 250px;
	perspective: 500px;
}
.box {
	height: 200px;
	width: 250px;
	background-color:#fca;
}

ちなみにコンテナと回転させる要素のwidthの値を揃えないとパースが歪みます。

.container {
	height: 200px;
	width:1000px;
	perspective: 500px;
}
.box {
	height: 200px;
	width: 250px;
	background-color:#fca;
}

しかし親要素の設定なしに実現したいので、さらに試行錯誤しました。perspectiveの初期値と最終地を揃えて以下のように記述することで実現できました。

パースのある回転(2)
http://jquerystudy.info/anime/2_etc/07_pers.html/
var animeObj = anime({
	targets: '.box',
	perspective:[500,500],
	rotateX: 360,
	duration: 6000,
	elasticity: 800,
	autoplay:false
});

 

・基準点

基準点はcssの設定だけで簡単にできました。値には100%以上も設定でき、200%に設定するとサンプルのように要素外を基準点に変形できます。

.box {
	height: 200px;
	width: 250px;
	background-color:#fca;
	transform-origin:50% 200%;
}

 

・skew

skewは問題なく利用できました。

anime({
	targets: '.box',
	skewY: '45deg',
	duration: 1000,
	elasticity: 800,
});

 
おしまい。
次回も続く予定
 
 
 

anime.js(8):パスアニメ

●パスに沿ったアニメ

パスに合わせて要素を移動できるライブラリはかなり珍しいと思う。
pathメソッドでパスを作成し、それをanimeオブジェクト内で利用する感じです。

svgのパスに沿ったアニメ
http://jquerystudy.info/anime/2_etc/00_test.html/
var mPath = anime.path('#motionPath path');
var motionPath = anime({
	targets: '#b1',
	translateX: mPath('x'),
	translateY: mPath('y'),
	rotate: path('angle'),
	easing: 'linear',
	duration: 20000,
	loop: true,
});

上記のサンプルではパスと要素が重なっているが、実際はパスの位置に関係なく要素の位置から相対的にパスに沿ってアニメします(つまり位置合わせ大変)。上記のサンプルはcssのposition:absoluteで位置を合わせていますが、その処理を省くと以下のようになります。

 
パスアニメを時間をずらして再生してみました。パスはデータ自体を参照しているため表示しなくても問題ありません。

電車のようなパスアニメ
http://jquerystudy.info/anime/2_etc/01_train.html/

 
objectタグで組み込んだsvgもcontentDocumentを利用すれば操作可能です。

objectタグで組み込んだsvgの利用
http://jquerystudy.info/anime/2_etc/02_object.html/
var svg = document.getElementById('pathSvg').contentDocument;
var mPath = svg.getElementById('mPath');

 
 

●SVGのモーフィング

svgのpolygonデータはモーフィングもできるそうなので試して見ました。マニュアルにはありませんでしたがfillもアニメできました。

ポリゴンをモーフィング
http://jquerystudy.info/anime/2_etc/03_morph.html/
var animeObj = anime({
	targets: '.shape polygon',
	points: '0,0 70,0 138,0 138,50 86,50 0,50',
	fill:'#aaccff',
	direction:'alternate',
	delay:500,
	loop:true
});

少し応用すればメニューなどに使えそうです。

 
 

●SVGのストロークアニメ

vivus.jsのようなストロークアニメも作成できます。ただしsobjectタグで表示されたsvgには対応していません。contentDocumentでパス情報を取得することは可能ですが、操作はできないのです。
 
vivis.jsと異なり、svgのプロパティもアニメできるのでcssに頼らずサンプルのようなアニメを作成することができます。あとストロークアニメではrestartメソッドは機能しないようです。

 
javaScriptは変数名にハイフンを利用できないので、fill-opacityのようなcssプロパティはfillOpacityのようなキャメルケースに置きかえられる仕組みになっています。

function fillFunc(){
	anime({targets:'.guideline',opacity:0,easing:'easeInOutSine',duration:500,delay:1000});
	anime({targets:'#font_line path',fillOpacity:1,easing:'easeInOutSine',duration:500,delay:1000});
	anime({targets:'#font_line path', strokeOpacity:0,easing:'easeInOutSine',duration:500,delay:1000});
}

 
今回はここまで。
次回はkute.jsのような3D的なアニメを作成できるか確認したいと思います。

anime.js(7):シーケンシャルなアニメ3

●promise

PromiseはjavaScriptも採用している非同期処理の仕組みです。これまでに学んだcompleteのコールバックやタイムラインで大抵のことは事足りますが、せっかくなのでメモ。
 
まずはシンプルにタイムラインではない、普通のアニメに対して利用してみました。finishedメソッドでpromiseオブジェクトを作成し、thenメソッドで完了した際の処理を設定します。

animeオブジェクトにpromiseを
http://jquerystudy.info/anime/1_advance/24_promise.html/
var animeObj=anime({targets:'.box',left:270,easing:'linear',duration:3000,autoplay:false});
var myPromise = animeObj.finished;
myPromise.then(resolve);
function resolve(){
	document.getElementById("b1").innerHTML="resolve";	
}

timelineオブジェクトに対してもfinishedメソッドやthenメソッドを利用できます。
タイムラインの最後のアニメでcompleteを設定するのと同じですが、明示的にタイムラインのすべてが終わったときの処理として分かりやすと思います。

timelineオブジェクトにpromiseを
http://jquerystudy.info/anime/1_advance/25_timeline.html/
var myTimeline = anime.timeline({targets: '.box',autoplay:false});
myTimeline.add({left:270}).add({top:270}).add({left:  0});	
var myPromise = myTimeline.finished;
myPromise.then(resolve);
function resolve(){
	document.getElementById("b1").innerHTML="resolve";	
}

 
 

failの設定はできない

promiseオブジェクトの便利なところは、処理が中断/失敗したときの設定もできる点なのですが、anime.jsに搭載されたpromiseにはfailの設定はできないようです。
そもそもアニメの処理に中断/失敗という概念?が無いので当然なのですが、アニメライブラリならあっても良いと思うのです。
jQueryを学んだときにも同じことを試していました(リンク先の「メモ」の項目)。
→参考:jQuery – fail()

anime.jsのpromiseにはfailの処理は設定できない
http://jquerystudy.info/anime/1_advance/26_prom_fail.html/

 
まずはpauseボタンが押されたときの処理を確認。pauseするだけでなく、ヘルパーメソッドのremoveを利用してanimeオブジェクト自体も削除しています。
→参考:Helper – remove

document.getElementById("btn_pause").onclick = function (){
	animeObj.pause();
	anime.remove('.box');
}

failの処理はjavaScriptの構文に合わせてthenメソッドの第2引数に設定しました。
→参考:Promise.prototype.then()

myPromise.then(resolve,fail);
function resolve(){
	document.getElementById("b1").innerHTML="resolve";	
}
function fail(){
	document.getElementById("b1").innerHTML="error";		
}

failの処理が設定できれば、アニメがキャンセルされたときの処理を追加できて便利だと思うのに残念です。
念のためtimelineオブジェクトのアニメに対しても試しましたが、やはりダメでした。

timelineオブジェクトのpromiseにもfailはダメ
http://jquerystudy.info/anime/1_advance/26b_timelin_fail.html/

 

allメソッド

javaScriptに備わっているPromise.allはanime.jsのpromiseオブジェクトにも利用できるのでサンプルを作成しました。
allメソッドを利用すると、設定したすべてのアニメが終了したときの処理を設定できます。

すべてのアニメが完了したら実行
http://jquerystudy.info/anime/1_advance/27_promise_all.html/
var prom_1 = anime_1.finished;
var prom_2 = anime_2.finished;
var prom_3 = anime_3.finished;
Promise.all([prom_1,prom_2,prom_3]).then(doneFunc);
function doneFunc(){
	alert('all anime is done');
}

これは演出が完了するまで操作を受け付けないようにしたい時などに利用できそうです。演出をキャンセルできるようにしたいところですが、ここれでもfailの設定はできないようです(未練がましい…)。
 
今日はここまで。
次回はパスアニメーションを学ぶ予定です。
 
 
 

anime.js(6):シーケンシャルなアニメ2

●タイムライン

addメソッドでアニメを追加できるtimelineは便利に見える。キーフレームの方が複雑なアニメにも対応できると思うけど、可読性が低くなりがちなので用途に合わせて使い分けていきたい。
 
まずはシンプルなサンプル。timelineメソッドで作成したタイムラインにaddメソッドでアニメを追加すると、順々に再生してくれます。

タイムラインにアニメを追加する
http://jquerystudy.info/anime/1_advance/18_timeline.html/
var myTimeline = anime.timeline({targets: '.box',autoplay:false});
myTimeline.add({left:270}).add({top:270}).add({left:  0});

初めは上記のようなleft/topではなくtranslateX/translateYを利用しました。そのさいに躓いたのでメモ。以下のサンプルは一見正しい処理に見えますが正常に機能しません。

【悪い例】translateだと機能しないの?
http://jquerystudy.info/anime/1_advance/18b_timeline.html/
var myTimeline = anime.timeline({
	targets: '.box',
	autoplay: false
});
myTimeline
	.add({translateX:270})
	.add({translateY:270})
	.add({translateX:  0});

これはanime.jsの問題ではなくcssの問題です(たぶん)。translateX=x/translateY=yは簡略構文で本来はtranslate(x,y)です。なので上記の構文では設定されてない値に0が補足され、次のように解釈されてしまうと思うのです。→translate(270,0)→translate(0,270)→translate(0,0)
 
ということで以下のように記述したら機能するようになりました。translateを利用するときはXとYの両方を設定するようにしましょう。

【良い例】translateでも機能するよ
http://jquerystudy.info/anime/1_advance/18c_timeline.html/
myTimeline
	.add({translateX:270,translateY:  0})
	.add({translateX:270,translateY:270})
	.add({translateX:  0,translateY:270});

もしキーフレームを利用すると以下のようなソースになります(delayの扱いが面倒ですし、プロパティが別々なのでアニメがイメージしにくいです)。
 
タイムラインの方が可読性が高いですがaddで区切られるのでアニメが入り交じるような複雑なアニメは実現できないので上手く使い分ける必要がありそうです。

var animeObj = anime({
		targets: '.box',
		translateX:[{value:270,duration:1000},{value:0,duration:1000,delay:1000}],
		translateY:[{value:270,duration:1000, delay:1000}],
		autoplay: false
	});

タイムラインならキーフレームで実現できなかった、アニメ毎のコールバックを設定できます。サンプルではアニメが完了する毎にcompFuncが処理されて、表示している数値が増えていきます。

アニメ毎にコールバックを受け取る
http://jquerystudy.info/anime/1_advance/19_callback.html/
myTimeline
	.add({left:270, complete:compFunc})
	.add({top: 270, complete:compFunc})
	.add({left:  0, complete:compFunc});

タイムラインは複数の要素のアニメも順次再生できます。

アニメ毎にコールバックを受け取る
http://jquerystudy.info/anime/1_advance/20_multi.html/
myTimeline
	.add({targets:'#b1',left:270,complete:compFunc})
	.add({targets:'#b2',left:270,complete:compFunc})
	.add({targets:'#b3',left:270,complete:compFunc})
	.add({targets:'#b4',left:270,complete:compFunc})
	.add({targets:'#b5',left:270,complete:compFunc})

 

offset

タイムラインにおいてaddされたアニメの開始を調整できる。delayと異なりマイナスの値が設定できたり、addの順番を無視した絶対指定が可能になっています。
 
以下のサンプルでは値に「-=300」と設定しているため、前のアニメが終わる0.3秒前にアニメが開始されます。※「-=」のような算術代入演算子が必要なことを忘れないでください。
→参考:Relative offset

myTimeline
	.add({left:270,easing:'linear'})
	.add({top: 270,easing:'linear',offset:'-=300'})
	.add({left:  0,easing:'linear',offset:'-=300'});

translateだとx、yの両方を設定するから思うような設定ができないかも(新しい設定に上書きされてしまう)。以下のサンプルは上記のサンプルとは異なった動きになります。

myTimeline
	.add({translateX:270,translateY:  0,easing:'linear'})
	.add({translateX:270,translateY:270,easing:'linear',offset:'-=300'})
	.add({translateX:  0,translateY:270,easing:'linear',offset:'-=300'});

算術代入演算子を利用せずに直接数値を設定すると、その時間にアニメが開始されます。
→参考:Absolute offset

offsetで再生タイミングを設定
http://jquerystudy.info/anime/1_advance/22_offset_abs.html/
myTimeline
		.add({left:270,easing:'linear',offset:1000})
		.add({top: 270,easing:'linear',offset:0})
		.add({left:  0,easing:'linear',offset:2000});

1つの要素の例だと分かりにくいので複数要素の例も確認しました。

offsetで再生タイミングを設定(2)
http://jquerystudy.info/anime/1_advance/23_offset_abs2.html/
myTimeline
	.add({targets:'#b1',left:270,offset:1000})
	.add({targets:'#b2',left:270,offset:0})
	.add({targets:'#b3',left:270,offset:2000})
	.add({targets:'#b4',left:270,offset:4000})
	.add({targets:'#b5',left:270,offset:3000})

次回はPromiseについて学ぶ予定です。
 
 
 

anime.js(5):シーケンシャルなアニメ1

●復習

 
厳密にはシーケンシャルではないけれど、パラメータ毎にdelayを設定してシーケンシャルっぽいアニメを作成できます。

delayを使った疑似シーケンシャルアニメ
http://jquerystudy.info/anime/1_advance/11_param.html/
var animeObj = anime({
	targets: '.box',
	translateX:{value:250},
	rotate:{value:360,delay:400},
	scale:{value: 2,delay:800},
	autoplay:false,
});

以前の記事でも紹介しましたが、値の設定にfunctionが利用できます。今回は値の利用にhelperのrandomメソッドを利用してみました。

→参考:anime.random()

delayの値にランダムを利用
http://jquerystudy.info/anime/1_advance/12_random.html/
var animeObj = anime({targets:'.box',left:'270px',easing:'linear',autoplay:false,
		delay:function(elm,index,ln){return anime.random(300,3000);}
	});

以前の記事でも紹介しましたが、間違いやすいので再掲。
数値を配列で設定すると初期値と最終値の設定となります。animeオブジェクトを作成した瞬間に最初の要素の値に設定されます(サンプルではleft=100)。
→参考:From > To values

配列は初期値の設定に利用する
http://jquerystudy.info/anime/1_advance/13_fromTo.html/
anime({targets:'.box',left:[100,270],easing:'linear',autoplay:false});

その場合の配列の要素数は2つで固定です。3つ以上設定すると誤動作します。

anime({targets:'.box',left:[100,270,150],easing:'linear',autoplay:false});

 
 

●キーフレームアニメ

本題のシーケンシャルアニメ。アニメを連結する場合は配列内に{}を利用して設定します。anime.jsではこのようなアニメをkeyframeアニメと呼んでいます。これも厳密にはシーケンシャルとはいえないかもしれません。コールバックも個別に設定することはできませんし…。
→参考:keyframe

基礎的なキーフレームアニメ
http://jquerystudy.info/anime/1_advance/14_seq.html/
var animeObj = anime({targets:'.box',easing:'linear',autoplay:false,
		left:[{value:270},{value:50},{value:200}]
	});

{}内にはvalueだけでなく、durationなどの設定も可能です。

詳細設定されたキーフレームアニメ
http://jquerystudy.info/anime/1_advance/15_seq2.html/
var animeObj = anime({targets:'.box',autoplay:false,
		left:[{value:270,duration:1000},
			{value:50,duration:500,delay:1000},
			{value:200,duration:1500,delay:500,easing:'linear'}
		]
	});

注意点として、delayは前のアニメが終わってからの待ち時間であるという点です。

キーフレームアニメでのdelayの扱い
http://jquerystudy.info/anime/1_advance/16_seq3.html/

 
以下のソースでleftの2番目のdelay(青字の部分)は、leftの1番目のアニメが終わってから500ms待ちます。topに設定されたアニメはleftとは別なので考慮されません。

var animeObj = anime({
	targets: '.box',
	left:[{value:270,easing:'linear',duration:500},
		{value:0,duration:500,easing:'linear', delay:500}],
	top:[{value:270,easing:'linear',duration:500, delay:500}],
	autoplay: false
});

プロパティ毎にキーフレームを設定することができます。ただ少し可読性が低くなりがち。

プロパティ毎にキーフレームアニメ
http://jquerystudy.info/anime/1_advance/17_seq4.html/
var animeObj = anime({targets:'.box',autoplay:false,
		translateX:[
			{ value: 270, duration:1000, delay:500},
			{ value:   0, duration:1000, delay:500}
		],
		translateY: [
			{ value:-100, duration:500},
			{ value: 100, duration:500, delay:1000},
			{ value:   0, duration:500, delay:1000}
		]
	});

ただし前回説明したように{}内にコールバックを設定することはできません。

キーフレーム毎にcompleteを設定してもダメ
http://jquerystudy.info/anime/1_advance/09_keyframe_comp3.html/
var animeObj = anime({targets:'.box',
	left:[{value:270,duration:1000,complete:compFunc},
	{value:0,duration:1000,complete:compFunc}],
	easing:'linear',loop:2,autoplay:false
});

キーフレームの外にはcompleteを設定できます。

キーフレームアニメが終わったらcompleteは処理される
http://jquerystudy.info/anime/1_advance/10_keyframe_comp4.html/
var animeObj = anime({targets:'.box',
	left:[{value:270,duration:1000},
	{value:0,duration:1000}],
	complete:compFunc,
	easing:'linear',loop:2,autoplay:false
});

 
今回はここまで。次回はタイムラインについて学ぶ予定です。
キーフレーム毎にコールバックが設定できない点を補えるような使用になっていることを期待したいです。
 
 

anime.js(4):前回の続き+コールバック

●基礎的な利用3

値に相対値を利用できるが、クリックするたびに移動するような処理はできないようです…。
→参考:Property values

anime({targets:'.box',left:'+=100',easing:'linear',autoplay:false});

これは初期値の2倍にしたいとか、そういうときに便利なのだと思う。

anime({targets:'.box',scale:'*=2',autoplay:false});

kute.jsでは変形の基準点を設定できた。anime.jsでは設定できないが、そもそも基準点はcssで設定できるので上記サンプルで試しています。以下のようにtransform-originを50%に指定することで要素の真ん中が変形の基準点になります。
→参考:can i use ? (transform-origin)

#b1{
	position:absolute;
	top:100px;
	left:100px;
	background-color:#FFCCCC;
	transform-origin:50%,50%;
}

もしクリックするたびに移動したいならjavaScriptで値を変えていくしかないと思う。

ボタンを押すたびに移動する
http://jquerystudy.info/anime/0_core/27_move.html/
var elmX = 0;
document.getElementById("btn_move").onclick = function (){
	elmX +=100;
	anime({targets:'.box',left:elmX});
}

ボタンを連打すると謎挙動する場合があったので移動中は処理を受け付けないようにした。

ボタンを押すたびに移動する
http://jquerystudy.info/anime/0_core/28_move2.html/

 
アニメライブラリでは要素がアニメ中か否かを取得する手段は必要。tweenMaxではisTween()やisActive()がある。
→参考:tweenMax – .isActive()
→参考:tweenMax – TweenMax.isTweening()
 
anime.jsでもあるはずと探したが中々見つからず時間を浪費した。実際はcallbackのcompleteの項目にひっそりと紹介されていた。tweenMaxのメソッド達とは異なりプロパティになっています。
→参考:Check if the animation has finished with myAnimation.completed.

document.getElementById("btn_move").onclick = function (){
	if (myAnime.completed == false) return;
	elmX +=100;
	myAnime = anime({targets:'.box',left:elmX});
}

 
 

●コールバック

アニメが完了したときの処理はcompleteプロパティにfunctionを設定する。functionにはanimeオブジェクトが渡される。

アニメが完了したらcompleteと表示
http://jquerystudy.info/anime/1_advance/00_complete.html/
var animeObj = anime({targets:'.box',left:270,complete:compFunc,easing:'linear',autoplay:false});
function compFunc(anim){
	document.getElementById("b1").innerHTML="complete";
}

引数にはanimeオブジェクトではなくアニメしている要素の方が嬉しい。なのでanimeオブジェクトを調べて要素を取得できるか試した。

animeオブジェクトから要素を抽出
http://jquerystudy.info/anime/1_advance/01_complete.html/
function compFunc(anim){
	var test = anim.animatables[0].target;
	test.innerHTML="complete";
}

前回説明した「functionを利用した値設定」では引数に要素(target)があったので、ここでも要素を期待したのですがありませんでした。
→参考:The function accepts 3 arguments: target, index, targetsLength.
 
とはいえ、これは2つ先のサンプルが指す使用のためなのでしょう。completeは各オブジェクトごとの設定ではなくanimeオブジェクトごとの設定なのです。ということでfunction内のthisもanimeオブジェクトです。

複数の時は少し面倒だけど、animeオブジェクトから要素を抽出することは可能でした。

animeオブジェクトから要素を抽出(複数)
http://jquerystudy.info/anime/1_advance/02_complete.html/
function compFunc(anim){	
	var elmNum = anim.animatables.length;
	for (var i=0; ianim.animatables[i].target;
		test.innerHTML="complete";	
	}
}

注意点としては個別のアニメ毎にcompleteが発生するわけではなく、あくまでも作成したanimeオブジェクトのすべてのアニメが完了したときにcompleteは発生します。

animeオブジェクトから要素を抽出(複数+遅延)
http://jquerystudy.info/anime/1_advance/02b_complete.html/

 
あとanimeオブジェクトを調べていたらマニュアルには存在しないresetメソッドを発見。試して見た。問題なく利用できそう。seekを0にする場合と異なり、アニメ再生中にはリセットできないようです。ちなみに前回紹介したseek(0)もアニメ再生中には効きません。

完了したアニメを元に戻すresetメソッド
http://jquerystudy.info/anime/1_advance/03_reset.html/
document.getElementById("btn_reset").onclick = function (){
	animeObj.reset();
}

beginを利用すると、delayによる待ち時間が終わりアニメを再生するときの処理が設定できます。

アニメ開始時の処理を設定
http://jquerystudy.info/anime/1_advance/04_begin.html/
var animeObj = anime({targets:'.box',left:270,begin:beginFunc,delay:3000,autoplay:false});
function beginFunc(anim){
	document.getElementById("b1").innerHTML="begin";
}

Updateを利用するとanimationFrame毎に実行する処理を設定できます。注意点としてはdelayでの待機中も処理されるという点です。

毎フレームの処理を設定(待機中も含む)
http://jquerystudy.info/anime/1_advance/05_update.html/
anime({targets:'.box',left:270,update:updateFunc,easing:'linear',delay:3000,autoplay:false});

もし待機中には処理したくない場合はrunプロパティで処理を設定します。

毎フレームの処理を設定(待機中は除く)
http://jquerystudy.info/anime/1_advance/06_run.html/
anime({targets:'.box',left:270,run:runFunc,easing:'linear',delay:3000,autoplay:false});

 

ループ時のcompleteの扱い

繰り返しの設定も含め1つのアニメと見なされる。そのため無限ループでは永遠にcompleteは処理されない

ループが終わってから処理される
http://jquerystudy.info/anime/1_advance/07_loop_comp.html/

 

ループが終わってから処理される(往復)
http://jquerystudy.info/anime/1_advance/08_loop_comp2.html/

 
キーフレーム毎にcompleteを設定することはできない

キーフレーム毎にcompleteを設定してもダメ
http://jquerystudy.info/anime/1_advance/09_keyframe_comp3.html/
var animeObj = anime({targets:'.box',
	left:[{value:270,duration:1000,complete:compFunc},
	{value:0,duration:1000,complete:compFunc}],
	easing:'linear',loop:2,autoplay:false
});

キーフレームの外にはcompleteを設定できます。

キーフレームアニメが終わったらcompleteは処理される
http://jquerystudy.info/anime/1_advance/10_keyframe_comp4.html/
var animeObj = anime({targets:'.box',
	left:[{value:270,duration:1000},
	{value:0,duration:1000}],
	complete:compFunc,
	easing:'linear',loop:2,autoplay:false
});

動作毎にfunctionを実行したい場合はタイムラインとかを利用するのだと思う。
次回は、それを含めシーケンシャルなアニメについて学ぶ。
 
 
 
 

anime.js(3):基礎的な利用2

●基礎的な利用2

 
アニメを最初から再生するrestartメソッドがあります。

restart:もう一度アニメを再生
http://jquerystudy.info/anime/0_core/12_restart.html/
document.getElementById("btn_restart").onclick = function (){
	animeObj.restart();
}

seekメソッドで引数に0を渡すことでリセットが可能です(kute.jsにはできなかった)。本来はアニメを指定した時間の状態にするメソッドです。seekで戻したアニメはresstartメソッドだけではなく、playメソッドでも再生できる。getSeekとかは無いみたい。
→参考:Seek

reset:seekを利用したリセット
http://jquerystudy.info/anime/0_core/13_seek.html/
document.getElementById("btn_reset").onclick = function (){
	animeObj.seek(0);
}

kute.jsのfromToの様に初期値を設定することもできる。特別なメソッドを使うのではなく配列で値を指定するだけです。[初期値,最終値]
→参考:From > To values

var animeObj = anime({targets:'.box',left:[100, 270],easing:'linear',autoplay:false});

アニメを再生しなくてもanimeオブジェクトを作成した段階で、要素は初期値の状態に設定されてしまう。これが嫌な場合はアニメを再生する直前にanimeオブジェクトを作るしかない。ただしseekメソッドでリセットしても最初に配置した場所ではなく、初期値の場所に配置されます。

document.getElementById("btn_play").onclick = function (){
	animeObj = anime({targets:'.box',left:[100, 270],easing:'linear',autoplay:false});
	animeObj.play();
}

イージングのelasticはelasticityオプションでバネ具合を調整できる。
→参考:Property parameters

anime({targets:'#b1',left:'270px',easing:'easeOutElastic',elasticity:   0,duration:1000,autoplay:false});
anime({targets:'#b2',left:'270px',easing:'easeOutElastic',elasticity: 500,duration:1000,autoplay:false});
anime({targets:'#b3',left:'270px',easing:'easeOutElastic',elasticity:1000,duration:1000,autoplay:false});

再生を遅らせる場合はdelayオプションを設定する。

delay:アニメの再生を遅らせる
http://jquerystudy.info/anime/0_core/16_delay.html/
var anime_2 = anime({targets:'#b2',left:270,delay:500,easing:'linear',autoplay:false});

複数の要素を順次送らせるためには値指定にfunctionを利用する。functionには要素とインデックス番号と総要素数が引数として送られるので、それを利用する。functionは様々な値設定に利用できます。
→参考:Function based property parameters
→参考:Function based values

function:関数を利用した値設定
http://jquerystudy.info/anime/0_core/17_function.html/
var animeObj = anime({targets:'.box',left:270,easing:'linear',autoplay:false,
	delay:function(elm,index, ln){
		return index * 500;
	}
});

再生方向はdirectionオプションを設定することで変えられます。

anime({targets:'.box',left:270,direction:'reverse',easing:'linear',autoplay:false});

directionオプションをalternateに設定すると往復再生ができます。往復で1再生ということに注意してください。

anime({targets:'.box',left:270,direction:'alternate',easing:'linear',autoplay:false});

loopオプションに数値を設定することで繰り返す回数を指定できます。

 anime({targets:'.box',left:270,easing:'linear',loop:2,autoplay:false});

loopオプションにtrueを設定すると無限ループになります。

anime({targets:'.box',left:270,easing:'linear',loop:true,autoplay:false});

directionをalternateに設定していても片道で1ループ扱いです。以下のサンプルではloopに5を設定しているので2往復半となります。

anime({targets:'.box',left:270,easing:'linear',direction:'alternate',loop:5,autoplay:false});

でもalternateのloopにdelayを設定すると往復したときにしかdelayが発生しない…

var animeObj = anime({targets:'.box',left:270,duration:200,delay:300,
		direction:'alternate',easing:'linear',loop:true,autoplay:false});

ループではなく2つのアニメを連結したら可能になりました。キーフレームについては次回に色々試したいと思います。
→参考:keyframes

var animeObj = anime({targets:'.box',
	left:[{value:270,duration:200,delay:1000},{value:0,duration:200,delay:1000}],
	easing:'linear',loop:true,autoplay:false});

 
相対的な値の設定についても今回学ぼうと思っていたのですが、躓いたので次回にします。
おしまい