POPSブログ

jQuery CSS3 TextCarouselを回転する

373

  Category:  jquery2015/11/19 pops 

CSS3 TextCarouselをjquery.transit.jsのtransitionアニメーションで回転させます。無理矢理応用していますが簡単に出来て便利です(本当ですか...怪しい)。表示に2つの形式がありますが、ここでは改造jquery.transit.jsを使用しています。

 

jQuery CSS3 TextCarouselを回転する、テスト


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


zu

 

手抜き目次


テキストCarouselの基本構造
1. パネルの中に文字を表示して回転表示する
2. パネル無しで文字間隔を調整し回転表示する
3. Firefoxのリロードで影響が出ないように改良したCarousel
4. Firefoxでの振る舞い


 

jQuery CSS3 TextCarouselを回転する

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


1-2分の改造でZ軸対応に改造します。

● jquery.transit.jsの改造は[ jQuery CSS3 3D回転Carouselをtransit.jsで処理する ]を参照ください。(至極簡単)

 

DEMO jQuery CSS3 TextCarouselを回転表示

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


Chromeでの閲覧を推奨します


DEMO1、パネルの中に文字を表示して回転表示するデモ1 (改造jquery.transit.jsを使用)
単なるCarouselに文字を入れたに過ぎない。

DEMO-033


DEMO2、パネル無しで文字間隔を調整し回転表示するデモ2 SPANで幅取得、(改造jquery.transit.jsを使用)
webFont表示、Firefoxの「バグ」を修正(ゴマカシ)しています。

DEMO-034




 

簡単な説明


jQuery CSS3 TextCarouselを回転するの説明


動的に作れるのがJSの良い所です。Carouselと同じ作りにして回転させます。
transit.jsを利用しますので複数のtransition()を連続して実行出来ます。ここがCSS3だけの操作と違う点だと思います。

 

デモのHTML JS CSSについて

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


HTMLの構造について

名前は変わっていますが、Carouselと同じ構造です。CSSもまったく同じです。

私の習性として「角丸陰影」はこだわりの絶対条件、陰影がずれるので1階層増やしています。


<div id="text-base-wrap">
	<div id="text-3d-base">
		<div id="text-3d"></div>
	</div>
</div>

エレメント数が多いので、JS側で生成した方が簡単です。


ボタン用、必ずとも必要では無い。(DEMO2用)


<div id="rotateChg-box" class="chg-box">
</div>

JSについて

説明用に下記で「デモ」のJSを表示します。text-carousel.jsの例


改造jquery.transit.jsについて

transform-style:preserve-3dのものを動かすにはZ軸の制御が不可欠ですが、現在jquery.transit.jsでは未対応ですので、必要に迫られ当方が勝手に改造したものです。(近い将来には正式対応すると予測していますが...)
よって、「改造JS」使用で当方が責任をもつものではありません。

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


テキストCarouselの基本構造

下図は「パネル無しで文字間隔を調整し回転表示する」文字間隔0、Fontを指定しないで作ったキャプチャーです。


kihon-zu

 

外周に配置するパネル(DIVエレメント)とそれらをラップする3D本体(ここでは、#text_3d)は同じ大きさで構成されます。
文字の大きさを取得するために、別にページ欄外に表示して取得しています。(同じCarouselで取得すると回転の中心が狂い、修正などが大変になります)
文字の位置を算出し、円周の割合に応じて角度をパネルに与え、Carouselを作ります。
文字はパネルの上で中央表示で「浮遊」している状態ですからサイズを変えることも可能です。(Fontクラスをも変えること可能)


3D本体のtranslateZ調整

3D本体つまりパネルをラップした、オブジェクトcarousel_3dのtranslateZ調整すると大きさが変わります。通常3Dである為手前が拡大されます。画像を原寸表示するには、ラップのtranslateZを半径分マイナスすると良い。
また全体の回転などをも設定可能です。画像拡大はperspective値により変化します。

rotateX、rotateYはアニメでも変化させていますので、注意ください。


注意、jquery.transit.jsの書式で記述します。



例
//半径
var radius=200;

//移動と回転
text_3d.css({translateZ:-200,rotateX:10,rotateZ:-15});

Fontについて

有る程度、Fontの指定は可能ですが、必ずブラウザが「指定Font」を表示できるとは限りません。
特に、webFontの場合に、Firefoxは正確に大きさ取得ができませんし、問題が発生します(2015/11現在)。
ブラウザ毎の確認が必要です。


 

 

1. パネルの中に文字を表示して回転表示する


図の様に文字のあるCarousel にすぎないので、作るのは簡単です。デモ1参照ください。

通常、この辺までは誰も作ります。文字は等間隔になる。


zuzu

 

1. 基本的な Carousel にすぎない。
2. 中の文字が指定の文章に変わっただけ。
3. 文字種は基本的にページ設定のfont-familyのFontです。
(Font指定は必ずしも有効とは成らない、webFontの使用可能です)
4. 中央指定の横は正確だが、高さはブラウザによって多少誤差あり。
5. 文字が重なると突き抜けて汚い。(基本的に重ならない様修正して配置する)
6. パネルが透明ならば、文字だけ表示出来ます。


説明用JS

説明用に下記で「デモ1」のJSを表示します。text-carousel.jsの例

DEMO1のJS

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


//text-carousel.js
//Y軸3D回転TextCarouselパネルつき

//Text-Carousel
(function($){

	$(function () {

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

		//TEXT
		var mainstring="ViVa POPS WEB KOUBOU ";

		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 radius=200;

		//配置する全体の角度
		var set_angle=200;

		//indentはマージンで設定/機能しない
		var indent=0;
		//エレメントの数
		var text_len=mainstring.length;

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

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

		var moveflag=false;//アニメ中判定
		var elem=[];//エレメント保存用
		var textChip=[];

		var intervalID=null;

		//オブジェクト保存
		var text_3d_base=$('#text-3d-base');
		var text_3d=$('#text-3d');


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

		//パネルを作る

		for (var i=0; i < text_len; i++) {

			var tx=mainstring.charAt(i);//1文字取り出す
			var deg_v=i*eleme_angle;
			//エレメントをつくる
			var id_name="text-elem" + i;
			var html='<div id="' + id_name + '" class="textpanel-3d">' + tx + '</div>';
			//append
			text_3d.append(html);
			//オブジェクト
			elem[i]=$("#text-elem" + i);

			//CSS3設定、rotateYを先に
			elem[i].css({rotateY:deg_v,rotateX:0,translateZ:radius});
			if(tx == " "){elem[i].css({opacity:0});}

			//エレメントを虹色に染める
			var angle_c=i/text_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});

			//角丸、陰影
			elem[i].css({borderRadius:'10px',boxShadow:'0 0 10px #000'});

		}

		//中央に配置
		text_3d.css({'left':(bace_W-radius*2)/2+radius-elem_W/2,'top':(bace_H-elem_H)/2});

		//移動と回転
		text_3d.css({translateZ:-200,rotateX:10,rotateZ:-15});

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

		//hover-action
		text_3d_base.hover(function(){

			$(this).toggleClass("active");
			//
			if ($(this).hasClass('active')) {
    				//IN
				intervalID=setInterval(spin_item,5);
			}else{
				//OUT
				clearInterval(intervalID);
			}

		});

		//回転
		function spin_item(){
			text_3d.css({rotateY:'-=0.25'});
		}

		//------------------------------------------------
		//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);



1文字ずつ取り出して挿入する。

下記の様に、1文字ずつ取り出して挿入しています。(処理書式は自由)
360度に展開する場合は、mainstring の最後に「半角スペース」を入れます。



//TEXT
var mainstring="ViVa POPS WEB KOUBOU ";

var tx=mainstring.charAt(i);//1文字取り出す

重なり調整

基本的に重なると文字が見えないので、間隔をとってならべます。
重なると突き抜けて汚いので、半径を広げるか、パネルサイズを小さくして重ならない様に調整します。
入れ子を回転して交差しないようにするのも方法の1つです。



//半径
var radius=200;

文字の配置は均等です

文字の配置は「時計の文字盤」と同じで「均等」に成ります。パネルを表示しなければ文字のみ表示できますが、それでは余り芸が有りません。
Htmlの文章の様に表示させるには、次の章で説明しているように「現在は難問」だらけになります。


パネル個別に角度を与えたりする場合

このままではCarouselが壊れますので、パネル部分を入れ子状にして構成すればパネル単独で回転できますから可能です。
以前の「画像Carousel」と同じです。


webFontを表示しても何ら問題は有りませんので、説明は省略します。



 

// これよりは、興味のある方のみお読みください。 //

 

2. パネル無しで文字間隔を調整し回転表示する


文字間隔を角度に直して配置するために、通常の文章表示と同じになります。文字の間隔は文字により違います。

Fontサイズなど変更しても、初期CSS中心が変わると困るため「エレメントの大きさ」などは変更せず、そのままにします。描画はレーヤーに対して行われますので問題は有りません。


zuzuzu

 

1. 日本語文字も表示できます。
2. デモでは専用の当方のアップロードwebFontを使用しました。
(Firefoxリロード時文字幅取得が違い全体が広がる、webFontの指定無しが問題が起きず簡単です)
3. 文字の配置を少し指定出来ます。
4. 重なる(交差する)と汚いので、場合により修正する。(入れ子を回転する)
5. 問題が起きても、どこが悪いのか判らなくなります。(そりゃ、大変だ)
6. 書き換えなどは自由です。(問題があれば自己解決ください、悩む得点付きがうれしい)


 

Firefoxのリロードで影響が出ないように改良したCarousel


FirefoxでwebFontを使用すると、どのような形でもリロードで影響が出ます。キャッシュしない様にしても結果は同じです。
FirefoxでwebFontの「大きさ取得を行わなければバグはでない」がそれでは困ります。
systemFontでは問題がないことに着目し、

Carouselエレメント以外の場所でFontの大きさ取得します。FirefoxはsystemFontの大きさ取得します。


違う文字で幅を取得していますので、少し配置が狂う場合があるが、見た目は余り違わない。いわゆるゴマカシです。
将来、FirefoxでのwebFont処理にバグが無くなれば、直接webFontで大きさ取得できるとおもいます。


説明用JS

説明用に下記で「デモ2」のJSを表示します。text-carousel5.jsの例

Firefoxに対応はしたくは無かったが、少し無理をしてみた。かなり色々な方法で書き換えテストの結果(リロードの問題があり実際2週間かかった)
最終的に、次の様になった。

DEMO2のJS

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


//text-carousel5.js
//Y軸3D回転TextCarousel文字のみ
//Firefoxリロード対策

//Text-Carousel
(function($){

	$(function () {

		//UserAgent/Firefox判定
		var ua=window.navigator.userAgent;
		var firefox=false;
		if (ua.indexOf("Firefox") > -1) {firefox=true;}

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

		//TEXT
		var mainstring="HelloWorld! ViVa POPSWEB KOUBOU ";

		//Fontクラスの使用
		var fontclass=true;
		//Fontクラス名
		var fontclass_name="GauFontMilkChoco";//webFont
		//var fontclass_name="Arial";//systemFont

		//システムFont使用は true /webFont使用は false
		var systemfont=false;

		//補正クラス名無し/ページ指定文字
		if(!fontclass){var fontclass_name="";}

		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 settype=true;
		//配置する全体の角度/settype=false
		var set_angle=180;
		//indent設定/settype=true
		var indent=0;
		if(!settype){indent=0;}//補正

		//半径
		var radius=200;

		//エレメントの数
		var text_len=mainstring.length;

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

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

		var moveflag=false;//アニメ中判定
		var elem=[];//エレメント保存用
		var textChip=[];//入れ子保存用
		var chip_W=[];
		var chip_H=[];
		var alltext_W=0;
		var chip_point=[];
		var slicetext=[];//テキスト判定用

		var intervalID=null;

		//オブジェクト保存
		var text_3d_base=$('#text-3d-base');
		var text_3d=$('#text-3d');

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

		var allhtml="";
		//文字Div
		for (var i=0; i < text_len; i++) {

			var tx=mainstring.charAt(i);//1文字取り出す
			if(tx == ' ') {tx='&nbsp;'}//Firefox

			//入れ子divエレメントをつくる
			var id_name="text-elem" + i;
			var html='<div id="' + id_name + '" class="textchip-3d"><div class="innerchip">' + tx + '</div></div>';
			allhtml=allhtml+html;

		}

		//append
		text_3d.append(allhtml);

		//文字の大きさ取得他
		for (var i=0; i < text_len; i++) {

			var tx=mainstring.charAt(i);//1文字取り出す
			slicetext[i]=tx;//1文字保存
			if(tx == ' ') {tx='&nbsp;'}//Firefox
			//オブジェクト保存
			elem[i]=$("#text-elem" + i);
			textChip[i]=elem[i].children('div');//入れ子保存

			//スパンで大きさ取得/
			var fontname="Arial";
			if(!fontclass){fontname="";}//クラス無し
			//システムFontを使用true
			if(!systemfont){
				//webfont
				if(firefox){fontname="Arial";}
				if(!firefox){fontname=fontclass_name;}
			}
			if(systemfont){
				fontname=fontclass_name;
			}

			//大きさ取得欄外処理
			chip_W[i]=getwidth(mainstring.charAt(i),fontname);

			chip_H[i]=elem[i].height();

			alltext_W=alltext_W+(chip_W[i]/2);//文字の距離
			chip_point[i]=alltext_W;//保存
			//幅半分加算/ループ最後のindent余計
			alltext_W=alltext_W+(chip_W[i]/2+indent);

		}

		//長さを正確に
		alltext_W=alltext_W-indent;

		//角度計算
		var circle_width=Math.round(radius*2*Math.PI);
		var all_angle=Math.round(360*alltext_W/circle_width);
		if(all_angle > 360){all_angle=360;}

		//再配置角度設定
		for (var i=0; i < text_len; i++) {

			if(settype){
				//配置角度計算2/indent有効
				var deg_v=360*chip_point[i]/circle_width;
				//var deg_v=all_angle*chip_point[i]/alltext_W;

			}else{
				//配置角度計算1/indent無効
				var deg_v=set_angle*chip_point[i]/alltext_W;
			}

			//Fontクラス設定
			if(fontclass){
				textChip[i].addClass(fontclass_name);
			}

			//CSS3設定、rotateYを先に/transform-style preserve-3d
			elem[i].css({rotateY:deg_v,rotateX:0,translateZ:radius});

			elem[i].children('div').css({rotateY:-5});
			//elem[i].children('div').css({rotateY:-85,rotateX:-30});

			//スペース処理
			if(slicetext[i] == " "){elem[i].css({opacity:0});}

			//文字を虹色に染める
			var angle_c=i/text_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({'color':color});

			//陰影
			//elem[i].css({boxShadow:'0 0 1px #000'});
			elem[i].css({textShadow:'0 0 3px #000'});

		}

		//中央に配置
		text_3d.css({'left':(bace_W-radius*2)/2+radius-elem_W/2,'top':(bace_H-elem_H)/2});

		//ボタンをつくる4
		var btnhtml="";
		for (var i=0; i < 4; i++) {
			btnhtml=btnhtml + '<span class="my-btn">' + i + '</span>';
		}
		$('#rotateChg-box').append('<p>' + btnhtml + '</p>');
		$('#rotateChg-box').find('span').eq(0).addClass('setcolored');

		//移動と回転
		text_3d.css({translateZ:-radius,rotateZ:-15});

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

		//3D回転/delayはdelay()でするFirefox180度対策
		function rotate3d_box(angle){

			moveflag=true;//回転中判定

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

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

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

					});

				});

			});

		}

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

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

				if(moveflag){return false;}

				$(this).addClass("setcolored");
				$(this).siblings("span").removeClass("setcolored");
				//マイナス値
				angle=90*i*-1;rotate3d_box(angle);

				return false;
			});
		});

		//hover-action
		text_3d_base.hover(function(){

			$(this).toggleClass("active");
			//
			if ($(this).hasClass('active')) {
    				//IN
				intervalID=setInterval(spin_item,5);
			}else{
				//OUT
				clearInterval(intervalID);
			}

		});

		//回転
		function spin_item(){
			text_3d.css({rotateY:'-=0.25'});
		}

		//大きさ取得
		function getwidth(tx,fontname){
			if(tx == ' ') {tx='&nbsp;'}
			var html='<span class="' + 'create-elm ' + fontname + '">' + tx + '</span>';
			$("body").append(html);
			var dummy=$(".create-elm");
			var w=dummy.width();
			dummy.remove();
			return w;
		}

		//------------------------------------------------
		//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);



エレメントの大きさとFont

下図は「パネル無しで文字間隔を調整し回転表示する」文字間隔0、アップロードしたwebFontを使用して作ったキャプチャーです。システムFont以外は少し小さく取得する傾向にあり、極太なので最初から少し重なっている。webFontによって違いがあるので「間隔の調整」で整え可能です。


エレメントの大きさは 50x50、などFontサイズに合わせ一定にしなければならない。
Flashの様に中心を決めればそこに自動的に重なる訳ではないので、重なるもの(入れ子など)は同じ大きさで作る。もし大きさが違う場合はポジションで合わせてゆくがこれは大変である。


Fontの作りが色々と有り、ブラウザ表示も異なり、旨く処理出来ないFontも有り、一層変になるようだ。


1. マシンにある、Impact Arial等は正確で、リロード時にも問題ないようです。
2. 当方の「GauFontMilkChoco」ではFirefoxでは幅取得が不正確です。リロード時に問題有り。
3. googleFontもFirefoxでは幅取得が不正確です。リロード時に問題有り。
4. 但し、Firefoxのリロード時に幅取得が大きくなる修正は可能です。
(systemFontなら問題がないので、systemFontを入れ幅取得、多少誤差はあるがなんとかいける)
5. Firefoxは当初から、webFontを表示出来ないなどの「バグ」があったのでいまだ完全ではないのでしょう。


henda

webFontの幅を取得すると、Firefoxのリロード時に幅取得が大きくなる。図の様に全体の長さが違ってきます。


文字幅の取得と配置

FirefoxでwebFontの幅を取得するとバグが発生します。

(幅取得は必要ですから、Firefoxのみ systemFont を表示して幅を取得すれば、バグが出ない)


原則、文字幅の取得はページ欄外で表示して取得します。この方が処理が簡単になります。
下記例ではspanに収容して幅取得、直ぐに削除しています。高さの取得は必ずしも必要ではありません。


下記の方式では、webFontによっては正確な幅を取得できない場合もあります。(表示してみないと判らない)
その場合は文字の間隔調整「indent」で調整します。(デモのGauFontMilkChoco)


//大きさ取得
function getwidth(tx,fontname){
	if(tx == ' ') {tx='&nbsp;'}
	var html='<span class="' + 'create-elm ' + fontname + '">' + tx + '</span>';
	$("body").append(html);
	var dummy=$(".create-elm");
	var w=dummy.width();
	dummy.remove();
	return w;
}

取得値に応じて角度に換算してエレメントを外周に配置してゆきます。
文字幅の取得はエレメントの配置計算のためで「文字表示」とは関係有りません。


zu-font

 

文字幅の取得は欄外で行い、Firefoxの場合webFontの指定はせずsystemFontで幅の取得を行います。
Carouselのエレメント内で「文字幅の取得」は行えますが、中央補正など面倒なので止めたほうが良い。


説明用に実際の幅を取得した例です。
文字を収容する div li span 要素などにより微妙に差が出る場合があります。

取得した幅

Firefox、webFontの取得例に注目ください。Fontの種類で異なるがFirefoxは少し小さい値になり易い。
Firefoxリロードで異常に大きな数値になるので、Carouselが壊れ易い。


var mainstring="HelloWorld! ViVa POPSWEB KOUBOU ";
Firefox判定
Chrome GauFontMilkChoco
38/24/14/14/26/48/26/18/14/26/16/16/38/14/38/24/16/28/38/28/28/48/32/34/16/38/38/38/34/38/38/16/

Firefox GauFontMilkChoco
32/25/11/11/25/37/25/17/11/25/11/15/32/11/32/24/15/31/35/31/30/37/28/32/15/30/35/32/32/35/32/15/
リロード
47/44/28/28/46/54/46/35/28/45/26/23/46/26/46/43/23/44/46/44/44/54/45/46/23/46/46/46/46/46/46/23/

Firefoxリロードでも同じ。Firefoxは少し小さい値になり易い。


Chrome Arial
38/28/12/12/28/48/28/18/12/28/14/14/34/12/34/28/14/34/40/34/34/48/34/34/14/34/40/38/34/40/38/14/
Firefox Arial
36/28/12/12/28/50/28/17/12/28/16/14/33/12/33/28/14/33/39/33/33/50/33/33/14/33/39/36/33/39/36/14/


無難なArialを指定して大きさを取得するが、問題があれば「Fontクラス」の指定は自由です。但し、ブラウザで「指定Font」を表示するとは限りません。


//スパンで大きさ取得/
var fontname="Arial";
if(!fontclass){fontname="";}//クラス無し
//システムFontを使用true
if(!systemfont){
	//webfont
	if(firefox){fontname="Arial";}
	if(!firefox){fontname=fontclass_name;}
}
if(systemfont){
	fontname=fontclass_name;
}

Carouselのエレメント内で「文字幅の取得」を行った場合

ブラウザにより表示が違った場合など、問題発生時「原因」が判らなくなり多くの時間を浪費します。


文字の中央表示

Carouselの外周配置エレメント(文字表示の親)を常に同じ大きさににしておけば中央に表示するのは簡単。
50pxのFontならエレメントを50x50で作る。CSSで中央に表示させる。但しブラウザにより表示高さに若干の誤差があります。

エレメントの大きさに関わらず、Fontのサイズ、Fontの種類が変更可能です。



エレメント50x50の場合

line-height:50px;
text-align:center;

半角スペースの処理

文字の間に「半角スペース」を入れられるようにしていますが、Firefoxは厳密ですから注意ください。
htmlの場合と .text() では旨く処理しないと「半角スペース」が反映されません。

spc

var allhtml="";
//文字Div
for (var i=0; i < text_len; i++) {

	var tx=mainstring.charAt(i);//1文字取り出す
	if(tx == ' ') {tx='&nbsp;'}//Firefox

	//入れ子divエレメントをつくる
	var id_name="text-elem" + i;
	var html='<div id="' + id_name + '" class="textchip-3d"><div class="innerchip">' + tx + '</div></div>';
	allhtml=allhtml+html;

}

文字の間隔

通常はHTMLに表示されるような間隔に成る様ににていますが、indentの調整で間隔を制御できます。
但し、円周に角度を指定して配置する場合は余りわからないでしょう。

webFontによっては、indent=0、でも最初から重なる場合があります。


zu-indent

 

以下の条件下で、indentの調整ができます。数値はマイナスも可能です。


//配置タイプ/そのまま配置
var settype=true;

//indent設定/settype=true
var indent=0;

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

//配置角度計算2/indent有効
var deg_v=360*chip_point[i]/circle_width;

文字の描画

CSS3ですから、文字などはレーヤーに描画されますのでCarouselのエレメントの大きさには関係有りません。
つまり、文字の大きさ、文字の種類はいつでも変更可能です。


Fontの指定

zuzuzu-font

 


CSS3より、webfontなどの読み込みが、下記の様に可能になりました。下記は当方でアップロードしたFontです。


@font-face{ 
font-family:'GauFontMilkChoco';
src:url('/main/asset/GAU_Milk_Choco.woff') format('woff');
}
.GauFontMilkChoco {
font-family:'GauFontMilkChoco';
}

通常のFont(システムFont)指定は以下の通りです。マシン環境に「指定Font」が在れば表示します。


/*Font*/
.Impact{
font-family:'Impact';
}
.Arial{
font-family:'Arial';
}
.ArialBlack{
font-family:'Arial Black';
}

googleFontのFont指定は以下の通りです。正常に読み込めば表示します。
その他、好みのものを設定可能です。googleFontの詳細はこちら、[ GoogleFont ]です。


<link href='https://fonts.googleapis.com/css?family=Open+Sans:800' rel='stylesheet' type='text/css'>

.OpenSans{
font-family:'Open Sans';
}
----------------------------------------------------------------

<link href='https://fonts.googleapis.com/css?family=Sigmar+One' rel='stylesheet' type='text/css'>

.SigmarOne{
font-family:'Sigmar One';
}

JSはwebFont使用に設定します。


//Fontクラスの使用
var fontclass=true;
//Fontクラス名
var fontclass_name="OpenSans";
または
var fontclass_name="SigmarOne";

「指定Font」が無い場合などには、ページのfont-familyが使用されます。
下記は、当方の例ですから、Arial Meiryo などが優先されて表示されることになります。


font-family:Arial, "Meiryo UI", "Meiryo", "MS Pゴシック", "ヒラギノ角ゴ Pro W3", Osaka, "MS PGothic", "Hiragino Kaku Gothic Pro", Sans-Serif;

重なった場合の修正

文字の間隔が小さい場合など「お互い角度の違いで文字が交差して」汚くなります。


同じ半径 translateZ で設定して作っていますので「重なり不具合い」は当然です。3Dのためz-indexで調整はできません。
Fontによっては意図的に重ねる場合もあるかと思いますが、重なりの修正は面倒になります。
入れ子を作り角度をかえて重なりを補正する方法を推奨します。(交差しないようにする)


● 半径(radius)を違わせて重なりを補正する (非推奨)
但し、半径が大きければ多少有効ですが、正確には「螺旋状」に成りますが判らない場合もあります。
プラスでもマイナスでも良い、重なりの形態が違ってくる。(正確には表示大きさも違ってくる)


//CSS3設定、rotateYを先に
elem[i].css({rotateY:deg_v,rotateX:0,translateZ:radius-i});

入れ子を作り角度をかえて重なりを補正する (推奨)
面倒ですが、「入れ子」を作り中のテキストの角度を変更して重ならない様にします。結構手間が掛かりますが正確です。
独立した「入れ子」部分の操作ですので、Carousel本体に影響は有りません。

大きさ取得は何らかのBOX要素などに入れて取得しますが、誤差が出る場合があります。


補正無しの処理例 1

文字が重ならないならこれでも良い。径が変わるので螺旋になる。(非推奨)


//エレメントをつくる
var id_name="text-elem" + i;
var html='<div id="' + id_name + '" class="textchip-3d">' + tx + '</div>';
//CSS3設定、rotateYを先に
elem[i].css({rotateY:deg_v,rotateX:0,translateZ:radius-i});

補正の処理例 2
必ず親要素に、transform-style:preserve-3d 設定を追加する。(設定無しでは rotateY など機能しない)
新たな角度設定で重なりは解消されます。半径は同じですから他に影響は無い。非常に面倒だ。

重なった方がデザイン的に良い場合もあるし、多くの文字を表示できる。


zuzuzu-hosei

 


//入れ子divエレメントをつくる
var id_name="text-elem" + i;
var html='<div id="' + id_name + '" class="textchip-3d"><div class="innerchip">' + tx + '</div></div>';

//CSS3設定、rotateYを先に
elem[i].css({rotateY:deg_v,rotateX:0,translateZ:radius});
elem[i].children('div').css({rotateY:-5});

#text-3d .textchip-3d{
transform-style:preserve-3d;
}

入れ子の中のエレメント角度などは自由


deg文字省略可
elem[i].children('div').css({rotateY:-5});

回転の方向を向く
elem[i].children('div').css({rotateY:-90});

回転の方向を向き、45度回転
elem[i].children('div').css({rotateY:-90,rotateZ:45});
同じ
elem[i].children('div').css({rotateY:-90,rotate:45});

文字の配置指定

文字の配置を少し指定できます。

1. 配置角度を決めて配置する。indent無効。(文字が多ければ重なりますので、角度を広げる)
2. 360度全体に配置する。indent有効。(重ねる、広げるの文字間の調整ができます)
3. 2番の場合、文字の間隔indentの設定ができます。
(どちらにしろ、重なった場合は修正が必要です)
4. 先に全体の幅を取得しなければならないので1つのループでは処理出来ない。
5.良い「アイデア」があれば、それで構いません。


1. 角度指定、重なる場合は角度を増やす。(デモでは未使用)
指定角度内で各ポイントの距離を割り振るので文字間隔はその時の条件次第です。

角度次第では、文字間の間隔がきれいでない場合も有ります。問題があってもさほどの差はないと思います。


//配置する全体の角度
var set_angle=200;

//配置角度計算1/indent無効
//var deg_v=set_angle*chip_point[i]/alltext_W;

2. デモではこちらで処理。プラスindentなら文字間は広がる。
円周の長さで各ポイントの距離を角度に換算すれば綺麗な間隔で文字が並ぶ理屈。(Firefoxは注意)

Fontによって違うようです。最終的には表示してみなければ判らないといえます。
360度以上に配置しますので、文字数、indent、radiusで調整します。システムFont用途です。


//indent設定
var indent=10;

//配置角度計算2/indent有効
var deg_v=360*chip_point[i]/(radius*2*Math.PI);

3. 実際の設定。Firefoxでの振る舞いの問題があり下記の様に初期設定で決めます。

ブラウザにより幅が違っても同じ角度範囲に収まる。


//配置タイプ/そのまま配置
var settype=false;
//配置する全体の角度/settype=false
var set_angle=180;
//indent設定/settype=true
var indent=0;

4. Firefox用に補正して実行。ページ下段の「Firefoxでの振る舞い」参照
システムFont以外のwefFont用途で、Firefoxの問題であり、Chromeは問題は無い。(その他不明)
仮に、リロードでエレメントの幅が広がっても最大限抑える修正で、360度以上にならない。

ブラウザにより幅が違っても同じ角度範囲に収まる。


var circle_width=Math.round(radius*2*Math.PI);
var all_angle=Math.round(360*alltext_W/circle_width);
if(all_angle > 360){all_angle=360;}

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

if(settype){

	//配置角度計算2/indent有効
	//360度に円周の比率で角度に換算
	//var deg_v=360*chip_point[i]/circle_width;
	//指定角度を計算で実行して補正
	var deg_v=all_angle*chip_point[i]/alltext_W;

}else{

	//配置角度計算1/indent無効
	var deg_v=set_angle*chip_point[i]/alltext_W;
}

ブラウザに関係なく文字幅を同じにする

幅を取得するのは文字収容のBOX配置のためです。文字はあくまでも中央設定です。つまり
その都度、文字幅を計算するのではなく、Chrome等で幅を取得しておきそのデータを使用すれば、ブラウザに関係なく同じになります。
但し、リアルタイムに処理はできませんが....。



事前に幅取得
Chrome GauFontMilkChoco
38/24/14/14/26/48/26/18/14/26/16/16/38/14/38/24/16/28/38/28/28/48/32/34/16/38/38/38/34/38/38/16/

同じデータを使用する
chip_W=[38,24,14,14,26,48,26,18,14,26,16,16,38,14,38,24,16,28,38,28,28,48,32,34,16,38,38,38,34,38,38,16];

文字の陰影はtextShadowです

重なりをハッキリさせるのにtextShadowは効果的ですが、Shadowは重くなるので軽く掛けます。
transit.js利用の場合は簡単です。



elem[i].css({textShadow:'0 0 3px #000'});

 

4. Firefoxでの振る舞い


思わぬ「交通事故」にあった感じである。リロードで影響の修正に手間取った。


通常のページのFont、システムFontの場合は問題は有りませんが、その他のwebFont、アップロードしたFontなどの幅取得が不正確で有り、リロードした場合にFirefoxで幅の設定が大きくなります。


henda

 

1. FirefoxでwebFontの幅を取得すると発生します。
2. systemFontでは起こりません。
3. 「リロード」時にFontの取得値が異常に大きくなりレイアウトが崩れます。
4. 「キャッシュ」とは関係がないようです。


「shiftを押しながらリロード」した場合、「強制リロード」で、再度サーバーより直接取り込み実行しますので問題は有りませんが実用的ではありません。


komaru-naa

 

解決策として


1. FirefoxでwebFontの幅を取得せず、systemFontで幅を取得する。(これが利口だ)
(FirefoxのみsystemFontで幅を取得、当然文字間のバランスは崩れる場合あり)
2. 360度の範囲内に配置できるように修正する。面倒です)
. systemFontはブラウザが違っても「ほぼ同じ」でリロードの違いが出ない。
. 文字を収容する div li span で「幅取得値」が微妙に違います。
. 文字の種類、サイズは後でも変更可能です。


上を改善して全体の角度を想定計算して割り振る(面倒)。リロードで壊れるのを最小限に抑える。
壊れたとしても、360度以内に配置できるので見苦しいことはないと思う。
webFontの種類で配置がかわるが多少の相違は仕方がない。


var all_angle=Math.round(360*alltext_W/circle_width);
if(all_angle > 360){all_angle=360;}

//var deg_v=all_angle*chip_point[i]/alltext_W;

canvas形式で大きさ取得

canvas形式で大きさを取得する事も可能ですが、systemFontはOKですが、webFontはFirefoxでリロードで壊れる。
かえって面倒なので止めとく。詳細は下記サイト記事を参照ください。

【参照】qiita.comの記事: javascriptで文字列の描画幅を取得する方法


下の例では丸めていますが、小数点以下の幅が得られます。


HTML
<canvas id="canvas" width="0" height="0" style="visibility:hidden;position:absolute;"></canvas>

-------------------------------------------------------
JS

//canvas大きさを取得する
chip_W[i]=strWidth(mainstring.charAt(i),"50px " + fontclass_name);

//canvas大きさ取得
//文字の前に空白を入れないとダメだ
function strWidth(str,fname) {
	var canvas=document.getElementById('canvas');
	if (canvas.getContext) {
		var context=canvas.getContext('2d');
		context.font=fname;
		var metrics=context.measureText(" "+str);
		return Math.round(metrics.width);
	}
	return -1;
}

 

最後に

まだ時期早尚と思いますが、ここまで面倒では利用するのは少し疑問です。
ちょっとしたCSS設定の違いで構造が出来なくなったりしますので、ご注意ください。
transit.jsのバージョンアップなどの事由、または、transform-style:preserve-3d 対応に変わったりした時は書き換える可能性があります。
JSの変更などは自由ですが、問題がでましたら自己解決ください。


Carouselタイプのものです。基本的なことなので参照ください。改造jquery.transit.jsも極簡単に作れます。

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

webFontの作り方は下記の記事を参照ください。Canvas以外でも使用できます。

【参考】当方の記事: CreateJS 複数のWebフォントをサイトにUploadしてCanvasで使用する


TEXT回すのは「アホウもしくは脳変態」です、疲れるゼ、お大事に。

 


[ この記事のURL ]


タグ:jquery , Transition , css3

 

ブログ記事一覧

年別アーカイブ一覧



[1]