POPSブログ

jQuery CSS3 球状Sphereをtransit.jsで3D回転させる

370

  Category:  jquery2015/10/20 pops 

CSS3 球状sphereに配置したパネルなどを3D回転させます。Carousel回転の応用ですが使用目的により作り方の違いがあります。jquery.transit.jsのtransitionアニメーションを無理矢理応用してみました。少しクセが有ります。

 

jQuery CSS3 球状Sphereをtransit.jsで3D回転させる、テスト


ご注意、Chrome.Firefox.Opera.等、transform-style:preserve-3d対応のモダンブラウザでご覧ください(Chrome推奨)。IE系ブラウザではご覧になれません。但し、Safari、Android系の動作は不明です。


CSS3でSphereを作りtransit.jsでアニメーション

CSS3でSphere等の構造を作り、transit.jsでアニメーションする試みです。
但し、transform-style:preserve-3dを使用しますので、まだ未対応のブラウザもありますし、且つtransit.jsがZ軸に対応していませんので、完全に機能しない場合も有ります。
それでも、そこそこ動きますので多少は重宝するかも知れません。

 

1. 3Dに未対応のブラウザが多い。(Chrome推奨)
2. transit.jsがZ軸に対応していませんので設定しても機能しないものもある。
(無理やり動かしています、試してみて機能するものだけ利用します)
3. 構造とCSS3設定で大きく違いがあるので試行錯誤が必要です。
4. 現在、transit.js対応はAndroid系が含まれていませんので動作は不明です。


Sphereの構造とアニメーションとの相性

CarouselをXY円周上に割り付ければSphereはできますが、Sphereの目的のパネル(エレメント)位置を正面にもってきたいのでテストで作って見ます。

zuzu-no-zu

 

構造次第では振る舞いが違います。

手抜き目次


1. Sphereの目的の位置を正面にもって来る構造 (修正が効くので多様性がある)
2. Sphereの描画が目的の構造 (正面にもってこれない、可能ではあるが修正が効かない)
3. 他にも方法があるとは思いますが試していません。


 

 

DEMO Sphereを回転して目的パネルを正面に回転する

● デモページは [ jqury-1.9 ] で動作しています。JS、CSS、は「デモ」ページに掲載しています。


Chromeでの閲覧推奨

DEMO1 SphereをXY軸3D回転1 (改造transit.jsを使用しています、前ページに掲載)

DEMO-030


DEMO2 SphereをXY軸3D回転2 (通常のtransit.jsを使用しています)

DEMO-030b


DEMO3 別Sphereを表示する (他サイト制作のものを参考表示しています)

DEMO-030c




 

簡単な説明


jQuery CSS3 球状Sphereをtransit.jsで3D回転させる説明


構造とCSSの設定違いで色々な形にもなりますし、角度をデグリーで指定しますので振る舞いを理解しながら作ります。
球状といえど、複数のCarouselを重ねた形になります。
一旦、縮小して回転、その後所定の大きさに戻します。 transit.jsを利用しますので複数のtransition()を連続して実行出来ます。(現在、Z軸未対応3Dのため必ず思うようにはならない場合あり、改造transit.jsを利用すればほぼ解決します)


jQuery Transitプラグイン、jquery.transit.js

JSは配布元または、githubから取得できます。各ページに説明などの記載が有りますので読まれるのが良いでしょう。

● 配布元、Web Site: Transit / jquery.transit.min.jsダウンロード可

● githubでのJSのダウンロード : jQuery Transit / jquery.transit.jsダウンロード可

 

Sphereの目的の位置を正面にもって来る構造

Sphereの表面に画像などを並べて、連続したアニメーションに仕立てる場合に欠かせません。
1つのDIVの中にSphereの表面に配置する要素の数だけ、中心を同一にして配置しますが角度にデグリーを使用しますので、修正などが必要です。
簡単に言えば、1つのDIVの中に複数のCarouselを水平に重ねて作ります。

 

0番を正面中央に配置して始める

Z軸の中心になります。回転の中心であり、地球にみ立てれば、キリバス共和国(Republic of Kiribati)中央一丁目への一番地です。赤道と日付変更線の交わる所になります。
つまりは「径度線」と「緯度線」で構成すれば良い事になります。上下は極ですから密集しますのでこの辺は問題です。
地球儀と同じ構成ですから多少理解し易く作り易いと思います。


zuzu-no-zu

 

説明用に下記でJSを表示します。

DEMO1のJS

注意、改造transit.jsを使用しています。


//transition3d-sphere.js
//jquery.transit.custom.js用
//XY軸3D回転球状Carousel

//球状Carousel
(function($){

	$(function () {

		//初期設定
		//-----------------------------------------------------

		var transit_speed=1000;//3D回転速度
		var scale_speed=600;//縮小拡大速度
		var scale_v=0.65;//縮小値 0.5-0.8

		//ベースの大きさ
		var bace_W=640;
		var bace_H=300;

		//エレメントの大きさ
		var elem_W=50;
		var elem_H=50;

		//縦横分割数要素
		var h_v=7;//緯線バーチカル奇数値のこと3579
		var v_v=10;//経線ホリゾンタル5-9-13/通常奇数は交互/集中補正除く

		//半径
		var radius=200;
		//円形パネルを接する
		//radius=(elem_W/2)/Math.tan(v_v*Math.PI/180);

		//両極を小さくする係数cos補正
		var scale_hosei=1;//1-2
		//cos補正をするfalse true
		var hosei=false;//false
		//両極部分のカット奇数は交互に成りませんfalse true
		var pole_cut=false;//false
		//中央(赤道)に集中false true
		var pos_center=false;//false
		//ピッチ角度
		var angle_pich=15;//15-25
		//angle_pich=Math.round(120/h_v);//60度以内で分割
		//angle_pich=Math.round(180/h_v);//90度以内で分割

		if(pos_center){pole_cut=false;}//補正

		//角丸、陰影必要でないなら削除する
		$('#carousel-base-wrap').css({borderRadius:'10px',boxShadow:'0 0 10px #000'});

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

		var carousel_len=0;
		var moveflag=false;//アニメ中判定
		var elem=[];//panelエレメント保存用
		var round=[];//roundエレメント保存用
		var angle_X=[];
		var angle_Y=[];
		var pos_v=[];
		var angle_flag=[];

		//オブジェクト保存
		var carousel_3d_base=$('#carousel-3d-base');
		var carousel_3d=$('#carousel-3d');

		//エレメント配置角度の計算
		var eleme_angle=360/v_v;
		var eleme_angle2=360/h_v;

		//ピッチ角度指定補正
		if(pos_center){
			for (var i=0; i < h_v; i++) {
				if(i < h_v/2){pos_v[i]=angle_pich*i;}
				if(i > h_v/2){pos_v[i]=360-angle_pich*(h_v-i);}
			}
		}

		var k=0;
		for (var i=0; i < h_v; i++) {

			for (var j=0; j < v_v; j++) {

				var deg_h=j*eleme_angle;//ホリゾンタル
				var deg_v=i*eleme_angle2;//バーチカル

				//補正バーチカル
				if(pos_center){
					var deg_v=pos_v[i];
				}

				//両極部分のカット
				if(pole_cut){
					if(i == Math.round(90/eleme_angle2)){continue;}
					if(i == Math.round(270/eleme_angle2)){continue;}
				}

				var id_name="photo-elem" + k;
				var html='<div id="' + id_name + '" class="elem-3d">' + k + '</div>';
				carousel_3d.append(html);
				elem[k]=$("#photo-elem" + k);

				//角度保存
 				angle_X[k]=deg_v;
 				angle_Y[k]=deg_h;

				//反転を調べる/反転-1
				angle_flag[k]=1;//kk値
				//if(angle_X[k] > 90 && angle_X[k] < 270){angle_flag[k]=-1;}

				//CSS3設定、rotateYを先に
				elem[k].css({rotateY:deg_h,rotateX:deg_v,translateZ:radius});
				elem[k].attr('no',k);

				//両極を小さくする少し有効
				//cos補正をする
				if(hosei){
					var s_v=scale_hosei*Math.abs(Math.cos(deg2rad(deg_v)));
					elem[k].css({scale:[s_v,s_v]});
					//elem[k].css({scale:[0.5,0.5]});
				}

				//パネル角丸処理
				//elem[k].css({borderRadius:'25px'});

				k ++;

			}

		}

		//パネル個数
		carousel_len=elem.length;

		//エレメントを虹色に染める/分離
		for (var i=0; i < carousel_len; i++) {
			var angle_c=i/carousel_len;//0-1
			var rgb=hslToRgb(angle_c,1,0.5);//RGB
			var color=getHexString(rgb[0],rgb[1],rgb[2])//#FFFFFF形式
			elem[i].css({'backgroundColor':color});
		}


		var btnhtml="";
		for (var k=0; k < carousel_len; k++) {
			btnhtml=btnhtml + '<span class="my-btn">' + k + '</span>';
		}
		$('#rotateChg-box').append('<p>' + btnhtml + '</p>');
		$('#rotateChg-box').find('span').eq(0).addClass('setcolored');

		//クリックアクション/回転はマイナス設定
		$("#rotateChg-box span").each(function(i){

			$(this).click(function(e) {

				var hit_no=i;
				if(moveflag){return false;}

				$(this).addClass("setcolored");
				$(this).siblings("span").removeClass("setcolored");
				//マイナス値
				var angle_v=-1*angle_X[hit_no];
				var angle_h=-1*angle_Y[hit_no];
				rotate3d_box(angle_v,angle_h);

				return false;
			});
		});

		//移動と回転カスタム
		carousel_3d.css({translateZ:-400,rotateZ:-15});

		//alert(carousel_3d.css('transform'));

		//重要、初期のCSS設定/どんな場合も必要です/どんな場合も必要です/カスタム
		carousel_3d.css({scale:[1,1],scaleZ:1,rotateX:0,rotateY:20});//使用するもの

		//カスタム
		//3D回転/delayはdelay()でするFirefox180度対策
		function rotate3d_box(angle_v,angle_h){

			var angleX=angle_v;
			var angleY=angle_h;

			moveflag=true;//回転中判定

			//縮小
			carousel_3d.transition({scale:[scale_v,scale_v],scaleZ:scale_v},scale_speed,function(){

				//3D回転
				$(this).delay(250).transition({rotateX:angleX,rotateY:angleY},transit_speed,"linear",function(){

					//縮小を戻す
					$(this).delay(250).transition({scale:[1,1],scaleZ:1},scale_speed,function(){
						//完了
						moveflag=false;

					});

				});

			});

		}

		//------------------------------------------------
		//degをradに変換
		function deg2rad(deg){
    			var rad=deg*Math.PI/180;
    			return rad;
		}

		//------------------------------------------------
		//HSL変換
		function hslToRgb(h,s,l){

			var r,g,b;
			if(s == 0){
				r=g=b=l;//achromatic
			}else{

				function hue2rgb(p, q, t){
					if(t<0) t +=1;
					if(t>1) t -=1;
					if(t<1/6) return p+(q-p)*6*t;
					if(t<1/2) return q;
					if(t<2/3) return p+(q-p)*(2/3-t)*6;
					return p;
				}

				var q=l < 0.5 ? l *(1+s):l+s-l*s;
				var p=2*l-q;
				r=hue2rgb(p,q,h+1/3);
				g=hue2rgb(p,q,h);
				b=hue2rgb(p,q,h-1/3);
			}

			return [Math.round(r*255),Math.round(g*255),Math.round(b*255)];
		}
		//------------------------------------------------
		//RGB数値を#000000形式に変換
		function getHexString(r,g,b) {
			var color="#"+("0"+parseInt(r).toString(16)).slice(-2)+("0"+parseInt(g).toString(16)).slice(-2)+("0"+parseInt(b).toString(16)).slice(-2);
			return color;
		}
		//------------------------------------------------

	});

})(jQuery);



分割と特徴

径度線がCarouselになりますので必ず奇数で設定します中央が中心になります。
サンプルには番号と色をつけています。並び方など判る様にするためです。


zu

 

1. 緯度線(バーチカル)は奇数値です。偶数値はSphereに成りません。
2. 径度線(ホリゾンタル)がCarouselの横で一周します。原則奇数値ですが、偶数値で交互に並びます。
3. 両極部分は重なってしまいますので、不便な場合もあります。そのため両極部分を削除して構成も可能です。
また、両極に行くほど小さくも可能です。
4. 画像などの場合は、両極部分を削除して間隔を狭める方法もあります。


360度回転して位置を決める

360度回転して位置を決めていますので不都合がでます。利用する条件によっては問題ない場合もあります。
「逆さ」が気になるのは個人差があると思います。


1. 90-270度の間は逆さになります。分割ループ処理の関係で交互に逆さになります。
(「逆さ」でも正面に戻した時にはマイナス回転でアニメするので正常に成ります)
2. スケールを変えて反転、パネルを入れ子にして、中を回転させて補正するなどの方法もある。
3. 「.逆さ」に成る90-270度の間を飛ばし、0-90、270-360度の間で描画すれば「逆さ」にならない。
4. 良い方法があれば考えてください。


zuzuzu-no-zu

 

修正する

初期設定で決定します。処理内容は該当のスクリプト参照ください。


zuzu

 

● 緯度に応じて縮小
両極を小さくする修正(cos補正)ですが、係数で大きさを少し変えれます。「1」は0番の大きさ(スケール値が1)です。
「中央(赤道)に集中して描画する」と併用も可能です。



//両極を小さくする係数cos補正
var scale_hosei=1;//1-2
//cos補正をするfalse true
var hosei=false;//false

● 両極部分のカット
両極部分の重なりが大きいために、描画せずに飛ばします。パネル総数は少なくなります。



//両極部分のカット奇数は交互に成りませんfalse true
var pole_cut=false;//false

中央(赤道)に集中して描画する。
360度に展開させているために、両極部分に描画されるのは避けられません(パネルが重なる)。
高緯度部分をさけて描画すれば多少よくなる。「ピッチ角度を指定する方法」と、「最大の緯度を決めてその中を等分する方法」があります。
要するに高緯度部分に描画させない工夫です。後者がよい様です。

画像関係の処理には、おそらくこれが一番合っているようです。



//中央(赤道)に集中false true
var pos_center=false;//false
//ピッチ角度
var angle_pich=15;//15-25
------------------------------------------

最大の緯度を決めてその中を等分

//angle_pich=Math.round(120/h_v);//60度以内で分割
//angle_pich=Math.round(180/h_v);//90度以内で分割

● 反転を調べる
配置角度、90-270度の間で上下反転しますのでscaleXで修正可能です。但しアクションで正面に移動した場合に「元に戻る」のでここでまた修正が必要です(結構面倒です)。上下反転修正はできますが、番号および色の順序は同じです。
そのための識別フラグを保存します(方法などは自由)。デモでは修正等は行っていません。



//反転を調べる/反転-1
angle_flag[k]=1;//kk値
//if(angle_X[k] > 90 && angle_X[k] < 270){angle_flag[k]=-1;}

● 円形パネルを接する
パネルを隙無く並べたい場合の半径の計算式になります。通常は画面を確認しながら、パネルの大きさなどを考慮して半径を設定します。


//円形パネルを接する
//radius=(elem_W/2)/Math.tan(v_v*Math.PI/180);

● パネル表示を原寸にする
通常パネルは手前ほど拡大されて表示されます。都合により正面のパネルを原寸にする場合、スケール値の調整では旨く原寸になりません。
パネルのラップ部分、つまりCarousel本体の部分の半径分、translateZを後退させると「原寸表示」に成ります。


1. カスタムtransit.jsの場合はtranslateZを操作できます。デモでは半径200ですから...


//移動と回転カスタム
carousel_3d.css({translateZ:-200,rotateZ:-15});

2. 通常のtransit.jsの場合は transform でtranslateZを操作します。

必要なものは一括して記載します。原則、初回に1回です(2回目も可能ですが、上書きされ消えるので、順序を同じに、複数を記載)。アニメの中では全てが壊れますので使用しないでください。使用には注意が必要です。


//transform移動と回転
carousel_3d.css({transform:'translateZ(-200px) rotateZ(-15deg)'});

rotateZは通常のrotateでも代用できるが、3Dがゆがむ場合があります

--------------------------------------------------
これは、前のtranslateZがクリアされてしまう、注意

carousel_3d.css({transform:'translateZ(-200px)'});
carousel_3d.css({transform:'rotateZ(-15deg)'});

transit.jsも近い将来には「Z軸」対応になると思いますが、....


その他の注意事項

● 最も注意しなければならないのはCSSの設定順序です。
順序が違っただけでまったく違う形になります。不思議と謎と未体験が混沌とした理解不能な世界だ。
球の外周に配置するパネル(エレメント)のCSSは...


Z軸に対応する様、改造jquery.transit.jsを使用した場合。

改造に関しては前のページCarousel関連記事[ jQuery CSS3 3D回転Carouselをtransit.jsで処理する ]の中ごろに記載しています。


改造jquery.transit.jsでは「Z軸」の制御が出来ますので、下記の様になります、アニメの中でも使用可能です。

必要にせまられ、改造したものですので責任は持てません。問題があれば自己解決ください。


パネル(エレメント)のCSS

//CSS3設定、rotateYを先に
エレメントのオブジェクト.css({rotateY:角度,rotateX:角度,translateZ:半径})

● jquery.transit.jsはまだ「Z軸に対応していません」のでtransformで設定します。(一応使えます程度)

「transform」これも未対応ですがCSSとして設定できます。但し初期時に1回限りでアニメの中では使用できません。
また、JSの修正次第では、回転軸が揺らいだりする場合があります。これはZ軸に未対応ですからありえる現象です。

但し、transformのperspectiveには対応しています。



//CSS3設定、rotateYを先に
エレメントのオブジェクト.css({transform:'rotateY(' + 角度値 + 'deg) rotateX(' + 角度値 + 'deg) translateZ(' + 半径値 + 'px)'});

● 画像の挿入
画像の挿入など可能です。基本的にCarouselですから、「前ページ」を参照ください。


● 角丸、陰影処理
下記の様にtransit.jsの機能を利用するのが簡単です。外側の処理に注意、この構造ではずれるためラップを増やして処理しています。



外形の場合

//角丸、陰影必要でないなら削除する
$('#carousel-base-wrap').css({borderRadius:'10px',boxShadow:'0 0 10px #000'});

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

パネルの場合、陰影も可能です

//パネル角丸処理、この例では円形
elem[k].css({borderRadius:'25px'});

● レインボー色処理
パネルの状態を把握するために着色しているだけですから、必要のない場合は削除ください。


デモのHTML JS CSSについて

デモページに記載しています。


 

Sphereの描画が目的の構造

別の方法で作成します。上記のものとは違い、正面に指定要素を持ってくるのではなく、純正にSphereの描画が目的です。
オリジナルではCarousel部分を「li」要素でラップして、X軸方向に「li」要素を傾けて行く方法です。(デモではDIVで構成)
アクションで正面に持ってくるのは難しく、計算式が見出せず幾度かテストしましたが失敗しました。
正面に持ってくるのが目的ではなく、Sphereの描画が目的だと思います。全体を回したりする分には支障有りません。


zuzu-no-zu

 

デモ3ページ 」に掲載します。出所は下記サイトです。

【参考】paulrhayes.comの記事: Creating a sphere with 3D CSS


 

最後に

transit.jsのバージョンアップなどの事由、または、transform-style:preserve-3d 対応に変わったりした時は書き換える可能性があります。
JSの変更などは自由ですが、問題がでましたら自己解決ください。

AS3と同様に3Dは始めから作るのは大変です。将来出てくるだろう「3D専用のプラグイン」など利用して制作する事と思います。


Carouselタイプのものです。基本的なことなので参照ください。

【参考】当方の記事: jQuery CSS3 3D回転Carouselをtransit.jsで処理する


以上です。

 


[ この記事のURL ]


タグ:jquery , Transition , css3

 

ブログ記事一覧

年別アーカイブ一覧



[1]