POPSブログ

SVG.js アニメーション(1)

382

  Category:  javascript2016/03/06 pops 

SVG.js アニメーションについて調べてみます。一部当方独自の方法をも取りますが、一応正常に可動します。何も知らない者が「SVG」を触るのですから大変無謀なことです。

 

SVG.js アニメーションのテスト

 

ご注意、Chrome.Firefox.IE11(一部機能しません)などSVGに対応したブラウザでご覧ください。Chromeを推奨します。

 

SVG.js 使用の基本的な説明


基本的な説明下記ページ参照ください。
【参照】当方の記事: SVG.js を使用してsvgコンテンツを作り表示します

このページとデモページにサンプルと共にJSを記載しています。余り説明などしていませんので、感覚的に違いなど理解ください。
Chrome.Firefox.IE11で確認しながら進めますが、その他のブラウザは未確認です。

 

SVG.jsのDropShadowはエラーで機能しません。カスタムDropShadowは独自のもので、以下4個をdropshadow-custom.jsで設定している。

【参照】当方の記事: SVG.js DropShadowの自作とBlur


 

SVG.js アニメーション


SVGではあらゆる所の変更が比較的簡単に出来るので、アニメーションの対象が多いのですが、他のアニメーションと比較すれば貧弱です。SVG.jsでは簡単にアニメーション実行出来る様に工夫されています。
SVGは、CSS、JavaScript、でも操作可能ですから、今後はその方向に進み、出来るこ事が多彩になると思います。
SVGは、他のアニメーションでは難しい「パス」の操作が簡単ですので、その特徴を生かしたアニメーションが可能です。


SVG.jsアニメーション書式

 

● SVG.jsアニメーション書式


アニメーション書式
default値は、duration 1000ミリ秒、ease <> です
animate(duration,ease,delay)

次の書き方もOKです
animate({duration:1000,ease:'=',delay:4000})

簡略は
animate()
下記と同等です
animate(1000,'<>')

rect形を1000ミリ秒遅延、速度1000ミリ秒、ease outで塗りを#f03色にアニメします
rect.animate(2000,'>',1000).attr({ fill:'#f03'})

速度、秒単位なら
animate('s1.5')

● アニメーション対象メソッド
以下、SVG.jsの「Syntax sugar」が対象に成ります。attr()使用の場合は「ブラウザ」によっては機能しない事があります。


x(), y(), move(),cx(), cy(), center()
fill(), stroke(), rotate(), skew(), scale(), matrix(), opacity(), radius()

勿論attrも使用できますが、機能するとは限らない
attr()

● 同じインスタンスに複数のアニメ設定は全て上手くは行かないのでグループ化した方が良い場合が多い。

center()で設定した要素に対して、移動させなければ、回転、拡大は上手く動作する、(移動すれば狂うので注意)。
移動が必要ならグループ化して、グループを動かす。
下の、「アニメーションTEST」3番6番を参照ください。

問題が起きたら自己解決してください。参考アニメ例、NET資料などほぼ存在しません。



上手く行く
rect.animate().x(100).fill('#4169E1')
rect.animate().attr({'x':100,'fill':'#FFD700'})

回転、拡大と組み合わせると上手く行かない
rect.animate().center(100,50).scale(1.2,1.2)
rect.animate().attr({'x':100}).scale(1.2)

● center()設定したインスタンスの回転、拡大は上手く行く。
移動が必要ならば、グループ化して「グループ」を移動した方が良い。


rect.center(100,50)
rect.animate().scale(1.2)
rect.animate().rotate(60)

● 複数の違うインスタンスを同時にアニメする。
インスタンスを列挙すれば実行します。


rect1.animate().....
rect2.animate().....
rect3.animate().....

● delay
delay値を設定の場合に、動かす時after()を実行しないと遅延しない。困るナ

以前は正常に動作していて、現在異常なのかも知れません....、真意は不明です。


delay正常遅延する
rect.animate(1000,'-',1000).attr({'fill':'#000'})
点滅する
rect.animate(1000,'-',1000).attr({'fill':'#000'}).loop()

------------------------------------------
動かす時ダミーで遅延してafter()を実行
下記の様に往復している場合はloop()は上手く機能しない、片道なら機能する
rect.animate(1000,'',2000).after(function(){
	this.animate(1000,SVG.easing.bounce).x(100).after(function(){
		this.animate().x(20)
	})
})

● after()
コールバックです。アニメーション終了後実行します。


rect.animate(1000).after(function(){
	//処理を書く
	beer.gokkun.umai.mou1pai
})
往復で条件を違わせる
rect.animate(1000,SVG.easing.bounce).x(100).after(function(){
	this.animate(500).x(0)
})
往復で条件が同じなら
rect.animate(1000).x(100).after(function(){
	this.animate(1000).x(0)
})
loop(true)をつけて同じ結果です
rect.animate(1000).x(100).loop(true)

● loop()
loop()は往復のアニメ構造ではなく、下記の様な片道のアニメ構造の場合に有効のようです。(after()があると機能しません)
loop()の解除には、loop()の付かないアニメを実行すれば上書きされて指定の位置で停止できる。
アニメおよびloop()を削除するメソッドは有りません。


引数数値はループ回数
引数 true はアニメーションで戻るか

半端に、無限ループ、停電では止まるらしい、電気量金はガッチリ請求されます
rect.animate(1000).x(100).loop()
半端に動き、終点でお泊り
rect.animate(1000).x(100).loop(3)
スムーズ往復、始点に朝帰り
rect.animate(1000).x(100).loop(3,true)

点滅する
rect.animate(500,'-',500).attr({'fill':'#000'}).loop()

------------------------------------

無限ループ、スムーズ往復
loop(0,true)
スムーズに行ってスムーズに戻る、始点-終点-始点
loop(1,true)
行って、瞬間移動で戻るまた行く、始点-終点-始点-終点
loop(1)
loop(1,false)

● stop()
stop()はアニメの削除では有りません(jQueryのstopと勘違いし易い)。アニメを停止するならアニメを上書きすれば指定位置で止まる。「SVG」の宿命かな。
特に、loop()設定の場合は注意が必要です。状態をみて適切な処理を考えます。


stop実行の位置で停止します
rect.stop()
アニメを省略して、所定の位置に即座に移動しますが、loop()設定があると停止ではなくまた動き出すフシギ
rect.stop(true)

------------------------------------

アニメ上書きで、指定位置で停止させる、loop()をつけなければloop()はなくなる
rect.animate(1000).x(100).loop(0,true)
rect.stop(true)
rect.animate(1).x(20)

● during()
animate()のイベント毎に何らかの設定変更を行える仕組みのようです。通常のアニメでは出来ない設定変更、つまりインスタンス化されたものならばアニメさせる事が可能です。
下記は、マニュアルの例です。便利ですが計算が大変です。数をこなせば理解出来ると思います。

下記、during()アニメーションの例を見たほうが判ると思います。


使用する変数を用意する、名前は自由
var position
  , from=100
  , to=300
アニメとduringを実行する
rect.animate(3000).move(100,100).during(function(pos){
  計算式を作る
  position=from+(to-from)*pos 
})
---------------------------------------------------

pos の値は 0 から 1 の値です、アニメの最後が 1 に成ります
何らかのインスタンス.attr({'x':position})
インスタンスが100から300に移動します

角度はこの式ではだめのようですので動くよう式を作ります
var angle

0から45度まで回転の例
angle=(1-pos)*45
対象インスタンス.rotate(angle)

3 during()アニメーションの9番「during() FadeIn 回転」参照
---------------------------------------------------

計算式さえ作ればattr()に限らず何でも出来る

rect.animate().x(100).during(function(pos){
  計算式を作り実行させる
  rect2.attr(...)
  rect3.attr(...)
  circle1.attr(...)
})

during()のmorph
size(w,h)のような場合は下記の様にmorph(数のモーフィング)を利用します。morphの正体は関数ですが、「%」等であってもposの値によって変換してくれます。7番「duringアニメーション縦横」参照


morphは次を実行します
function(from,to){return at({from:from,to:to},pos)}

---------------------------------------------------
マニュアルの例

size()ならそれぞれのアニメ実行時点の from,to 値を変化させてくれます
posの値は0から1に変化します

rect.animate(3000).move(100,100).during(function(pos,morph) {
 // numeric values
 ellipse.size(morph(100,200),morph(100,50))
 // unit strings
 ellipse.attr('cx',morph('20%','80%'))
 // hex color strings
 ellipse.fill(morph('#333','#ff0066'))
})

その他ありますが、ここでは省略しますので、マニュアル参照ください。


SVG.jsのEasing

SVG.jsのEasingはCSS3のEasingでは有りません。SVG.js独自のEasingに成ります。
「easing書式」は下記の通りで、記号を表記します。
それ以外のEasingはSVG.js専用のプラグイン「svg.easing.js」が必要になります。



easing書式

All available ease types are:
<>: ease in and out
>: ease out
<: ease in
-: linear
=: external control 外部制御
a function
For the latter, here is an example of the default <> function:
function(pos) { return (-Math.cos(pos * Math.PI) / 2) + 0.5 }

● EasingのSAMPLE

easeのテストを行えます。 RECT形を「クリック」で、アニメーション移動します、右ボタン一括移動

赤色RECT形は「プラグイン」の quadInOut bounce に成ります。


アニメーションTEST 1

アニメーション移動と回転などの振る舞いを見てみます。jQueryなどとは違う所が有りますので注意ください。
一番簡単な構成であるrectで動かします。


1番、移動は簡単です / 2番、回転を伴うとNG / 3番、アニメ移動と回転はグループ化


サンプルJS


	//TEST1
	//エレメントID
	var draw=SVG('test-anime-1a').size(160,160)

	//rect1
	var test_rect1=draw.rect(40,40).attr({'fill':'#40E0D0'}).center(40,50)//.move(20,30)
	//rect2
	var test_rect2=draw.rect(40,40).attr({'fill':'#4169E1'}).center(40,100)

	//ボタン
	var test_btn1=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(140,140)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	test_btn1.click(function(){
		test_rect1.animate().x(100).after(function(){
			this.animate().x(20)
		})
		test_rect2.animate().center(120,100).after(function(){
			this.animate().center(40,100)
		})
	})

	var txt=draw.text('1 x()とcenter()アニメ移動').font({leading:0.8})

	//-------------

	//TEST2
	//エレメントID
	var draw=SVG('test-anime-1b').size(160,160)

	//rect3
	var test_rect3=draw.rect(40,40).attr({'fill':'#40E0D0'}).center(40,50)
	//rect4
	var test_rect4=draw.rect(40,40).attr({'fill':'#4169E1'}).center(40,100)

	//ボタン
	var test_btn2=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(140,140)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	test_btn2.click(function(){
		test_rect3.animate().x(100).rotate(180).after(function(){
			this.animate().x(20).rotate(0)
		})
		test_rect4.animate().center(120,100).rotate(180).after(function(){
			this.animate().center(40,100).rotate(0)
		})

	})

	var txt=draw.text('2 x()とcenter()の回転 NG').font({leading:0.8})

	//-------------

	//TEST3
	//エレメントID
	var draw=SVG('test-anime-1c').size(160,160)

	//rect5
	var group5=draw.group()
	var test_rect5=group5.rect(40,40).attr({'fill':'#40E0D0'}).center(40,50)
	//rect6
	var group6=draw.group()
	var test_rect6=group6.rect(40,40).attr({'fill':'#4169E1'}).center(40,100)

	//ボタン
	var test_btn3=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(140,140)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	test_btn3.click(function(){
		test_rect5.animate().rotate(180).after(function(){
			this.animate().rotate(0)
		})

		group6.animate().x(80)
		test_rect6.animate().rotate(180).after(function(){
			group6.animate().x(0)
			this.animate().rotate(0)
		})

	})

	var txt2=draw.text('center()回転 OK').font({size:10,leading:0.8}).move(70,45)
	var txt=draw.text('3 回転 group移動 OK').font({leading:0.8})


透明度の変更は fill stroke 個別でも fill-opacity stroke-opacity で変更可能ですから処理によっては便利です。但し、5番のデモ、はopacityで2つ一緒に変更しています。


個別に透明度を設定
rect.attr({'fill-opacity':0.5})
rect.attr({'stroke-opacity':0.5})
個別に透明度をアニメ
rect.animate(1000).attr({'fill-opacity':0})
rect.animate(1000).attr({'stroke-opacity':0})

下は主にattr()形式 /4番、色変更strokeもOK / 6番、アニメ移動とSCALEはグループ化


サンプルJS


	//TEST4
	//エレメントID
	var draw=SVG('test-anime-1d').size(160,160)

	//rect7
	var test_rect7=draw.rect(40,40).attr({'fill':'#40E0D0'}).center(40,50)
	//rect8
	var test_rect8=draw.rect(40,40).attr({'fill':'#FF0000'}).center(40,100)

	//ボタン
	var test_btn4=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(140,140)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	test_btn4.click(function(){
		test_rect7.animate().x(100).fill('#4169E1').after(function(){
			this.animate().x(20).fill('#40E0D0')
		})
		test_rect8.animate().attr({'x':100,'fill':'#FFD700'}).after(function(){
			this.animate().attr({'x':20,'fill':'#FF0000'})
		})
	})

	var txt=draw.text('4 アニメ移動と色変更').font({leading:0.8})

	//-------------

	//TEST5
	//エレメントID
	var draw=SVG('test-anime-1e').size(160,160)

	//rect9
	var test_rect9=draw.rect(40,40).attr({'fill':'#40E0D0'}).center(40,50)
	//rect10
	var test_rect10=draw.rect(40,40).attr({'fill':'#FF0000'}).center(40,100)

	//ボタン
	var test_btn5=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(140,140)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	test_btn5.click(function(){
		test_rect9.animate().x(100).opacity(0).after(function(){
			this.animate().x(20).opacity(1)
		})
		test_rect10.animate().attr({'x':100,'opacity':0}).after(function(){
			this.animate().attr({'x':20,'opacity':1})
		})
	})

	var txt=draw.text('5 アニメ移動と透明度').font({leading:0.8})

	//-------------

	//TEST6/scale移動は困難でグループ化
	//エレメントID
	var draw=SVG('test-anime-1f').size(160,160)

	//rect11
	var group11=draw.group()
	var test_rect11=group11.rect(40,40).attr({'fill':'#40E0D0'}).center(40,50)
	//rect12
	var group12=draw.group()
	var test_rect12=group12.rect(40,40).attr({'fill':'#FF0000'}).center(40,100)

	//ボタン
	var test_btn6=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(140,140)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	test_btn6.click(function(){
		test_rect11.animate().scale(1.5).after(function(){
			this.animate().scale(1)
		})
		group12.animate().x(100)
		test_rect12.animate().scale(1.5).after(function(){
			group12.animate().x(0)
			this.animate().scale(1)
		})
	})

	var txt2=draw.text('center()拡大 OK').font({size:10,leading:0.8}).move(70,45)
	var txt=draw.text('6 拡大 group移動 OK').font({leading:0.8})


delay loop at
at はページ内のマウスのイベントなどで、設定範囲内でアニメーションする仕組みを作れる。(マニュアル参照)


サンプルJS


	//エレメントID
	var draw=SVG('test-anime-1g').size(160,160)

	//rect13
	var test_rect13=draw.rect(40,40).attr({'fill':'#40E0D0'}).center(40,50)
	//rect14
	var test_rect14=draw.rect(40,40).attr({'fill':'#FF0000'}).center(40,100)

	//ボタン
	var test_btn7=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(140,140)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	test_btn7.click(function(){
		test_rect13.animate(1000,'',2000).after(function(){
			this.animate(1000,SVG.easing.bounce).x(100).after(function(){
				this.animate().x(20)
			})
		})
		test_rect14.animate(1000,'-',1000).attr({'fill':'#000'}).after(function(){
			this.animate().attr({'fill':'#FF0000'})
		})
	})

	var txt=draw.text('7 delay 2000 下1000').font({leading:0.8})

	//-------------

	//エレメントID
	var draw=SVG('test-anime-1h').size(160,160)

	//rect15
	var test_rect15=draw.rect(40,40).attr({'fill':'#40E0D0'}).center(40,50)
	//rect16
	var test_rect16=draw.rect(40,40).attr({'fill':'#FF0000'}).center(40,100)

	//ボタン
	var test_btn8=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(140,140)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	test_btn8.click(function(){
		this.hide()
		test_rect15.animate(1000).x(100).loop(0,true)
		test_rect16.animate(500,'-',500).attr({'fill':'#000'}).loop()
	})

	var txt=draw.text('8 上loop(0,true) 下loop()').font({leading:0.8})

	//-------------

	//エレメントID
	var draw=SVG('test-anime-1i').size(160,160)

	var animation=draw.rect(40,40).attr({'fill':'#40E0D0'}).move(10,60).animate('=').move(110,60)

	document.onmousemove=function(event){
		animation.at(event.pageX/1000)//event.clientX
	}

	var txt=draw.text('9 at').font({leading:0.8})


オリジナルLoop (登録商標テキトウ印)
1、3番はOKである / 2番 繰り返し回転ステップモータの様でギコチない、時計秒針用に使えるかも


サンプルJS


	//エレメントID
	var draw=SVG('test-anime-1j').size(160,160)

	//rect
	var loop_rect=draw.rect(40,40).attr({'fill':'#40E0D0'}).center(40,50)
	loopAnime()

	//LOOP
	function loopAnime(){
		loop_rect.animate(2000,SVG.easing.bounce).x(100).after(function(){
			this.animate(1000).x(20).after(function(){
				loopAnime()//回帰
			})
		})
	}

	var txt=draw.text('1 after()在っても繰り返し').font({leading:0.8})

	//-------------

	//エレメントID
	var draw=SVG('test-anime-1k').size(160,160)

	//rect
	var loop_rect2=draw.rect(40,40).attr({'fill':'#40E0D0'}).center(80,80)
	loopAnime2()

	//LOOP2
	function loopAnime2(){
		loop_rect2.animate(200).transform({rotation:25}).after(function(){
			loopAnime2()//回帰
		})
	}

	var txt=draw.text('2 繰り返し回転').font({leading:0.8})

	//-------------

	//エレメントID
	var draw=SVG('test-anime-1l').size(160,160)

	//rect
	var loop_rect3=draw.rect(40,40).attr({'fill':'#40E0D0'}).center(80,80)
	var rotation_angle=0
	setTimeout(function(){loopAnime3()},20)

	//アニメ
	function loopAnime3(){
		rotation_angle +=5
		loop_rect3.transform({rotation:rotation_angle})
		setTimeout(function(){loopAnime3()},20)
	}

	var txt=draw.text('3 setTimeout繰り返し回転').font({leading:0.8})


stop
3個とも、loop(0,true)で永久左右運動をしています。ボタンを押せば stop() します。

1番、その場で停止します。
2番左右いずれかに戻るが、停止していない、しばらくすると暴れる。「コラ止まらんカイ」
3番は停止後強制移動(強制送還)しています。


loop()は便利ですが、反面、完全に停止させたい場合などは、工夫が必要のようです。
「暴れる君」には「コラ止まらんカイ」を言えば止まります。

サンプルJS


	//エレメントID
	var draw=SVG('test-anime-1m').size(160,160)

	//rect17
	var test_rect17=draw.rect(40,40).attr({'fill':'#40E0D0'}).center(40,50)
	test_rect17.animate(1000).x(100).loop(0,true)

	//ボタン
	var test_btn17=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(140,140)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	test_btn17.click(function(){
		test_rect17.stop()
	})

	var txt=draw.text('1 stop()').font({leading:0.8})

	//-------------

	//エレメントID
	var draw=SVG('test-anime-1o').size(160,160)

	//rect18
	var test_rect18=draw.rect(40,40).attr({'fill':'#FF0000'}).center(40,50)
	test_rect18.animate(1000).x(100).loop(0,true)

	//ボタン
	var test_btn18=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(140,140)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	test_btn18.click(function(){
		test_rect18.stop(true)
		//コラ止まらんカイ
		//test_rect18.animate(1).x(20)
	})

	var txt=draw.text('2 stop(true) 変だ.アバレル').font({leading:0.8})

	//-------------

	//エレメントID
	var draw=SVG('test-anime-1p').size(160,160)

	//rect19
	var test_rect19=draw.rect(40,40).attr({'fill':'#40E0D0'}).center(40,50)
	test_rect19.animate(1000).x(100).loop(0,true)

	//ボタン
	var test_btn19=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(140,140)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	test_btn19.click(function(){
		test_rect19.stop()
		test_rect19.center(40,50)
		test_rect19.attr({'fill':'#FFD700'})
	})

	var txt=draw.text('3 stop()後 強制移動').font({leading:0.8})


 

アニメーションTEST 2(具体的な例)

画像塗り、陰影を使用する観点から、下記の様な考え方と構造でアニメーションTESTを行う。構造が変わればアニメーションの方法も変わるだろうし、ここは慣れが必要です。


1. 画像塗りのために、要素はcenter()が基本で拡大、回転も上手く機能する。
2. 陰影を使用することも考慮してcenter()がベターである。
3. transformの使用はなるべく控えています。(使用は自由です...)
3. 複合アニメーションの場合はグループ化して不具合を抑える。(グループ化することが多い)
4. 方法が多数ありますから数をこなして覚えるのが1番です。


グループ以外rect等でcenter()設定をしているのが原因か、transformは通常のanimate()では正常な動きをしない場合もある様です(少し難しい)。during()ではanimate()ではないから上手く行く。
transformはグループ用で使用すべきか...この辺は個人の自由です。


● SAMPLE 1

1 通常のアニメーション
3番、rotate回転(transformでも結果は同じ)


サンプルJS


	//エレメントID
	var draw=SVG('graphics-8a').size(160,160)

	//rect
	var anime_rect=draw.rect(40,40).attr({'fill':'#40E0D0','stroke':'#FFF','stroke-width':2}).center(40,80)
	.attr({'filter':'url(#dropShadow2)'})//陰影

	//ボタン
	var anime_btn1=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(140,140)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	anime_btn1.click(function() {
		anime_rect.animate(1000).x(100).after(function(){
			this.animate(1000).x(20)
		})
	})

	var txt=draw.text('1 アニメーション移動').font({leading:0.8})

	//-------------

	//エレメントID
	var draw=SVG('graphics-8b').size(160,160)

	//image 100x100
	var image=draw.image('/main/images/testImage108.jpg').size(160,160).center(80,80).scale(100/160)
	//rect
	var anime_rect2=draw.rect(100,100).attr({'fill':image}).radius(10).center(80,80).rotate(30)
	//オリジナルdropShadow
	anime_rect2.attr({'filter':'url(#dropShadow2)'})
	//アニメ実行
	animeloop()

	//afterアニメはloop()で繰り返さないので
	//loop
	function animeloop(){
		anime_rect2.animate(3000).radius(50).after(function(){
			this.animate(3000).radius(10).after(function(){
				setTimeout(function() {
					animeloop()
				},2000);
			})
		})
	}

	var txt=draw.text('2 角丸アニメーション').font({leading:0.8})

	//-------------

	//複合アニメーション
	//対象エレメントID
	var draw=SVG('graphics-8c').size(160,160)

	//グループ
	var demo_group2=draw.group().x(0).y(0)
	//image 100x100
	var image=demo_group2.image('/main/images/testImage108.jpg').size(160,160).center(40,80).scale(40/160)
	//rect
	var demo_rect2=demo_group2.rect(40,40).attr({'fill':image,'stroke':'#FFF','stroke-width':2}).center(40,80)
	.attr({'filter':'url(#dropShadow2)'})//陰影

	//ボタン
	var anime_btn2=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(140,140)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	anime_btn2.click(function(){
		demo_group2.animate(1000).x(80)
		demo_rect2.animate(1000).rotate(360).after(function(){
			demo_group2.animate(1000).x(0)
			this.animate(1000).rotate(0).after(function(){
				//
			})
		})
	})

	var txt=draw.text('3 複合アニメーション移動').font({leading:0.8})


2番 角丸アニメーション、下記でもOKです。

サンプルJS


	//エレメントID
	var draw=SVG('graphics-8b').size(160,160)

	//image 100x100
	var image=draw.image('/main/images/testImage108.jpg').size(160,160).center(80,80).scale(100/160)
	//rect
	var anime_rect2=draw.rect(100,100).attr({'fill':image}).radius(10).center(80,80).rotate(30)
	//オリジナルdropShadow
	anime_rect2.attr({'filter':'url(#dropShadow2)'})
	//アニメ実行繰り返し
	anime_rect2.animate(3000).radius(50).loop(0,true)

	var txt=draw.text('2 角丸アニメーション').font({leading:0.8})

2 during()アニメーション

duringアニメーション縦横の大きさ変更は面倒だ、他に良い方法があると思うが、これからの課題である。

4番、通常の拡大はstroke線幅が太くなる。(vector-effectを設定すれば変わらない)
5番、画像塗り出来ない / 6番は異常です。(3番の様にグループ化すると簡単)


通常の拡大はstroke線幅が太くなるが、「SVG2」規格の vector-effect を設定すれば線幅は変わらない。但し陰影は別ですから拡大されています。「IE11」は対応していません。


rect.attr({'vector-effect':'non-scaling-stroke'})
解除
rect.attr({'vector-effect':'none'})

サンプルJS


	//エレメントID
	var draw=SVG('graphics-8d').size(160,160)

	//image 100x100
	var image=draw.image('/main/images/testImage108.jpg').size(160,160).center(80,80).scale(40/160)
	//rect
	var anime_rect3=draw.rect(40,40).attr({'fill':image,'stroke':'#FFF','stroke-width':2}).center(80,80)
	.attr({'filter':'url(#dropShadow2)'})//陰影

	//ボタン
	var anime_btn3=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(140,140)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	anime_btn3.click(function(){

		anime_rect3.animate(1000,SVG.easing.bounce).scale(2.5).after(function(){
			anime_rect3.animate(1000,SVG.easing.bounce).scale(1)
		})

		//transformの場合
		//anime_rect3.animate(1000,SVG.easing.bounce).transform({scale:2}).after(function(){
			//anime_rect3.animate(1000,SVG.easing.bounce).transform({scale:1})
		//})

	})

	var txt=draw.text('4 アニメーション拡大縮小').font({size:10,leading:0.8})

	//ボタン
	var parts_btn=draw.circle(10).attr({'fill':'#0000FF','stroke':'#FFF','stroke-width':2}).center(140,15)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	parts_btn.click(function(){
		anime_rect3.attr({'vector-effect':'non-scaling-stroke'})
	})

	var txt=draw.text('vector-effectを設定').font({size:10,leading:0.8}).move(40,10)

	//-------------

	//エレメントID
	var draw=SVG('graphics-8e').size(160,160)

	//rect
	var anime_rect4=draw.rect(40,40).attr({'fill':'#40E0D0','stroke':'#FFF','stroke-width':2}).move(60,60)
	.attr({'filter':'url(#dropShadow2)'})//陰影

	//ボタン
	var anime_btn4=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(140,140)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	anime_btn4.click(function(){

		anime_rect4.animate(1000).move(40,40).during(function(pos,morph){
			anime_rect4.size(morph(40,80),morph(40,80))
		})
		.after(function(){
			anime_rect4.animate(1000).move(60,60).during(function(pos,morph){
				anime_rect4.size(morph(80,40),morph(80,40))
			})
		})
	})

	var txt=draw.text('5 duringアニメーション縦横').font({leading:0.8})

	//-------------

	//エレメントID
	var draw=SVG('graphics-8f').size(160,160)

	//image 100x100
	var image=draw.image('/main/images/testImage108.jpg').size(160,160).center(40,80).scale(40/160)
	//rect
	var anime_rect5=draw.rect(40,40).attr({'fill':image,'stroke':'#FFF','stroke-width':2}).move(20,60)
	.attr({'filter':'url(#dropShadow2)'})//陰影

	var rotation
	,from=0
	,to=360

	//ボタン
	var anime_btn5=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(140,140)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	anime_btn5.click(function(){

		anime_rect5.animate(1000).transform({x:80}).during(function(pos){
			rotation=from+(to-from)*pos
			this.transform({rotation:rotation})
		})
		.after(function(){
			this.animate(1000).transform({x:0}).during(function(pos){
				rotation=to+(from-to)*pos
				this.transform({rotation:rotation})
			})
		})

	})

	var txt=draw.text('6 複合duringアニメーション').font({leading:0.8})


「5 duringアニメーション縦横」ストローク幅が変わらない利点はあるが、原点を移動させなければならないので大変、これはCSS3の問題点で有る。画像を入れればまた複雑だ。(作りたくないのが本音)

3 during()アニメーション
7番グループ陰影が綺麗だが、IE11でNGのため、中の要素に処理している。
下記7番は、上のデモ5番をグループ化して下層に画像表示 / 8番、posを0-1-0と変化させている。


「アニメーションヨコヨコ」にも出来ます。「アンメルツヨコヨコ」の兄弟になります。

サンプルJS


	//エレメントID
	var draw=SVG('graphics-8g').size(160,160)

	//グループ
	var group=draw.group()
	//下画像image 100x100
	var image_panel=group.image('/main/images/testImage108.jpg').size(40,40).move(60,60)
	//rect
	var anime_rect6=group.rect(40,40).attr({'fill':'none','stroke':'#FFF','stroke-width':2}).move(60,60)
	.attr({'filter':'url(#dropShadow2)'})
	//グループ陰影IE11 NG
	//group.attr({'filter':'url(#dropShadow2)'})

	//ボタン
	var anime_btn6=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(140,140)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	anime_btn6.click(function(){

		image_panel.animate(1000).move(40,40)
		anime_rect6.animate(1000).move(40,40).during(function(pos,morph){
			anime_rect6.size(morph(40,80),morph(40,80))
			image_panel.size(morph(40,80),morph(40,80))
		})
		.after(function(){
			image_panel.animate(1000).move(60,60)
			anime_rect6.animate(1000).move(60,60).during(function(pos,morph){
				anime_rect6.size(morph(80,40),morph(80,40))
				image_panel.size(morph(80,40),morph(80,40))
			})
		})
	})

	var txt=draw.text('7 duringアニメーション縦横').font({leading:0.8})

	//-------------
	//エレメントID
	var draw=SVG('graphics-8h').size(160,160)

	var c_matrix2
	//image 100x100
	var image=draw.image('/main/images/testImage108.jpg').size(100,100).move(30,30)
	//colorize
	image.filter(function(add) {
		c_matrix2=add.colorMatrix('matrix',[1,0,0,0,0, 0,1,0,0,0, 0,0,1,0,0, 0,0,0,1,0])
	})

	var colorize=1

	//ボタン
	var test_btn10=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(145,145)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	test_btn10.click(animate_colorMatrix2)

	function animate_colorMatrix2(){

		c_matrix2.animate(3000).during(function(pos){
			colorize=1-pos//1から0
			c_matrix2.attr('values',[colorize,0,0,0,0, 0,1,0,0,0, 0,0,1,0,0, 0,0,0,1,0])
		})
		.after(function(){
			c_matrix2.animate(2000).during(function(pos){
				colorize=pos//0から1
				c_matrix2.attr('values',[colorize,0,0,0,0, 0,1,0,0,0, 0,0,1,0,0, 0,0,0,1,0])
			})
		})

	}

	var txt=draw.text('8 during() colorize アニメ').font({leading:0.8})

	//-------------

	//エレメントID
	var draw=SVG('graphics-8i').size(160,160)

	//画像image 100x100
	var image=draw.image('/main/images/testImage108.jpg').size(160,160).center(80,80).scale(100/160)
	//rect
	var anime_rect8=draw.rect(100,100).attr({'fill':image,'stroke':'#FFF','stroke-width':2}).center(80,80)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	anime_rect8.transform({'scale':0.2})
	anime_rect8.rotate(45)
	anime_rect8.attr({'opacity':0})
	var alpha,angle

	//ボタン
	var anime_btn8=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(140,140)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	anime_btn8.click(function(){

		anime_rect8.animate(1000).transform({'scale':1}).during(function(pos){
			alpha=pos
			angle=(1-pos)*45
			anime_rect8.attr({'opacity':alpha}).rotate(angle)
		})
		.after(function(){
			anime_rect8.animate(1000).transform({'scale':0.2}).during(function(pos){
				alpha=1-pos
				angle=pos*45
				anime_rect8.attr({'opacity':alpha}).rotate(angle)
			})
		})
	})
	var txt=draw.text('9 during() FadeIn 回転').font({leading:0.8})


 

その他のアニメーション

マスクアニメーション、グラデアニメーション、filterアニメーションの例、ほとんどの設定が変更可能ですからアイデア次第です。
4番は画像を動かしています / 5,6番はduring()を利用しています


サンプルJS


	//対象エレメントID
	var draw=SVG('graphics-8j').size(160,160)

	var group=draw.group()
	group.rect()
	//画像に文字でマスク
	var mask_image=group.image('/main/images/grad_200.jpg').size(200,200)
	var mask_text=group.text('POPS').attr({'fill':'#FFFFFF'}).move(80,60)
	.font({
		family:'Arial'
		,size:50
		,'font-weight':'bold'
		,anchor:'middle'
		,leading:1
	})

	//MASK
	mask_image.clipWith(mask_text).y(50)
	//全体に陰影
	group.attr({'filter':'url(#dropShadow2)'})

	//ボタン
	var anime_btn13=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(140,140)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	anime_btn13.click(function() {
		//マスクの画像を移動する
		mask_image.animate(1000).y(-50).after(function(){
			this.animate(1000).y(50).after(function(){
				//
			})
		})
	})

	var txt=draw.text('4 マスク背景アニメーション').font({leading:0.8})

	//-------------

	//対象エレメントID
	var draw=SVG('graphics-8k').size(160,160)

	var grad_text=draw.text('POPS').attr({'fill':'#FFFFFF'}).move(80,60)
	.font({
		family:'Arial'
		,size:50
		,'font-weight':'bold'
		,anchor:'left'
		,leading:1
	})

	var grad_stop1,grad_stop2,grad_stop3,gradpoint
	//gradientの塗り
	var gradient_mv=draw.gradient('linear', function(stop) {
  		grad_stop1=stop.at(0.1,'#FFFFFF')
		grad_stop2=stop.at(0.4,'#FF0000')
  		grad_stop3=stop.at(0.9,'#000000')
	})
	//gradientの方向
	gradient_mv.from(0,0).to(0,1)

	//gradient塗りと位置移動陰影
	grad_text.attr({fill:gradient_mv}).center(80,80)
	.attr({'filter':'url(#dropShadow2)'})

	//ボタン
	var anime_btn14=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(140,140)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	anime_btn14.click(function() {

		grad_text.animate(2000).during(function(pos){
			gradpoint=pos
			chg_grad(gradpoint)
		})
	})

	function chg_grad(g_point){
		gradient_mv.update(function(stop) {
  			grad_stop1=stop.at(.1,'#FFD700')
			grad_stop2=stop.at(g_point,'#FF0000')
  			grad_stop1=stop.at(.9,'#000000')
		})
	}

	var txt=draw.text('5 グラデアニメーション').font({leading:0.8})

	//-------------

	//対象エレメントID
	var draw=SVG('graphics-8l').size(160,160)

	//グループ化
	var group=draw.group()
	//BACK陰影
	var back_text=group.text('POPS')
	.font({
		family:'Arial'
		,size:50
		,'font-weight':'bold'
		,anchor:'left'
		,leading:1
	})
	back_text.attr({'fill':'#000'}).center(80,80)
	.attr({'filter':'url(#dropShadow2)'})//陰影

	//画像塗り/250x250
	var image=group.image('/main/images/patn-img03.png').size(125,125)
	var filter_text=group.text('POPS')
	.font({
		family:'Arial'
		,size:50
		,'font-weight':'bold'
		,anchor:'left'
		,leading:1
	})
	filter_text.attr({'fill':image}).center(80,80)

	//filterはテキストに
	var hueRotate
	filter_text.filter(function(add){
		hueRotate=add.colorMatrix('hueRotate',0)
	})

	//ボタン
	var anime_btn15=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(140,140)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	anime_btn15.click(function() {
		hueRotate.animate(4000).attr('values',360).after(function(){
			this.attr('values',0)
		})
	})

	var txt=draw.text('6 filterアニメーション').font({leading:0.8})


PATHアニメーション、SMIL形式のアニメーション、パスに沿ってアニメーション、画像のFadeとCrossFade はページ容量の都合で次のページに掲載します。


 

サンプルJSの全表示

Chromeは文字化けしますのでエンコード(UTF-8)してご覧ください。

● サンプルJSの全表示1(解説ページ用) svg-sample9.js

使用画像

画像は原則使用者が用意ください。デモなどで使用した画像は下記に有ります。

使用画像サンプル

 


 

dropshadowは当方自作の dropshadow-custom.js を使用します。
なおこのページはjQuery1.6.4のため dropshadow-custom-ie.js に成ります。

DropShadowと基本的なことは下記記事を参照ください。

【参照】当方の記事: SVG.js filterとDropShadow

【参照】当方の記事: SVG.js Use,Symbol,Setとその他のメソッド

【参照】当方の記事: SVG.js グラデーションとパターン

【参照】当方の記事: SVG.js TEXT表示とTEXTマスク

【参照】当方の記事: SVG.js 図形とパスの描画

【参照】当方の記事: SVG.js を使用してsvgコンテンツを作り表示します

【参照】当方の記事: SVG.js DropShadowの自作とBlur


非常に「苦悶式」です。以上。

 


[ この記事のURL ]


タグ:javascript , SVG

 

ブログ記事一覧

年別アーカイブ一覧



[1]