- トップ
- iOS9
- Lithium Ion のテーマを作る
- テーマの基本 その12(図形切り抜き編)
テーマの基本 その12
(図形切り抜き編)
		四角に始まった図形描画ですが、円弧や線分を描画することで、パスを知ることになりました。
		線分描画や塗りつぶしもできるようになりましたので、どんな図形でも描画できるかと思います。
		簡単な図形を簡単な図形で切り抜くと、複雑な図形ができたりします。
		ここでは、画像を切り抜くことで、バッテリーを表現してみようと思います。
  
図形の切り抜き方を知る
		「切り抜き」というものは、身近にあります。
		いろいろな切り抜きを知るところから始めましょう。
	
身近な切り抜き
		切り抜きはいろいろありますが、このサイトをご覧になっている方にとって、一番身近な切り抜きは、iPhoneアプリのアイコンではないでしょうか。
		
		アプリ内に用意されているもともとのアイコンはこんな感じです。
		 
		 
		 
		
		iOSでは、この角張ったアイコンに対し、以下の角の丸い図形を用意しています。
		
		この角丸四角形で切り抜いたモノが、iPhoneアプリのアイコンとして表示されています。
		 
		 
		 
		
	
イメージしてみる
		iPhoneアプリのアイコンは、とても分かりやすい例です。
		もう少し、複雑な図形をイメージしてみましょう。
		以下の図形は、どんな図形をどんな図形で切り抜いたものだと思いますか?
		
		実は、切り抜く図形も、切り抜かれる図形も、全く同じ図形なのです。
		しかも、とても単純な図形です。
		
		切り抜く前の図形は、以下の通りです。
		
		全く同じ正方形なのですが、一方の正方形の角度を変えています。
		分かりやすくするために、正方形の透過率を下げています。
		
		先ほどの図形は、それぞれが重なった部分を抜き出したものであることがお分かりいただけるかと思います。
		このように、面倒くさそうに見える図形でも、単純な図形から作り出すことができます。
	
切り抜きを使ってバッテリーを考える
		切り抜きを使うと、バッテリー表示も凝ったものにできます。
		しかし、凝りすぎてもスマートではなくなるので、やはりシンプルなものをサンプルとして用意したいのですよ。はい。
		シンプルなデザインとして取り上げるには、やはりオリジナルデザインかと思います。
		オリジナルデザインを幾つか見直しましたが、ビビッと来たのが電波強度の画像です。
		
		この状態が、バッテリー残量80%と考えると、分かりやすいかと思います。
		そして、バッテリー残量70%だと、こんな感じでしょうか。
		
		これなら、円を四角で切り抜けば良いので、イメージもしやすいですね。
	
プログラミングによる切り抜き
		プログラミングで切り抜きを考えるときは、当然のように約束事があります。
		それは、「パスをパスで切り抜く」ということです。
		そのために、これまでの流れを作ってきたと言っても過言かもしれません。
		しかし、イメージはできると思います。
		
		パスでパスを切り抜くには、以下のように記述します。
		
		 パス
		 ctx.clip();
		 パス
		
		このように記述すると、パスとパスが重なった部分だけ表示されます。
	
しかし問題が・・・
		切り抜きのイメージもできて、切り抜き方もわかったので、実際に作り始めようとしたのですが、問題発生です!!
		5つの円が並んでいることはもちろん分かっていたのですが、円と円の間隔に関しては、全く考えていませんでした。
		バッテリー残量を反映させようとすると、このスキマが邪魔で仕方ありません。
		そのため、スキマを無くしたデザインでやってみたのですが・・・
		
		こんな感じで、デザイン的にはスキマが無いとダメなのです・・・
		
		ここで、逆に考えてみました。
		「スキマが邪魔なら全部つなげてしまえ!!」ということで、円による凹凸すら無くしてみました。
		
		このように、とてもシンプルになりました。
		これを作っていきましょう。
	
仕様を決める
		イメージが固まりましたので、細かい部分を決めていきましょう。
	
キャンバスの大きさ
		高さは、これまで通り、ステータスバー高さの半分で良いと思います。
		問題は幅ですね。
		幅によってデザインが大きく左右されるため、慎重に決めなければなりません。
		先ほどのイメージでは 76×16でしたので、高さの約5倍の幅を用意すればイメージ通りのデザインにできます。
		
		
			キャンバスの高さ:ステータスバー高さの半分
		
		
			キャンバスの幅 :キャンバス高さの5倍
		
	
色の割り振り
		この場合、考えるまでもありません。
		バッテリー残量にはメインカラーを割り当て、外枠にはベースカラーを割り当てます。
		
		
			メインカラー:バッテリー残量
		
		
			ベースカラー:バッテリー外枠
		
	
バッテリーの外枠を描画する
		仕様も決まりましたので、バッテリーの外枠から描画していきましょう。
	
変数を決定する
		描画だけなら何とでもなりますが、分かりやすくスマートな記述に心がけると、変数を導入すべきかと思います。
		線分を描画するにも座標が必要ですし、円弧の場合ですと、半径や角度まで必要になってきます。
		そこで、以下のように変数を決めました。
		p_Left:左円弧中心X座標用
		p_Right:右円弧中心X座標用
		p_Center:円弧中心Y座標用
		drawWidth:バッテリー外枠の幅
		drawHeight:バッテリー外枠の高さ
		r:円弧の半径
	

		座標用の変数には p を付加しました。
		drawWidthとdrawHeightは、キャンバスの大きさと同じですが、それぞれ変数を用意しました。
	
変数を定義する
		変数を決めたら、次は、その変数を定義します。
		以下のように変数を定義しました。
		
			drawWidth = canvas.width (キャンバスの幅)
			drawHeight = canvas.height (キャンバスの高さ)
			r = drawHeight / 2 (描画高さの半分)
			p_Left = r (左端から半径の分だけ右へ)
			p_Right = drawWidth - r (右端から半径の分だけ左へ)
			p_Center = drawHeight / 2 (描画高さの半分)
		
		()内に、簡単な説明を書いておきました。
		p_Center は、r でも構いません。
	
変数を活用してプログラミングする
		これだけ変数が決まったら、後のプログラミングはとても楽になります。
		変数は、自分がわかりやすい名前に変更して構いません。
		
		バッテリーの外枠を描画するプログラムは、以下の通りです。
		
			(height, percent, charge, low, lpm, m_color, b_color) {
			
			 var canvas = document.createElement("canvas");
			 canvas.height = height / 2;
			 canvas.width = canvas.height * 5;
			 var ctx  = canvas.getContext("2d");
			
			 var drawWidth = canvas.width;
			 var drawHeight = canvas.height;
			 var r = drawHeight / 2;
			 var p_Left = r;
			 var p_Right = drawWidth - r;
			 var p_Center = drawHeight / 2;
			
			 ctx.strokeStyle="rgb(" + b_color.slice(0, 3).join()+ ")";
			 ctx.moveTo( p_Left, 0 );
			 ctx.lineTo( p_Right, 0 );
			 ctx.arc( p_Right, p_Center, r, -Math.PI/2, Math.PI/2 );
			 ctx.lineTo( p_Left, drawHeight );
			 ctx.arc( p_Left, p_Center, r, Math.PI/2, Math.PI*3/2 );
			 ctx.stroke();
			
			 return canvas.toDataURL("image/png");
			}
		
		左上→右上→右下→左下→左上という流れで描画しています。
		
		
		結果は、こんな感じです。
		 
		
		おっと・・・
		思ったよりも、ずいぶん横長になってしまいました。
		指定した通りなので、指定し直した方が良さそうですね。
		この結果を見た感じでは、3倍くらいが良いような気がします。
		
		実際に、3倍にしてみました。
		 
		
		これくらいですかねぇ〜
		5倍をやめて3倍にしましょう!!
		
		
		このサンプルのダウンロード ー> basic12_1.zip
	
バッテリー残量を反映させる
		バッテリー外枠の描画ができましたので、バッテリー残量を反映させましょう。
	
変数を追加する
		バッテリー残量を反映させるために、変数を追加します。
		バッテリー外枠に対するバッテリー残量を算出するための変数なのですが、これまでと同様に rectWidth とします。
	

この rectWidth は、切り抜き用にも使います。
	
変数を定義する
		rectWidth は、以下のように定義します。
		
			rectWidth = drawWidth * percent / 100
		
		簡単ですね。
	
切り抜きを活用してプログラミングする
では、お待ちかねの切り抜きを使いましょう。
		
		バッテリーの外枠を描画するプログラムは、以下の通りです。
		
			(height, percent, charge, low, lpm, m_color, b_color) {
			
			 var canvas = document.createElement("canvas");
			 canvas.height = height / 2;
			 canvas.width = canvas.height * 3;
			 var ctx  = canvas.getContext("2d");
			
			 var drawWidth = canvas.width;
			 var drawHeight = canvas.height;
			 var r = drawHeight / 2;
			 var p_Left = r;
			 var p_Right = drawWidth - r;
			 var p_Center = drawHeight / 2;
			
			
			 var rectWidth = drawWidth * percent / 100;
			
			 ctx.moveTo( p_Left, 0 );
			 ctx.lineTo( p_Right, 0 );
			 ctx.arc( p_Right, p_Center, r, -Math.PI/2, Math.PI/2 );
			 ctx.lineTo( p_Left, drawHeight );
			 ctx.arc( p_Left, p_Center, r, Math.PI/2, Math.PI*3/2 );
			 ctx.closePath();
			
			
			 ctx.clip();
			
			 ctx.fillStyle="rgb(" + m_color.join()+ ")";
			 ctx.fillRect(0, 0, rectWidth, drawHeight);			
			
			
			 return canvas.toDataURL("image/png");
			}
		
		切り抜きに clip() を使いますが、「パス対パス」ですので、パスを閉じておくために、バッテリー外枠の stroke() を closePath() にしました。
		切り抜かれた図形は塗りつぶされていて欲しいので、切り取る四角の方を塗りつぶしました。
		
		
		結果は、こんな感じです。
		 
		
		95%くらいの方が分かりやすかったかもしれませんが、塗りつぶされたバッテリーの右側が丸くなり始めていることがお分かりいただけますでしょうか。
		
		
		このサンプルのダウンロード ー> basic12_2.zip
	
バッテリー残量に外枠を上書きする
		切り抜きによるバッテリー残量描画はできましたが、しばらく使っていると、バッテリーの全容が分からないため、バッテリー残量自体もはっきりしなくなります。
		
		残量数値表示がなければ、よく分かりませんね。
		
		そこで、バッテリーの外枠とバッテリー残量の両方を描画することで、バッテリーとして仕上げましょう。
		塗りつぶしのバッテリー残量を描画してから、バッテリーの外枠を描画すれば良さそうですね。
		どちらもすでにやっているので、そのまま並べてみます。
		
		バッテリーの外枠と残量を描画するプログラムは、以下の通りです。
		
			(height, percent, charge, low, lpm, m_color, b_color) {
			
			 var canvas = document.createElement("canvas");
			 canvas.height = height / 2;
			 canvas.width = canvas.height * 3;
			 var ctx  = canvas.getContext("2d");
			
			 var drawWidth = canvas.width;
			 var drawHeight = canvas.height;
			 var r = drawHeight / 2;
			 var p_Left = r;
			 var p_Right = drawWidth - r;
			 var p_Center = drawHeight / 2;
			 var rectWidth = drawWidth * percent / 100;
			
			 ctx.fillStyle="rgb(" + m_color.join()+ ")";
			
			 ctx.beginPath();
			
			 ctx.moveTo( p_Left, 0 );
			 ctx.lineTo( p_Right, 0 );
			 ctx.arc( p_Right, p_Center, r, -Math.PI/2, Math.PI/2 );
			 ctx.lineTo( p_Left, drawHeight );
			 ctx.arc( p_Left, p_Center, r, Math.PI/2, Math.PI/2 * 3 );
			
			 ctx.closePath();
			
			 ctx.clip();
			 ctx.fillRect(0, 0, rectWidth, drawHeight);
			
			 ctx.strokeStyle="rgb(" + b_color.slice(0, 3).join()+ ")";
			
			 ctx.beginPath();
			
			 ctx.moveTo( p_Left, 0 );
			 ctx.lineTo( p_Right, 0 );
			 ctx.arc( p_Right, p_Center, r, -Math.PI/2, Math.PI/2 );
			 ctx.lineTo( p_Left, drawHeight );
			 ctx.arc( p_Left, p_Center, r, Math.PI/2, Math.PI/2 * 3 );
			
			 ctx.closePath();
			
			 ctx.stroke();
			
			 return canvas.toDataURL("image/png");
			}
		パスを作り始めることと、そのパスが閉じるべきパスかどうかを明示的にするため、BeginPath と closePath を追加してしておきました。
		
		長くなりましたが、バッテリー残量を反映させた塗りつぶしのあとに、バッテリーの外枠を描画しているだけです。
		
		
		結果は、こんな感じです。
		 
		
		バッテリーが減っても、外枠があるので、どれくらい減っているかが分かります。
		何とか、形になりましたね。
		
		
		このサンプルのダウンロード ー> basic12_3.zip
	
仕上げる
		では、仕上げていきましょう。
		
		しばらく使っていて思うことは、バッテリーの外枠が細いということです。
		単純に太くすれば良さそうなのですが、キャンバスからはみ出してしまった部分が表示されないので、太くするなら半径も小さくする必要があります。
		欲を言うと、外枠と残量の間にスキマがあると良い感じに見えそうなので、仕上げるならスキマも採用したいところです。
		あとは、プログラム自体もスッキリさせたいですね。
		デバイスの違いにも、対応させなければなりませんが、一度に全部はややこしいので、1つ1つ潰していきましょう。
	
変数を追加する
		最初に、外枠の線を太くしましょう。
		最終的には、デバイスの違いに対応させますので、線の太さを変数にしておきます。
		線の太さの変数は、line_Width とします。
		
		さらに、線の幅が太くなると、キャンバスからはみ出してしまい、はみ出した部分は表示されません。
		太くなった分だけ移動させれば良いのですが、その移動量は線幅とは違いますので、移動量も変数にしておきましょう。
		移動量の変数は、オフセットという意味を込めて、offset(まんまやんけ)とします。
	
変数を使ってプログラミングする
では、線幅を考慮してプログラミングします。
			
			キャンバスの大きさは決めてあるので、外枠の線が太くなればなるほど、線を内側に移動させなければなりません。
			そこで、線分に関しては、Y座標だけを内側に移動すれば良いと思います。
			円弧は半径を小さくすれば良いだけので、中心を移動させる必要はありません。
		
		線幅を考慮したプログラムは、以下の通りです。
		
			(height, percent, charge, low, lpm, m_color, b_color) {
			
			 var canvas = document.createElement("canvas");
			 canvas.height = height / 2;
			 canvas.width = canvas.height * 3;
			 var ctx  = canvas.getContext("2d");
			
			 var drawWidth = canvas.width;
			 var drawHeight = canvas.height;
			
			 var line_Width = 3;
			 var offset = line_Width / 2;
			
			 var r = drawHeight / 2;
			 var p_Left = r;
			 var p_Right = drawWidth - r;
			 var p_Center = drawHeight / 2;
			 var rectWidth = drawWidth * percent / 100;
			
			 ctx.fillStyle="rgb(" + m_color.join()+ ")";
			 ctx.beginPath();
			 ctx.moveTo( p_Left, 0 );
			 ctx.lineTo( p_Right, 0 );
			 ctx.arc( p_Right, p_Center, r, -Math.PI/2, Math.PI/2 );
			 ctx.lineTo( p_Left, drawHeight );
			 ctx.arc( p_Left, p_Center, r, Math.PI/2, Math.PI/2 * 3 );
			 ctx.closePath();
			 ctx.clip();
			 ctx.fillRect(0, 0, rectWidth, drawHeight);
			
			 ctx.strokeStyle="rgb(" + b_color.slice(0, 3).join()+ ")";
			
			 ctx.lineWidth = line_Width;
			
			 ctx.beginPath();
			 ctx.moveTo( p_Left, offset );
			 ctx.lineTo( p_Right, offset );
			 ctx.arc( p_Right, p_Center, r - offset, -Math.PI/2, Math.PI/2 );
			 ctx.lineTo( p_Left, drawHeight - offset );
			 ctx.arc( p_Left, p_Center, r - offset, Math.PI/2, Math.PI/2 * 3 );
			 ctx.closePath();
			 ctx.stroke();
			
			 return canvas.toDataURL("image/png");
			}
		
		線幅は、線の中心から外側へ広がっていきますので、オフセットは線幅の半分になります。
		
		結果は、こんな感じです。
		 
		
		それっぽくなってまいりました!!
		如何でしょうか!
		
		
		このサンプルのダウンロード ー> basic12_4.zip
		
		
		しかし、問題が・・・
残量表示を見直す
		線幅を太くできて、見た目も良くなりました。
		少し太い感じもしますが、それ以上の問題があります。
		幅を太くした線を上書きしているため、97%のように多少減っていなければならない表示が、100%のように見えてしまうのです。
		 
		
		
		線幅の分だけ残量表示の幅も減るので、これを考慮して計算しなければなりません。
		この手の計算は、テーマの基本その8でやっておりますので、考慮済みのプログラムを紹介します。
		
		線幅の影響を考慮したプログラムは、以下の通りです。
		
			(height, percent, charge, low, lpm, m_color, b_color) {
			
			 var canvas = document.createElement("canvas");
			 canvas.height = height / 2;
			 canvas.width = canvas.height * 3;
			 var ctx  = canvas.getContext("2d");
			
			 var drawWidth = canvas.width;
			 var drawHeight = canvas.height;
			 var line_Width = 3;
			 var offset = line_Width / 2;
			 var r = drawHeight / 2;
			 var p_Left = r;
			 var p_Right = drawWidth - r;
			 var p_Center = drawHeight / 2;
			 var rectWidth = (drawWidth - line_Width*2) * percent / 100;
			
			 ctx.fillStyle="rgb(" + m_color.join()+ ")";
			 ctx.beginPath();
			 ctx.moveTo( p_Left, line_Width );
			 ctx.lineTo( p_Right, line_Width );
			 ctx.arc( p_Right, p_Center, r - line_Width, -Math.PI/2, Math.PI/2 );
			 ctx.lineTo( p_Left, drawHeight - line_Width );
			 ctx.arc( p_Left, p_Center, r - line_Width, Math.PI/2, Math.PI/2 * 3 );1
			 ctx.closePath();
			 ctx.clip();
			 ctx.fillRect( line_Width, 0, rectWidth, drawHeight );
			
			 ctx.strokeStyle="rgb(" + b_color.slice(0, 3).join()+ ")";
			 ctx.lineWidth = line_Width;
			 ctx.beginPath();
			 ctx.moveTo( p_Left, offset );
			 ctx.lineTo( p_Right, offset );
			 ctx.arc( p_Right, p_Center, r - offset, -Math.PI/2, Math.PI/2 );
			 ctx.lineTo( p_Left, drawHeight - offset );
			 ctx.arc( p_Left, p_Center, r - offset, Math.PI/2, Math.PI/2 * 3 );
			 ctx.closePath();
			 ctx.stroke();
			
			 return canvas.toDataURL("image/png");
			}
		
		バッテリー残量の表示幅は、左右の線幅を引いて算出しています。
		切り抜くための塗りつぶし開始位置も、枠線と同様に、線幅の分だけズラしています。
		
		結果は、こんな感じです。
		 
		
		あれれ???
		切り抜き領域を変更したら枠線が無くなってしまいましたね。
		これが、clip の威力なんですね!!
	
		clip は切り抜き領域を指定しますので、clip 以降の描画はすべて clip の影響を受けます。
		つまり、切り抜き領域に指定された部分は表示されますが、切り抜き領域以外の部分は表示されないので、切り抜き領域の外に描画したバッテリーの外枠が見えないのですね。
		
		バッテリーの外枠を先に描画すれば解決しますが、この先、描画順だけで解決できない状況に遭遇してしまうとお手上げなので、ここで、きちんとした対処を覚えておきましょう。
		イメージとしては、「切り抜く時だけ切り抜き領域を有効にする」という感じです。
		切り抜いたら切り抜き領域を無効にしたいのですが、「unclip」のように領域解除のようなものはありませんので、切り抜き領域を指定する前の状態に戻すという方法で実現します。
		具体的には、切り抜き指定する前に描画状態を保存し、切り抜いたら、描画状態を元に戻すという流れです。
		描画状態を保存するには、以下のように記述します。
		
		 ctx.save();
		
		
		描画状態を復元するには、以下のように記述します。
		
		 ctx.restore();
		
		
		描画状態の保存&復元を使ったプログラムは、以下の通りです。
		
			(height, percent, charge, low, lpm, m_color, b_color) {
			
			 var canvas = document.createElement("canvas");
			 canvas.height = height / 2;
			 canvas.width = canvas.height * 3;
			 var ctx  = canvas.getContext("2d");
			
			 var drawWidth = canvas.width;
			 var drawHeight = canvas.height;
			 var line_Width = 3;
			 var offset = line_Width / 2;
			 var r = drawHeight / 2;
			 var p_Left = r;
			 var p_Right = drawWidth - r;
			 var p_Center = drawHeight / 2;
			 var rectWidth = (drawWidth - line_Width*2) * percent / 100;
			
			 ctx.fillStyle="rgb(" + m_color.join()+ ")";
			 ctx.beginPath();
			 ctx.moveTo( p_Left, line_Width );
			 ctx.lineTo( p_Right, line_Width );
			 ctx.arc( p_Right, p_Center, r - line_Width, -Math.PI/2, Math.PI/2 );
			 ctx.lineTo( p_Left, drawHeight - line_Width );
			 ctx.arc( p_Left, p_Center, r - line_Width, Math.PI/2, Math.PI/2 * 3 );
			 ctx.closePath();
			
			 ctx.save();
			
			 ctx.clip();
			 ctx.fillRect( line_Width, 0, rectWidth, drawHeight );
			
			 ctx.restore();
			
			
			 ctx.strokeStyle="rgb(" + b_color.slice(0, 3).join()+ ")";
			 ctx.lineWidth = (line_Width+s);
			 ctx.beginPath();
			 ctx.moveTo( p_Left, offset );
			 ctx.lineTo( p_Right, offset );
			 ctx.arc( p_Right, p_Center, r - offset, -Math.PI/2, Math.PI/2 );
			 ctx.lineTo( p_Left, drawHeight - offset );
			 ctx.arc( p_Left, p_Center, r - offset, Math.PI/2, Math.PI/2 * 3 );
			 ctx.closePath();
			 ctx.stroke();
			
			 return canvas.toDataURL("image/png");
			}
		
		clip() の前に保存し、目的の切り抜きが終わったら復元しています。
		
		結果は、こんな感じです。
		 
		
		思った通りの表示になりました。
		
			このサンプルのダウンロード ー> basic12_5.zip
	
スキマを入れる
		では、枠線と残量表示の間にスキマを設けましょう。
		こちらも、テーマの基本 その8と同様に、スキマ変数を s とします。
		線幅を考慮した時に、描画幅や描画位置などを変更しましたが、スキマも同様です。
		
		スキマを設けたプログラムは、以下の通りです。
		
			(height, percent, charge, low, lpm, m_color, b_color) {
			
			 var canvas = document.createElement("canvas");
			 canvas.height = height / 2;
			 canvas.width = canvas.height * 3;
			 var ctx  = canvas.getContext("2d");
			
			 var drawWidth = canvas.width;
			 var drawHeight = canvas.height;
			 var line_Width = 3;
			 var offset = line_Width / 2;
			
			 var s = 2;
			
			 var r = drawHeight / 2;
			 var p_Left = r;
			 var p_Right = drawWidth - r;
			 var p_Center = drawHeight / 2;
			 var rectWidth = (drawWidth - (line_Width+s)*2) * percent / 100;
			
			 ctx.fillStyle="rgb(" + m_color.join()+ ")";
			 ctx.beginPath();
			 ctx.moveTo( p_Left, (line_Width+s) );
			 ctx.lineTo( p_Right, (line_Width+s) );
			 ctx.arc( p_Right, p_Center, r - (line_Width+s), -Math.PI/2, Math.PI/2 );
			 ctx.lineTo( p_Left, drawHeight - (line_Width+s) );
			 ctx.arc( p_Left, p_Center, r - (line_Width+s), Math.PI/2, Math.PI/2 * 3 );
			 ctx.closePath();
			 ctx.save();
			
			 ctx.clip();
			 ctx.fillRect( (line_Width+s), 0, rectWidth, drawHeight );
			 ctx.restore();
			
			
			 ctx.strokeStyle="rgb(" + b_color.slice(0, 3).join()+ ")";
			 ctx.lineWidth = (line_Width+s);
			 ctx.beginPath();
			 ctx.moveTo( p_Left, offset );
			 ctx.lineTo( p_Right, offset );
			 ctx.arc( p_Right, p_Center, r - offset, -Math.PI/2, Math.PI/2 );
			 ctx.lineTo( p_Left, drawHeight - offset );
			 ctx.arc( p_Left, p_Center, r - offset, Math.PI/2, Math.PI/2 * 3 );
			 ctx.closePath();
			 ctx.stroke();
			
			 return canvas.toDataURL("image/png");
			}
		
		塗りつぶしの描画で線幅の分だけズラしましたが、スキマの分も加えてズラしています。
		具体的には、line_Width を (line_Width+s) にしただけです。
		
		
		結果は、こんな感じです。
		 
		 
		 
		
		スキマを0から3まで変化させてみました。
		
		
		このサンプルのダウンロード ー> basic12_6.zip
	
プログラムのスリム化
		動作としては完成なのですが、プログラミング的に、この長さはなんとかしたいところです。
		テーマの基本 その11で登場した「関数」を使って、プログラムをスリムにしましょう。
		
		共通の部分は、バッテリー残量の部分と枠線の部分で、共に beginPath から closePath までの部分です。
		ズラす量が違うだけですので、それを引数にしましょう。
		関数を使ってスリム化したプログラムは、以下の通りです。
		
			(height, percent, charge, low, lpm, m_color, b_color) {
			
			
			 function drawRect(  offset ) {
			  ctx.beginPath();
			  ctx.moveTo( p_Left, offset);
			  ctx.lineTo( p_Right, offset);
			  ctx.arc( p_Right, p_Center, r - offset, -Math.PI/2, Math.PI/2 );
			  ctx.lineTo( p_Left, drawHeight - offset);
			  ctx.arc( p_Left, p_Center, r - offset, Math.PI/2, Math.PI/2 * 3 );
			  ctx.closePath();
			 }
			
			
			 var canvas = document.createElement("canvas");
			 canvas.height = height / 2;
			 canvas.width = canvas.height * 3;
			 var ctx  = canvas.getContext("2d");
			
			 var drawWidth = canvas.width;
			 var drawHeight = canvas.height;
			 var line_Width = 3;
			 var offset = line_Width / 2;
			 var s = 2;
			 var r = drawHeight / 2;
			 var p_Left = r;
			 var p_Right = drawWidth - r;
			 var p_Center = drawHeight / 2;
			 var rectWidth = (drawWidth - (line_Width+s)*2) * percent / 100;
			
			 ctx.fillStyle="rgb(" + m_color.join()+ ")";
			
			 drawRect(  line_Width+s )
			
			 ctx.save();
			 ctx.clip();
			 ctx.fillRect(line_Width+s, 0, rectWidth, drawHeight);
			 ctx.restore();
			
			 ctx.strokeStyle="rgb(" + b_color.slice(0, 3).join()+ ")";
			 ctx.lineWidth = line_Width;
			
			 drawRect(  offset )
			
			 ctx.stroke();
			 return canvas.toDataURL("image/png");
			}
		
		
		
		結果は、こんな感じです。
		 
		 
		 
		
		当然のように同じ結果なのですが、こちらも、スキマを0から3まで変化させてみました。
		
		
		このサンプルのダウンロード ー> basic12_7.zip
	
デバイスの違いに対応する
		関数化して終わりかと思っていましたが、デバイスの違いへの対応を忘れていました。
			
		デバイスの違いで影響が出るのは、数値を指定する部分です。
		今回の内容では、線幅とスキマが該当します。
		
		デバイスの違いに対応したプログラムは、以下の通りです。
		
			(height, percent, charge, low, lpm, m_color, b_color) {
			
			 function drawRect(  offset ) {
			  ctx.beginPath();
			  ctx.moveTo( p_Left, offset);
			  ctx.lineTo( p_Right, offset);
			  ctx.arc( p_Right, p_Center, r - offset, -Math.PI/2, Math.PI/2 );
			  ctx.lineTo( p_Left, drawHeight - offset);
			  ctx.arc( p_Left, p_Center, r - offset, Math.PI/2, Math.PI/2 * 3 );
			  ctx.closePath();
			 }
			
			 var canvas = document.createElement("canvas");
			 canvas.height = height / 2;
			 canvas.width = canvas.height * 3;
			 var ctx  = canvas.getContext("2d");
			
			 var drawWidth = canvas.width;
			 var drawHeight = canvas.height;
			 var line_Width = Math.round( height / 20 );
			 var offset = line_Width / 2;
			 var s = Math.ceil( height / 30 );
			 var r = drawHeight / 2;
			 var p_Left = r;
			 var p_Right = drawWidth - r;
			 var p_Center = drawHeight / 2;
			 var rectWidth = (drawWidth - (line_Width+s)*2) * percent / 100;
			
			 ctx.fillStyle="rgb(" + m_color.join()+ ")";
			 drawRect( line_Width+s )
			 ctx.save();
			 ctx.clip();
			 ctx.fillRect(line_Width+s, 0, rectWidth, drawHeight);
			 ctx.restore();
			
			 ctx.strokeStyle="rgb(" + b_color.slice(0, 3).join()+ ")";
			 ctx.lineWidth = line_Width;
			 drawRect( offset )
			 ctx.stroke();
			 return canvas.toDataURL("image/png");
			}
		デバイスの違いを利用できる唯一の情報である「ステータスバーの高さ」から算出しています。
		線幅は四捨五入ですが、スキマは切り上げとしました。
		
		
		結果は、こんな感じです。
		 
		
		@2xでもきちんと表示されています。
		スキマは、数値指定でも良いかもしれませんね。
		
		
		このサンプルのダウンロード ー> basic12_8.zip
	
				当サイトの更新状況を、アラートで表示するかどうかの設定をします。
			
保存する
 
         
        