kute.js :イントロ

●jQueryアニメの代わりに

モダンブラウザはjavaScriptやcssの差異が少なく、jQueryなどに頼らなくてもすむようになってきました。しかしアニメ処理、特にシーケンシャルなアニメを実現しようとすると記述量が多くなり面倒です。
 
ということでjQueryに代わってシーケンシャルなアニメを簡単に作成できるようなライブラリを探したところkute.jsが良さそうなので学ぶことにしました。
 
サイトが素敵なのもkuteを選択した大きな理由です。

kute.js :公式サイト
http://thednp.github.io/kute.js/

  
基本的にレガシーブラウザには対応しない。Modernizrも使用しないでとあります(以下ページの最下段)。※IEはver10以前がサポートを打ち切りレガシーとなっている。
→参考:公式サイトget start
→参考:各Windows OSでのInternet Explorerのサポート終了時期
 
サポートしているプロパティは以下。レガシーブラウザに対応しないと言いつつも結構IE9に対応している(3D系はIE10以降)。
→参考:公式サイトSupported Properties

日本語で説明しているサイトは少ないのですが、以下のサイトが詳しいです。
→参考:DOMアニメーションの決定版「KUTE.js」が登場
 
前回まで学んでいたsvgにも対応しています。ただsvgはシンプルな用途に留めた方が良さそうと思っているので積極的な使用はしない。ただvivusよりも複雑なストロークアニメが実現できるので、そのことだけ留意しておこうと思う。
→参考:公式サイト svg plug-in
 

●導入の注意

kute.jsのダウンロードボタンはトップページのイントロアニメが終わった後に表示されます。ダウンロードされるデータはjsファイルの他にサンプルファイルもあるので自習用にダウンロードしておきました。
1031
 
公式サイトのget startedで「kute.jsの読込はbodyタグの最後で読み込むのがベスト」と書いてあったのですが、なんとなくheadタグ内に設定したらエラーになりました。やはりbodyタグの最後に記述のが良さそうです。
→参考:Uncaught TypeError: Cannot read property ‘style’ of null

<script src="../js/kute.min.js"></script>
</body>

 

●スクロール

私の中でスクロールアニメは別カテゴリなので、先にまとめておきます。スムーススクロールの機能で、examplesのVertical Scrollingに説明があります。おまけ的な扱いなのか横スクロール(scrollLeft)には対応していません…。すこしショック。

kute : スムーススクロール
http://jquerystudy.info/kute/0_core/1_scroll.html

 
ソースは以下。jQueryを使わないと記述量が多くなりますね、safariはwindowでなくbody使わないと機能しないし…。あと、なんで横スクロールに対応しないのだろう。
→参考:Scroll Example for KUTE.js

function scrollTo(_id){
	var navHeight = 70;
	var elmRect = document.getElementById(_id).getBoundingClientRect();
	var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
	var pos = elmRect.top + scrollTop - navHeight;
	KUTE.to(scrollElm,{scroll:pos},{easing:'easingCubicOut',duration:1500}).start();
}

 

補足:他のアニメライブラリも試すよ

kute.js以外にもアニメ系のライブラリはたくさんある。kuteの基礎的な学習が済んだら以下のライブラリも試す予定。
 
anime.js
軽量でシンプルなライブラリ。パスに沿ったアニメができる。あと、以下サイトのエフェクトが素敵
→参考:Letter Effects with anime.js
※対応はIE10以降でIE9には対応していない。
 
velocity.js
興味深いのはスプリング系の処理があること。公式サイトのtopで「spring physics」と検索すると説明している部分が見つかります。
jQueryと利用するときはIE8にも対応するが、単体で利用する場合はIE8は対象から外れる。その場合は読込順に注意が必要っぽい。
→参考:Velocity.js not working in IE8

 
おしまい
 
 
 

svgアニメ:ループ

前回の記事で最後と言いつつ、ループ処理について学び残していた…。
 

●アニメは再生後に最初に戻る

ループではないのですが、少し躓いたのでメモ。cssのanimate設定はfill属性をforwardに設定しないと再生終了後に最初のフレームに戻ってしまいます。

CSS animation : デフォルトの設定だと最初に戻る
http://jquerystudy.info/svg/06_loop/fill00.svg

 
そしてfill属性をforwardに設定すると以下のサンプルのように最後のフレームで停止する。

CSS animation : fill属性をforwardに
http://jquerystudy.info/svg/06_loop/fill01.svg

 
svgファイル内に記述したcssは以下のような感じ

#light{
	stroke-width:0; 
	stroke-dasharray: 15 30;
	stroke-dashoffset:20;
	stroke: #000000;
	animation: light_anime 500ms ease-in-out forwards; 
}

forward以外に設定できる値は以下の通り
→参考:MDN animation-fill-mode
 

●ループの設定

ループの設定で覚えるのは2種類。まずはデフォルのとの設定で、最後のフレームになったら最初のフレームに戻るループです。

CSS animation : デフォルトのループ
http://jquerystudy.info/svg/06_loop/loop00.svg

 
svg内のcssは以下の通り。繰り返し回数にinfiniteを設定するととで永遠にループ再生されます。再生回数を設定したい場合はinfiniteの代わりに数値を設定します。

#light{
	stroke-width:0; 
	stroke-dasharray: 15 30;
	stroke-dashoffset:20;
	stroke: #000000;
	animation: light_anime 500ms ease-in-out 0s infinite; 
}

もう1つのループ設定は、最後のフレームに来たら逆再生で最初のフレームに戻るループです。アニメの種類に応じて前述の設定と使い分けましょう。

CSS animation : alternateなループ
http://jquerystudy.info/svg/06_loop/loop01.svg

 
svg内のcssは以下の通り。alternateの設定を追加するだけです。
→参考:MDN animation-direction

#light{
	stroke-width:0; 
	stroke-dasharray: 15 30;
	stroke-dashoffset:20;
	stroke: #000000;
	animation: light_anime 500ms ease-in-out 0s infinite alternate; 
}

 

●一時停止

一時停止もcssで設定できます。以下のサンプルではボタンをクリックするたびに再生/停止が切り替わります。

 
このサンプルはjavaScriptも利用しているのですが、まずはsvg内に設定したcssを確認。以下のように一時停止させたい要素にstopクラスが追加されたらanimation-play-stateをpausedに設定するようにしています。

#light.stop{
	animation-play-state: paused;
}
#bulb.stop{
	animation-play-state: paused;
}

そしてhtml側に記述したjavaScriptでは以下のようにstopクラスを付けたり外したりしているだけです。

function animeToggle(){
	var svg = document.getElementById('sw').contentDocument;
	svg.getElementById('light').classList.toggle("stop");
	svg.getElementById('bulb').classList.toggle("stop");
}

 

●キリの良いところで停止したい

前項のサンプルはボタンをクリックしたタイミングで停止しますが、そうではなくてキリの良いところで停止させたいです。しかし、これは簡単に実現できないようです(webkitは方法があるそうですが…)。
→参考:cssアニメーションの再スタート
 
しかしcssのanimationはイベントが設定できるので、それを利用して無理矢理実現してみました。アニメの長さによって数式を変更する必要があり汎用性は高くないのですが…。
→参考:MDN CSS アニメーション

CSS animation : キリの良いところで停止
http://jquerystudy.info/svg/06_loop/1_pause.html

 
以下はsvg内に記述したjavaScriptの一部です。この_flgの部分でキリの良いポイントを見分けているのですが、アニメの長さによって数式を変更しなければなりません(小数点誤差が出ても問題ない条件式にしたかったので少し回りくどい式になっています)。

var _flg = (e.elapsedTime * 2) % 2 -0.5;
if (_flg &lt; 0){
	light.classList.add("stop");
	bulb.classList.add("stop");
}

※SVGファイル内で「<」を利用するとエラーになるので特殊文字に変換しています。
 
おしまい
 
 
 

クロージャでSVGを管理してみた

今回の技術も対応していないブラウザがあるので、仕事では使えないかもしれませんが…
なんだかパズルゲームのようで楽しくなってきたのでメモ。
svgの記事は一旦、今日が最終回です。

●外部からsvgにjavascriptを設定

前回の記事でhtml側からsvg内にアクセスできることを知りました。それならsvg内にjavascriptを記述しなくても外部から付加できるだろうと思い試しました。

sample : htmlからsvgにjavascriptを付加
http://jquerystudy.info/svg/05_closure/0_func.html

 
まずsvg(switch.svg)内にはcssだけ設定し、javascriptは記述していないことを確認してください(ブラウザの「ソースを表示する」系のメニューでsvgのソースを確認できます)。
 
html側のjavascriptは前回のソースとほとんど同じです。異なるポイントとしては、前回の自分のidを取得する部分が「負荷の高い力業」だったのに対し、今回は引数で受け取り設定しているだけなので負荷が低い点です。

function switchMaster(_id){
	var target_obj = document.getElementById(_id);
	target_obj.contentDocument.id = _id;
	target_obj.contentDocument.onclick = function(){
		var _classList = this.getElementById('light').classList;
		_classList.toggle("switchon");
		var _flg = _classList.contains("switchon");
		window.parent.document.svgState(this.id, _flg);
		
		this.getElementById('bulb').classList.toggle("switchon");
	}
}

 

●setterとgetterの設定

外部から状態(ON/OFF)を設定/取得できるようにクロージャにしてsetterとgetterを付けてみた。サンプルにはsvgとは別にボタンがあり、そこからsvgの状態を取得/変更できます。

sample : svgを外部からアクセスしやすいようにした
http://jquerystudy.info/svg/05_closure/1_clo.html

 
クロージャに関しては以前勉強した(jQueryだけど)。
→参考:クロージャ(1)
 
setterやgetterについては色々悩む。
→参考:オブジェクト指向設計 getter, setterを使うなとはどういうことか
→参考:結局のところgetter/setterは要るのか?要らないのか?
 
おしまい
 
 
 

svgの中にjavascript

●今はまだ使わない方がよい?

以下サイトの最後の部分でsvgファイル内にjavaScriptを記述したサンプルがあります。この方法はfireFoxやoperaで利用できないので、smil同様に仕事では避けるべきなのでしょう。
→参考:HTML5でのSVGファイル操作のおさらい
 
しかし現在(2017.10/26)ではMacのfirefoxやoperaで機能しています。徐々に対応ブラウザも増えていくのでしょう。
 

●firefoxとsvgのクリップパス

今回のサンプルはsvg内のクリップパスを操作しているのですが、これはfirefoxが対応していないためfirefoxではスイッチのデザインが変化しません…。cssを制御する有名なGreenSockのライブラリを利用すれば、この問題も解決できるそうです。
→参考:animating svg masks clip path not working in firefox/
 

●マウスイベント

これまでsvgファイル内にcssを設定してhoverを実現しましたが、今回はjavascriptを利用してhoverを実現しようと思います。

sample : javascriptでhover
http://jquerystudy.info/svg/04_js/hover.svg

 
javaScriptを利用するとはいえデザインの変更はcssで設定します。注意点はhoverの部分で、疑似要素の:hoverではなく、class要素のhoverになっていることです。つまりhoverクラスの付け外しでデザインの変更を行えるようにしています。

<style>
#mask{
	transform:translateX(-250px);
    transition:transform 1s;
}
#mask.hover{
	transform:translateX(0px);
}
</style>

でもってjavaScriptは以下のように記述されています。onmouseover/onmouseoutイベントによってhoverクラスを付けたり外しているだけです。

<script>
var mySvg = document.getElementById('all');
mySvg.onmouseover = function(){
	document.getElementById("mask").classList.add("hover");
};
mySvg.onmouseout = function(){
	document.getElementById("mask").classList.remove("hover");
};
</script>

 

●トグルボタン

前述のサンプルを少し変更してトグルボタンを作りました。クリックするたびにON/OFFが切り替わります。このサンプルもsvg内にjavaScriptを記述しているのでsvgファイル単体で機能します。

 
javaScriptは以下のように記述しています。classListのcontains関数で要素に指定されたclassが負荷されているか確認できるので、それをフラグに表示を切り替えているだけです。

mySvg.onclick = function(){
	var status = document.getElementById("mask").classList.contains("hover");
	if (!status){
		document.getElementById("mask").classList.add("hover");
		//---ONの時に処理したい何か
	}else{
		document.getElementById("mask").classList.remove("hover");
		//---OFFの時に処理したい何か
	}
};

 

●htmlからsvgの関数を実行

ここまでのサンプルはsvg内で完結していましたが、次はhtml側に設定したfunctionを実行してみます。ここからサンプルは直リンのsvgではなくhtmlファイルになります。html側のtoggleボタンをクリックするとsvgの状態が変化します。

sample : htmlからsvgの関数を実行
http://jquerystudy.info/svg/04_js/0_html2svgl.html

 
htmlからsvg内のfunctionをコールするためには一工夫が必要で、以下のサイトが参考になりました。
→参考:Call svg javascript function inside html javascript function
 
svg側のjavascriptの以下1行がポイントです。html側からはsvgのscriptタグにはアクセスできないため、実行したい関数をdocumentに付加する必要があるのです。

document.toggleFunc = toggleFunc;

 
html側は以下のように記述しています。以前の記事に書いたとおりsvg内にアクセスするためにはcontentDocumentが必要となります。

var svg = document.getElementById('svgSwitch');
svg.contentDocument.toggleFunc();

 

●svgからhtmlの関数を実行

次は逆にsvgからhtmlのfunctionを実行してみます。以下のサンプルはsvgをクリックするたびに、その状態をhtmlに表示します。

sample :svgからhtmlの関数を実行
http://jquerystudy.info/svg/04_js/1_svg2html.html

 
まずはhtml側のscriptを確認します、前項と同じようにdocumentの設定が必要となります。svg内部からもhtmlのscriptタグにはアクセスできないためfunctionをdocumentに設定する必要があるのです。

document.svgState = svgState;
function svgState(state){
	var str = state ? "on" : "off";
	document.getElementById('debugText').innerHTML = "svg switch status is " + str + ".";
}

svg側は以下のように記述しています。svg内部からhtmlにアクセスするには以下のようにwindow.parent.documentというパスを記述します。

function toggleFunc(){
	var myClassList = document.getElementById("mask").classList;
	myClassList.toggle("hover");
	window.parent.document.svgState(myClassList.contains("hover"));
}

 

●svgから自分のidを取得

最後に複数のsvgを効率よく管理する仕組みを追加しました。以下のサンプルではsvgのスイッチを切り替えると、上部テキストに「スイッチの状態」が表示されます。

sample :自分のidを管理するsvg
http://jquerystudy.info/svg/04_js/2_id.html

 
まずはhtmlを確認します。ポイントはsvgを配置しているobjectタグのidです。このidをsvg側で取得できれば、管理しやすい構造にできるのです。

<object id="svgSwitch_1" data="toggleFunc3.svg"></object>
<object id="svgSwitch_2" data="toggleFunc3.svg"></object>
<object id="svgSwitch_3" data="toggleFunc3.svg"></object>

最初はparent.idのノリで簡単に取得できると思ったのですが、直接取得できるような仕組みはないようです。なんとかiframeの事例を見つけて、それをsvgに応用することで取得できました。
→参考:How to get parent iframe element from inner page without knowing id?
 
テクニックとしてはかなり力業でです。html内にあるobject要素の内部情報(document)を自分と比較して自分のobjectタグを探し、そのidを取得します。ファイルサイズの大きなsvgでは大きな負荷がかかりそうです…。

var myID;
var objs = window.parent.document.getElementsByTagName("object");
for(var i=0; i&lt;objs.length;i++){
	var f = objs[i];
	var fDoc = f.contentDocument || f.contentWindow.document;
	if(fDoc === document){
		myID = f.getAttribute("id");
	}
}

あとは取得したmyIDをsvgがクリックされたときにhtmlに渡すだけです。

function toggleFunc(){
	var myClassList = document.getElementById("mask").classList;
	myClassList.toggle("hover");
	window.parent.document.svgState(myID, myClassList.contains("hover"));
}

 

●object要素(svg)にcssを付けるときの注意

svg(object要素)にcssを設定するさいにhtml側に設定したら機能しなかった。しかしsvg側に記述したら機能しました。上記サンプルで利用したtoggleFunc3.svgのcssには以下のように記述したのでsvg上にマウスオーバーしたさいにカーソルが変わります。またiOSではタップ時のハイライトが表示されなくなります。

#all{
	-webkit-tap-highlight-color:rgba(0,0,0,0);
	cursor:pointer;
}

 
おしまい
 

フォームでsvgを使いたかった…

●svgを利用したフォームアイテム

これまでの学習で「cssで実現できないような演出のボタン」をsvgで作れそうなことを確認しました。それを発展させてformのトグルボタンもsvgで作成したいと思ったのです。
 
例えば以下のサイトでは素敵な演出のついた「いいねボタン」の例があるのですが、これをformのトグルボタン(ラジオボタン)に組み込めたら素敵だと思ったわけです。
→参考:今こそ導入したいSVGアニメーションの作り方まとめ(全3ページ)

inlineの記述方であればformのトグルボタンとして設定できそうな気もするのですが、その場合はhtmlの可読性が下がり色々編集しにくくなるので避けたいのです。
マイクロインタラクションはインラインsvgが基本っぽい?
→参考:SVGで始めるマイクロインタラクション入門(全2ページ)

 
さらに調査を進めたところ、adobeのブログにてsvgで演出を付けたラジオボタンやチェックボックスの記事がありました。
→参考:CSS vs SVG: Styling Checkboxes and Radio Buttons
→参考:上記のデモページ
 
このサンプルはhtmlの可読性は高いのですが、javaScriptで動的にsvgを制御(svgcheckbx.js)しており難易度は高そうです。javaScriptを利用せずにcssだけでformに組み込めたら嬉しいのですが、現状は無理っぽいです。
 
 
フォームに関しては素直にcss3アニメで対応した方が良さそうですね。
→参考:HTMLとCSSだけで簡単に作れる! トグルボタンの作り方!!
→参考:フォーム周りで覚えておくと便利なCSS Snippets
 
svgは純粋なアニメやシンプルなボタンでの利用に抑えた方が良さそうです。以下のサイトの地図の表示の仕方とか素敵です。
→参考:demo_kanorealestate.html
 
あと何となくマスクも。
→参考:SVGクリッピングマスクにチャレンジ!静止画像も動画も、SVGで切り抜こう!
 
あと再利用(defs/use)についてもメモ。
→参考:図形の定義と再利用

 

●canvasとsvgの違い

svgについて調べるとcanvasとの区別が曖昧になってくる。というわけで調べた。以下のサイトの後半に詳しい説明が載っている。ついでに直ぐしたのcss3との比較も参考になった。
→参考:svg要素の基本的な使い方まとめ

個人的には大がかりな演出はcanvas(create.jsやtree.jsを利用)を使い、ロゴアニメやマイクロインタラクションはsvgを使おう(inlineなsvgは好きになれないので避ける)と思う。
 
あとadobeのcanvasを操作するjsフレームワークとしてはcreate.jsが有名だが、実はsvg用のフレームワークも作成している。
→参考:snap.svg
 
おしまい
 
 

svgアニメ:寄り道(smil)

SVGアニメの実現にはsmilという仕組みもあるのですが…。
 

●svgアニメを設定するsmil

smilはsvgタグ内に記述できる高度なアニメーション処理です。しかしIEどころかEdgeにも対応していないため仕事での使用は避けた方が良さそうです。
→参考:can i use (smil)

利用できるアニメーションは以下のサイトが詳しいです。
→参考:svgにおけるアニメーションの実現
 
以下は往復アニメをリピートさせたサンプルです。

sample : シンプルなsmil
http://jquerystudy.info/svg/03_etc/smil.svg

 
ソースは以下のようになっており、アニメさせる要素(サンプルではrect)の子要素としてanimateタグを設定します。
サンプルでは繰り返し回数を無限(indefinite)に設定し、操作する属性(attributeName)をx、その値(values)を0,-250,0とすることで往復させています。

<rect id="mask" x="-216" y="-45" width="234" height="153">
	<animate repeatCount="indefinite" attributeName="x"
	values="0;-250;0" dur="3s" ></animate>	
</rect>	

 

●マウスイベントでアニメ

smilは簡単にマウスイベントにアニメを設定できます。begin属性で利用できるイベントは以下のサイトが詳しいです。
→参考:MDN web docs :begin

sample : smilでロールオーバーアニメ
http://jquerystudy.info/svg/03_etc/mouse.svg

 
前のサンプルと同じようにアニメさせたい要素の子要素としてanimateタグを設定します。ポイントはbegin属性の値で、ここにイベントを設定します。便利なのは、自分の要素(ここではrect)意外のidも利用できる点で、今回は一番親の要素であるallを利用しました(cssでidを指す記号の#は必要ないことに注意してください)。
 
あと注意点としてはfill属性にfreezeを設定しないとアニメ再生後に最初のフレームに戻ってしまう点です。

<rect id="mask" x="-250" y="-45" width="234" height="153">
	<animate begin="all.mouseover" attributeName="x"  to="0" dur="0.3s"
	fill="freeze"></animate>	
	<animate begin="all.mouseout" attributeName="x"  to="-250" dur="0.3s" 
	fill="freeze"></animate>	
</rect>

 

●javaScriptとの連携

smilの利用を諦めたのはjavaScriptとの連携に向かないためです。beginElementというメソッドで特定の要素に設定されたアニメを再生できるのですが複数のアニメを使い分けることができません。つまり「ボタンAをクリックしたら要素XのアニメA、ボタンBをクリックしたら要素XのアニメBを再生する」といったことができないのです。beginElementのサンプルとしては以下のサイトが詳しいです。
→参考:SVGのpathをJavaScriptでぬるぬる動かしたかった
 
beginElementの引数に何か設定できないかとW3Cのマニュアルを確認したのですが、実行するアニメを振り分けるような処理はありませんでした。
→参考:W3C(animate – dom interface)

●補足

クリップパスのモーフィングを利用したサイト。
→参考:Organic Shape Animations with SVG clipPath
 
 

●素直にCSSを使おう

追記 2017.10/26 : firefoxとクリップパスアニメ
firefoxではクリップパスをcssでアニメさせることは出来ないようです。しかしGreenSockを利用するとなんとかなるっぽいです。
https://greensock.com/forums/topic/12272-animating-svg-masks-clip-path-not-working-in-firefox/

 
 
以下のサンプルはsmilと同じ動作をしますがcssだけで実現しています。

sample : cssでロールオーバーアニメ
http://jquerystudy.info/svg/03_etc/css.svg

 
操作しているのは実際には表示されないclipPathの要素ですが、cssで操作することができます。ただし少し躓いた点があるので、サンプルで少しづつ説明していきます。まず以下のサンプルはcssを設定していないサンプルで、OFFの状態になるようにclipPathの位置を設定しています。

sample : OFFの状態を確認
http://jquerystudy.info/svg/03_etc/css_off.svg

 
ソースは以下のように記述しておりrect要素のx属性の値を-250に設定して画面外に出しています。結果として#mask_onの要素が表示されずグレー表示になります。

<clipPath id="mask_1_">
	<rect id="mask" x="-250" y="-45" width="234" height="153"/>	
</clipPath>

続いてはONの状態。

sample : ONの状態を確認
http://jquerystudy.info/svg/03_etc/css_on.svg

 
このサンプルではx属性の値が0(デフォルトの位置)に設定され、#mask_onの要素がすべて表示されます。

<clipPath id="mask_1_">
	<rect id="mask" x="0" y="-45" width="234" height="153"/>	
</clipPath>

 
でもってcssでこの2つの状態を切り替えるように設定したのが以下のサンプル。

sample : cssアニメの失敗例
http://jquerystudy.info/svg/03_etc/css_ng.svg

 
まずclipPathの位置は以下のように最初はOFFの状態になるようにしました。

<clipPath id="mask_1_">
	<rect id="mask" x="-250" y="-45" width="234" height="153"/>	
</clipPath>

そしてcssの表記は以下のようにしています。translateで勘違いしやすいのは引数は座標を指すのではなく移動量を指す点です。つまり以下のcssだと、最初の段階で、X軸方向にさらに-250してしまうのです。
→参考:CSS3リファレンス-transform:translate

#mask{
	transform:translateX(-250px);
	transition:transform 1s;
}
#all:hover #mask{
	transform:translateX(0px);
}

 
機能するサンプルでは、cssはそのままでclipPathの設定を最初ブルーの状態(つまりx=0)に設定しています。そしてcssのtranslateXによって-250の移動がなされグレーの状態になります。しかし仕様としてイマイチ納得できないのはマウスオーバーでのtranslateXの設定。ここで0を設定することでcssの初期値の位置に戻すのですが、少し分かりにくい気がします(0でなく250と設定しがち…)。

sample : cssでロールオーバーアニメ
http://jquerystudy.info/svg/03_etc/css.svg

 

<clipPath id="mask_1_">
	<rect id="mask" x="0" y="-45" width="234" height="153"/>	
</clipPath>

 
次回はこのサンプルを発展させてform要素のtoggleボタンをsvgで作成したいのですが…。
少し調べたところ無理そう…。
 
 
 

Posted in html5 & css3, study | Tagged , | svgアニメ:寄り道(smil) はコメントを受け付けていません。

svgの中にcss(2)

前回の続きです。

●大きさを変更するときの注意

cssで最初に表示するサイズを少し縮小したところ、位置がずれて配置される現象が発生しました。一度でもマウスオーバーすると正常になるのですが…

sample : 縮小表示したら位置がずれた
http://jquerystudy.info/svg/02_css/hover03.svg

 
1021 
ソースは以下のように記述し、transform-originを利用して基準点を中央にしています(デフォルトで中央だけど念のため)。

#bulb{
	transform-origin: 50% 50%;
	transform:scale(0.5,0.5);
	stroke: #000000;
	transition:stroke 1s, transform 1s;
}

 
対処方法が思いつかなかったので、初期状態は拡大縮小しないように元のsvgを作成するように心がけることにしました。

sample : 最初にscaleを設定するのはやめる
http://jquerystudy.info/svg/02_css/hover03b.svg

 

●ストロークアニメ

ストロークアニメの際に破線の設定(stroke-dasharrayなど)をすることが不思議だったので調べてみました。以下のサイトが図解で説明していて分かりやすいです。
→参考:SVGのアニメーションで線を引く方法まとめ(IEへの対応も)

今回はストロークアニメを利用して光の表現を実装してみました。

sample : ストロークアニメで光を
http://jquerystudy.info/svg/02_css/hover04.svg

 
まずは初期状態のcssを説明します。dasharrayで線の長さを15、空白の長さを30にしています(値を変えながら試行錯誤が必要でした)。そしてstroke-dashoffsetの値を調節して、最初は線が表示されないようにします。

#light{
	stroke-dasharray: 15 30;
	stroke-dashoffset:20;
	stroke: #000000;
	transition:stroke 1s, stroke-dashoffset 1s;
}

マウスオーバーしたときの処理は以下。stroke-dashoffsetを0に戻して線が表示される状態にします。こうすることで最初の線がない状態から、マウスオーバーで線が描画されるアニメが完成します。

#all:hover > #light{
	stroke: #cccc33;
	stroke-dashoffset:0;
}

 

●ストロークアニメの調整

前項のサンプルは「光のストローク幅が大きい」ため表示されるときに唐突な感じがします。しかしアニメの速度を上げれば違和感は感じないと思います。

sample : 光のアニメを速度UP
http://jquerystudy.info/svg/02_css/hover04b.svg

 
とはいえ今回は練習なので、速度が遅くても違和感のない演出を考えました。ストローク幅が大きいから違和感が出るのですから最初はストローク幅を小さくして、アニメでストローク幅を大きくすればよいのです。

sample : ストローク幅もアニメ
http://jquerystudy.info/svg/02_css/hover04c.svg

 
ストローク幅をアニメさせるので、まずタグの方からストローク幅の設定を削除します。

<path class="path_hand" fill="none" stroke="#000000" stroke-width="10" …(省略)
↓
<path class="path_hand" fill="none" stroke="#000000" …(省略)

そして、cssは以下のように記述しています。stroke-widthの設定を追加しただけです。

#light{
	stroke-width:0; 
	stroke-dasharray: 15 30;
	stroke-dashoffset:20;
	stroke: #000000;
	transition:stroke 1s, stroke-width 1s, stroke-dashoffset 1s;
}
#all:hover > #light{
	stroke-width:10; 
	stroke-dashoffset:0;
	stroke: #cccc33;
}

●移動

最後に移動に関して学びました。cssで移動というとtopやleft、marginを利用したものを思い浮かべますが、svgの場合はtransformを利用するようです。cssのtransformに関しては以下のサイトが詳しいです。
→参考:【CSS3】Transform(変形)関連のまとめ

今回はマウスオーバーで手を下に移動してみました。

 
cssは以下のように記述しました。

#hand{
	transform:translateY(0px);
	transition:transform 1s;
}
#all:hover > #hand{
	transform:translateY(10px);
}

 

●補足

svgの機能について詳しくまとめられたページを見つけたのでメモ。javaScriptとの連携についても説明されています。
→参考:svg要素の基本的な使い方まとめ
 
 
 
 

svgの中にcss(1)

これまで学習でsvg内にcssを設定できることが分かりました(レガシーなブラウザでは未対応だと思いますが)。なので今回はjavaScriptからは離れて、svg内に記述したcssだけでロールオーバーの演出を実現に挑戦したいと思います。
 

 
※サンプルで開くsvgファイルはブラウザの「ソースを表示」系のメニューでソースが確認できます
  

●classを利用

svgファイルは内部のタグごとにidやclassを設定できるため、パス毎に個別の設定ができます。下のサンプルは手のストロークにマウスオーバーすると赤くなります。

sample : 手のストロークを個別にアニメ
http://jquerystudy.info/svg/02_css/hover00.svg

 
タグには以下のように手のパスに「path_hand」クラスを設定しています。

<g id="hand">
	<path class="path_hand" d="M16.(省略)
	<path class="path_hand" d="M16.(省略)

そしてスタイルシートは以下のように記述しています(htmlと同じルールです)。

.path_hand{
    fill: #000;
    transition:fill 1s;
}
.path_hand:hover {
    fill: #f00;
}

 

●まとめて操作

今回のsvgファイルには手の部分をまとめたgタグを用意し、id属性にhandと設定しました。これを利用してgタグが内包したパスをまとめて操作します。

sample : 複数のストロークをまとめてアニメ
http://jquerystudy.info/svg/02_css/hover00b.svg

 
以下のように手のパスの親階層のidにhandが設定されています。

<g id="hand">
	<path class="path_hand" d="M16.(省略)
	<path class="path_hand" d="M16.(省略)
	(省略)
</g>

そしてスタイルシートは以下の通り(htmlと同じルールです)。

#hand{
    fill: #000;
    transition:fill 1s;
}
#hand:hover {
    fill: #f00;
}

 

●まとめて操作する場合の注意

ここまでのsvgは素材集のデータを利用していたのですが、自作のデータを利用したらcssが機能しないケースを発見したのでメモ。
 
まずclassを利用した場合は問題なく機能しました。以下のサンプルで手のストロークにマウスオーバーすると赤くアニメします。

sample : 手のストロークを個別にアニメ(class)
http://jquerystudy.info/svg/02_css/hover01.svg

 
問題はidを利用したサンプルです。以下のサンプルでは手のストロークにマウスオーバーしても機能しません。

sample : idを利用したアニメ(失敗例)
http://jquerystudy.info/svg/02_css/hover01b.svg

 
素材集のsvgとタグを比較したところ、素材集のsvgにはパス情報だけでfillやstrokeの情報がありませんでした。なので上記のsvgファイルからfillやstrokeの記述を削除したところ、マウスオーバーに反応するようになりました。

sample : idを利用したアニメ(調査用)
http://jquerystudy.info/svg/02_css/hover01c.svg

 
失敗例のタグは以下のようにpathやstrokeの設定がしてあります。

<path class="path_hand" fill="none" stroke="#000000" stroke-width="10" 
stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" 
d="M35.833,240c0,0-1-19.499-12-36.166s-14-25.671-14-47.169s0-27.831,0-46.498s31-(省略)

成功例のタグは以下のようにpathやstrokeの設定を削除しました。

<path class="path_hand" d="M35.833,240c0,0-1-19.499-12-36.166s-14-25.671-14-47.169s0-27.831,0-46.498s31-

 

●変更する要素はcssで指定しタグからは削除

hover01c.svgは機能しましたが、設定を削除しすぎたためデザインが変わってしまいました。これでは使えないので「何を削除すればよいか?」を調査しまし、結論としてアニメさせる要素はタグから削除してcssに設定すると機能することが分かりました。

sample : idを利用したアニメ(成功例)
http://jquerystudy.info/svg/02_css/hover01d.svg

 
今回はストロークの色を変更しているので、その部分だけを削除しました。

<path class="path_hand" fill="none" stroke-width="10"
 stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"
 d="M35.833,240c0,0-1-(省略)

 

●領域に入ったらアニメ

ここまでのサンプルはパスにマウスオーバーするとアニメしていました。しかし、これでは不便です。画像と同じようにsvgの領域に入ったらアニメするようにしました。

sample : 領域に入ったらアニメ
http://jquerystudy.info/svg/02_css/hover02.svg

 
まず以下のように領域を設定するrectを追加しました。今回はテスト用にopacityを0.1にして表示していますが、最終的には0にして表示しないようにします。またid属性としてareaと名付けました。

<rect id="area" opacity="0.1" fill="#FF0000" width="240" height="240"/>

そしてcssは以下のように記述しています。hoverの部分の「>」については以下のサイトが詳しいです。
→参考:【CSS】:hover疑似クラスで指定要素とは別の要素にスタイルを適用する


#hand{
    stroke: #000;
    transition:stroke 1s;
}
#all:hover > #hand{
    stroke: #f00;
}

今回はここまで。
 
 
 
 

SVGアニメ(2)

前回のサンプルはsvgをタグとしてhtml内に直接記述しました。svgを操作宇する場合、この記述方法が一番簡単なのですがhtmlの可読性が著しく下がってしまいます。なので今回は外部のsvgファイルをobjectタグで読込、そのsvgを操作することに挑戦したいと思います。

●CSSが適用されない

objectタグで配置したsvgにはhtml側に記述したcssは適用されません。以下のサンプルではhtml側のcssでpathの色を変更しているのですが、適用されず黒色で描画されてしまいます。
 

sample : html側のCSSは適用されない
http://jquerystudy.info/svg/01_object/0_test.html

 
以下のようにpathに対して線を水色に指定しています。

<style>
path{
	stroke:#0099cc;
}
</style>

 

●svg内にCSSを設定する

前回紹介したwebサイトでsvg内にjavaScriptを記述できると知ったので、cssも記述できるだろうと試したところ出来ました。線は水色で描画されます。

 
html側のcssは削除し代わりにsvgファイル(logo_css.svg:テキストエディタで開いてください)側に以下のように記述しました。
 
1017_01
 

●svg内の要素をjavaScriptで操作する

では前回と同じようにvivusの描画が完了したらガイドラインを削除して文字を塗りつぶします。javaScriptを利用してもhtml側のcssをsvg内の要素に設定することはできないようです。とはいえsvg内でしか利用しないcssであればhtml側よりsvg側に記述したほうが管理しやすいでしょう。

sample : 描画後にCSSアニメを実行
http://jquerystudy.info/svg/01_object/2_js.html

 
アニメは前回同様cssで行うので、svgファイル内に前回利用したアニメ用のcssを記述しておきます。今回利用するsvgファイルはlogo_anime.svg(テキストエディタで開いてください)。
 
1017_02
 
以下はvivus描画語に実行するcompFuncの一部です。ポイントはcontentDocumentです。このプロパティを利用することでsvg内のタグにアクセスできます。それcss用のアニメを設定する部分は前回のサンプルと同じです。

function compFunc(){
	var svg = document.getElementById('logoSVG').contentDocument;
	//---fontline fill
	var fontline = svg.getElementsByClassName("fontline");
	for (var i=0; i<fontline.length; i++){
		fontline[i].classList.add("fillAnime");
	}

 

●jQueryを使ってみた

複数の要素にまとめてcssを設定する場合はjQueryを利用した方が便利なのでサンプルを作成してみました。

sample : jQueryでシンプルに記述
http://jquerystudy.info/svg/01_object/3_jquery.html

 
contentDocumentの部分はjQueryのcontents()で置きかえられると思ったのですがダメでした。以下のサイトではcontents()もaddClass()も利用できないとあるのですが、現最新版のver3.2.1ではaddClass()を利用することができました。しかしcontents()はやはり利用できませんでした。
→参考:SVGをjQueryで操作する際にハマったので、書き留めておく

function compFunc(){
	var svg = document.getElementById('logoSVG').contentDocument;
	$(svg).find(".fontline").addClass("fillAnime");	
	$(svg).find(".guideline").addClass("fadeOutAnime");	
}

 
ついでに別のサンプルを作成した。

 
このサンプルではsvg内のcssにtransitionでアニメの設定をしています(logo_anime2.svg:テキストエディタで開いてください)。このように記述しておけば、外部からfillを操作した際にすべてアニメで演出されます。

<style>
	.fontline{
		stroke:#0099cc;
		fill:transparent;
		transition: fill 1s linear;
	}
	.guideline{
		stroke:#ff6633;
	}
</style>

そしてjQueryで以下のようにcssを設定してるので、交互に別の色が設定されます。transitionの設定をsvg内でしておけば、javaScript側で値を変えるだけでアニメになるのは便利だと思うのです。

$(svg).find(".fontline").each(function(index, elem){
	if (index%2==0){
		$(elem).css("fill","#0099cc");
	}else{
		$(elem).css("fill","#ff6633");
	}			
});	

おしまい。 

SVGアニメ(1)

webサイトでsvgを利用したコンテンツをよく見かけるようになったので調査することにしました。svgを表示するだけなら利用したことはあるのですが、最近のコンテンツではsvgをcssやjavaScriptで制御しているので、その辺りに興味があるのです。

●組み込み方

svgはイメージタグだけでなくobjectタグやsvgタグなどで組み込めます。ただしjavaScriptで操作する場合はブラウザによって対応していない形式があるので注意。以下のサイトが詳しいです。
→参考:HTML5でのSVGファイル操作のおさらい
 

●cssのみでアニメ

まずはcssのみでアニメをさせてみました。扱いやすいようにsvgはインライン(svgタグ)で組み込んできます。

sample : CSSのみでアニメ
http://jquerystudy.info/svg/00_inline/0_css.html

 
最初はすべてのpathのstrokeやfillをnoneに設定し、あとからcssでアニメを設定しています。今回はキーフレームで段階的に演出してみたのですが、思うようにアニメを作成できず複雑な演出には向いていない印象を持ちました。

.guideline {
    stroke-dasharray: 2000;
    stroke-dashoffset: 0;
    stroke-width: .25;
    stroke:#0099CC;
   animation:  guide_anime 4s linear forwards; 
}
@keyframes  guide_anime {
    0%  {stroke-dashoffset: 2000;fill:transparent}
    25% {}
    50% {}
    75% {stroke-dashoffset: 0;}
    100%{stroke:transparent;}
}

参考にしたのは以下のサイト。
→参考:CSSだけでSVGをアニメーションさせる

●vivus.js

vivus.jsを利用するとsvgを利用したストロークアニメが簡単に作成できます。以下のサンプルのようなpathを順に描画するアニメも簡単にできます。
→参考:公式サイト

 
スクリプトの部分はたったこれだけ。これでidがlogoSVGで設定されたsvgファイルを順々に描画(type:oneByOne)することができます。

<script>
    new Vivus('logoSVG', {type:'oneByOne', duration:300});
</script>

コールバックが取れるので描画を完了したらcssアニメを実行するようにもできます。

sample : vivus.js + CSSアニメ
http://jquerystudy.info/svg/00_inline/2_vivus.html

 
下図のcompFuncがコールバックの指定。cssアニメはcssアニメを設定したクラス(fillAnimeとfadeOutAnime)を付加することで実現しています。

new Vivus('logoSVG', {
	type:'oneByOne',
        duration: 300,
	animTimingFunction:Vivus.Linear
}, compFunc);
	
function compFunc(){
	var elm = document.getElementsByClassName("fontline");
	for (var i=0; i<elm.length; i++){
		elm[i].classList.add("fillAnime");
	}
	var elm = document.getElementsByClassName("guideline");
	for (var i=0; i<elm.length; i++){
		elm[i].classList.add("fadeOutAnime");
	}
}

 

●transitionで躓いた(修正:10/21)

複数の属性にtransitionを利用するときの構文を間違えてしまったのでメモ。まずは間違ったサンプル。vivusの処理が終わった後にフォントのstrokeとfillをアニメさせようとしているのですが、strokeのアニメが無視され機能していません(線がすぐに消えてしまう)。

sample : transition(間違った構文)
http://jquerystudy.info/svg/00_inline/3_vivus.html

 
cssは以下のように記述され、transitionの処理を2つに分けているのがポイントです。

.fontline{
	stroke:#0099cc;
	fill:transparent;
	transition: stroke 5s linear;
	transition: fill 5s linear;
}
.fillAnime{
	stroke:transparent;
	fill:#0099CC;
}

1つの要素にtransitionは1つしか設定できないため、上記の処理では最初に設定したstrokeのアニメがfillのアニメに上書きされ処理されません。
 
transitionで複数の属性をアニメさせる場合は複数の属性ごとに,(カンマ)で区切って設定します。以下のサンプルは正しい構文で記述しているので、vivusの処理が終わった後にstrokeがフェードアウトし、fillがフェードインします。

sample : transition(正しい構文)
http://jquerystudy.info/svg/00_inline/3b_vivus.html

 
cssは以下のように記述されています。

.fontline{
	stroke:#0099cc;
	fill:transparent;
	transition: stroke 5s linear ,fill 5s linear;
}
.fillAnime{
	stroke:transparent;
	fill:#0099CC;
}

  

●次回は

今回のサンプルはsvgタグを利用してhtml内に直接svgデータを書きました。シンプルなhtmlページであれば問題ないのですが、複雑なhtmlページでは可読性を下げてしまいます。ナノで次回はsvgデータを外部に配置する方法に挑戦したいと思います。