- トップ
- iOS10
- Lithium Ion のテーマを作る
- テーマの基本 その15(総括編)
テーマの基本 その15
(総括編)
これまでいろいろやってきましたが、これまでやってきたことのまとめをしようと思います。
しかし、単純にまとめただけでは面白くないので、やってきたことを総動員して、何か作ってみようと思います。
いろいろ考えましたが、いろいろ考え過ぎて一周りしてしまいました。
というわけで、オリジナルバッテリーを作ってみます。
オリジナルの寸法を確認する
せっかくオリジナルバッテリーを作るのですから、完全コピーしたいです。
1つ1つ見ていきましょう。
バッテリー外枠
では、バッテリーの外枠サイズから確認しましょう。
iPhone6Plusの@3x画像で確認しています。
高さは、やはりステータスバーの半分てとこですね。
これを29のまま完全コピーするのは、とても厄介ですので、@2xデバイスでも対応できるように、3の倍数で確認しようと思います。
しかし、電極部分の2ピクセルや4ピクセルはどうしましょうね・・・
とりあえず、確認を進めます。
丸みの半径
バッテリーの外枠は角丸四角形ですので、丸みの半径が必要です。
電極部分も丸くなっているので、確認しましょう。
どちらも半径5ピクセルでした。
電極の丸みは半円ではなく、円を部分的に切り取っている形になっています。
残量表示部分
バッテリーの外枠は角丸四角形ですので、丸みの半径が必要です。
電極部分も丸くなっているので、確認しましょう。
寸法は画像の通りです。
外枠と重ねたところ、スキマが1ピクセルでしたので、寸法的にドンピシャですね。
したがって、角丸半径も3ピクセルということになります。
充電中を示すアレ
忘れちゃいけない充電中を示すアレです。
座標を拾う目的があるため、細かく確認しないといけませんね。
できるだけ3の倍数が良いのですが、思った以上に3の倍数で構成されていました。
描画するときは、幅を15にしちゃいましょう。
座標を拾う
寸法を確認しましたので、プログラミングのために座標を拾っていきましょう。
バッテリー外枠
では、バッテリー外枠の座標を拾いましょう。
0スタートが基本ですので、5ピクセルズレた座標は4となりますが、ここではまだ便宜上、5としておきます。
電極部分
電極部分は円の右側を切り抜いた形となっております。
これは、実際に切り抜いてみないと分からないですね。
残量表示部分
バッテリー外枠の座標が参考にできるので、楽ですね。
角丸半径を3とすれば、自ずと求められます。
こちらも便宜上の座標です。
充電中を示すアレ
これが一番面倒かもしれません。
3の倍数は難しいかなぁ・・・
それっぽく見えれば良いのですけど、完全コピーから遠ざかってしまいますね。
7を6にしたり、8を9にしたりすれば3の倍数になりますが、その結果どうなるかは、やってみないと分かりませんね。
パーツを描画してみる
いきなり全部はムリ?ですし、長くなるので、1つずつやっつけていきましょう。
バッテリー外枠を描画する
では、バッテリー外枠から描画していきましょう。
とりあえず、電極なしの外枠からです。
バッテリーの外枠を描画するプログラムは、以下の通りです。
(height, percent, charge, low, lpm, m_color, b_color) {
var canvas = document.createElement("canvas");
canvas.height = height/2;
canvas.width = height * 1.1;
ctx = canvas.getContext("2d");
var r = height / 12;
var line_Width = 1;
var p_Left = line_Width/2;
var p_Right = canvas.width - line_Width/2;
var p_Top = line_Width/2;
var p_Bottom = canvas.height - line_Width/2;
var pi = Math.PI;
ctx.beginPath();
ctx.strokeStyle = "rgb(" + b_color.slice(0, 3).join()+ ")";
ctx.lineWidth = line_Width;
ctx.moveTo( p_Left+r, p_Top );
ctx.lineTo( p_Right-r, p_Top );
ctx.arc( p_Right-r, p_Top+r, r, -pi/2, 0, false);
ctx.lineTo( p_Right, p_Bottom-r );
ctx.arc( p_Right-r, p_Bottom-r, r, 0, pi/2, false);
ctx.lineTo( p_Left+r, p_Bottom);
ctx.arc( p_Left+r, p_Bottom-r, r, pi/2, pi, false);
ctx.lineTo( p_Left, p_Top+r);
ctx.arc( p_Left+r, p_Top+r, r, pi, pi*3/2, false);
ctx.closePath();
ctx.stroke();
return canvas.toDataURL("image/png");
}
数値を直接指定しているのは、線幅しかありません。
線幅以外は、ステータスバー高さなど、何らかの変数から算出しています。
外枠描画のための変数(4つ)は、線幅を考慮した数値を代入しています。
実際の座標を算出するには、角丸半径の分だけ外枠の座標をズラしています。
ちなみに、今回から円周率πも変数にしています。
結果は、こんな感じです。
3の倍数にしているため、本来 67×29 のサイズが 66×30 となっております。
このサンプルのダウンロード ー> basic15_1.zip
電極を追加する
バッテリー外枠に電極を追加していきましょう。
もちろん、キャンバスも広げます。
バッテリーの外枠を描画するプログラムは、以下の通りです。
(height, percent, charge, low, lpm, m_color, b_color) {
var canvas = document.createElement("canvas");
canvas.height = height/2;
canvas.width = height * 1.2;
ctx = canvas.getContext("2d");
var r = height / 12;
var line_Width = 1;
var p_Left = line_Width/2;
var p_Right = height*1.1 - line_Width/2;
var p_Top = line_Width/2;
var p_Bottom = canvas.height - line_Width/2;
var pi = Math.PI;
ctx.beginPath();
ctx.strokeStyle = "rgb(" + b_color.slice(0, 3).join()+ ")";
ctx.lineWidth = line_Width;
ctx.moveTo( p_Left+r, p_Top );
ctx.lineTo( p_Right-r, p_Top );
ctx.arc( p_Right-r, p_Top+r, r, -pi/2, 0, false);
ctx.lineTo( p_Right, p_Bottom-r );
ctx.arc( p_Right-r, p_Bottom-r, r, 0, pi/2, false);
ctx.lineTo( p_Left+r, p_Bottom);
ctx.arc( p_Left+r, p_Bottom-r, r, pi/2, pi, false);
ctx.lineTo( p_Left, p_Top+r);
ctx.arc( p_Left+r, p_Top+r, r, pi, pi*3/2, false);
ctx.closePath();
ctx.stroke();
ctx.beginPath();
ctx.fillStyle = "rgb(" + b_color.slice(0, 3).join()+ ")";
ctx.arc( p_Right+height/30, height/4, height/12, 0, pi*2, false);
ctx.closePath();
ctx.clip();
ctx.fillRect( p_Right+height/20, 0, p_Right+height/10, p_Bottom);
return canvas.toDataURL("image/png");
}
電極の分だけキャンバスの幅が増えました。
p_Right は、キャンバスの幅から算出していましたが、そのままだと都合が悪いので、ステータスバー高さから算出し直しました。
電極の元となる円は、外枠の右側を基準としています。
p_right に対して、ステータスバー高さを基準とした数値を追加しています。
切り抜く座標も同様で、外枠の右側に対して、ステータスバー高さから算出した数値を追加しています。
オリジナルの画像を確認した図において、外枠と電極のスキマが2ですので、座標としての増分は3なので、ステータスバー高さを20で割った数値を加えている訳です。
結果は、こんな感じです。
おぉ〜
それっぽいではありませんか!?
ちょっと、オリジナルと並べてみましょう!!
右がオリジナルです。
オリジナルは残量が表示されてしまうため、直接的な比較をするのは難しいですが、それなりに出来上がっているかと思います。
ただ、見れば見るほど、3の倍数にするために増やした1ピクセルが気になりますね。
このサンプルのダウンロード ー> basic15_2.zip
充電中を示すアレまでも追加する
充電中を示すアレ(稲妻マーク)ですが、さらに追加するか、単独で描画するか、とても迷ったのですが、さらに追加して描画していこうと思います。
しかし、電極からの距離を測っていませんでした。
今更ですが、確認してみます。
10ピクセルでした。
電極から10ピクセルのスキマを開けて、稲妻マークを描画しましょう。
さらに稲妻マークまでも描画するプログラムは、以下の通りです。
(height, percent, charge, low, lpm, m_color, b_color) {
var canvas = document.createElement("canvas");
canvas.height = height/2;
canvas.width = height * 1.65;
ctx = canvas.getContext("2d");
var r = height / 12;
var line_Width = 1;
var p_Left = line_Width/2;
var p_Right = height*1.1 - line_Width/2;
var p_Top = line_Width/2;
var p_Bottom = canvas.height - line_Width/2;
var pi = Math.PI;
ctx.beginPath();
ctx.strokeStyle = "rgb(" + b_color.slice(0, 3).join()+ ")";
ctx.lineWidth = line_Width;
ctx.moveTo( p_Left+r, p_Top );
ctx.lineTo( p_Right-r, p_Top );
ctx.arc( p_Right-r, p_Top+r, r, -pi/2, 0, false);
ctx.lineTo( p_Right, p_Bottom-r );
ctx.arc( p_Right-r, p_Bottom-r, r, 0, pi/2, false);
ctx.lineTo( p_Left+r, p_Bottom);
ctx.arc( p_Left+r, p_Bottom-r, r, pi/2, pi, false);
ctx.lineTo( p_Left, p_Top+r);
ctx.arc( p_Left+r, p_Top+r, r, pi, pi*3/2, false);
ctx.closePath();
ctx.stroke();
ctx.beginPath();
ctx.fillStyle = "rgb(" + b_color.slice(0, 3).join()+ ")";
ctx.arc( p_Right+height/30, height/4, height/12, 0, pi*2, false);
ctx.closePath();
ctx.save();
ctx.clip();
ctx.fillRect( p_Right+height/20, 0, p_Right+height/10, p_Bottom);
ctx.restore();
ctx.beginPath();
ctx.fillStyle = "rgb(" + b_color.slice(0, 3).join()+ ")";
ctx.moveTo( height*1.2+height/6 + height/5, 0 );
ctx.lineTo( height*1.2+height/6 + height/20*3, height/5 );
ctx.lineTo( height*1.2+height/6 + height/20*5, height/5 );
ctx.lineTo( height*1.2+height/6 + height/20*1, height/2 );
ctx.lineTo( height*1.2+height/6 + height/20*2, height/4 );
ctx.lineTo( height*1.2+height/6 + height/20*0, height/4 );
ctx.closePath();
ctx.fill();
return canvas.toDataURL("image/png");
}
さらにキャンバスの幅が増えました。
電極までの幅(height*1.2)に、10ピクセルに相当するheight/6を加え、これを基準に座標を指定しています。
height/20が3ピクセルに相当しますので、「3の何倍か」という求め方にしました。
最後はパスを閉じて、塗るだけです。
結果は、こんな感じです。
おぉ〜
これも良い感じですね〜!?
こちらも、オリジナルと並べてみましょう!!
オリジナルの残量は気にせずいきましょう。
遜色ないように見えますが、3の倍数にしたことによるズレは隠せませんね。
このサンプルのダウンロード ー> basic15_3.zip
バッテリー残量を反映させる
いろいろ描画しましたが、最後を飾るのは残量表示です。
スキマ1ピクセルを設けて反映させましょう。
残量も描画するプログラムは、以下の通りです。
(height, percent, charge, low, lpm, m_color, b_color) {
var canvas = document.createElement("canvas");
canvas.height = height/2;
canvas.width = height * 1.65;
ctx = canvas.getContext("2d");
var r = height / 12;
var line_Width = 1;
var p_Left = line_Width/2;
var p_Right = height*1.1 - line_Width/2;
var p_Top = line_Width/2;
var p_Bottom = canvas.height - line_Width/2;
var pi = Math.PI;
var s = 1;
s += line_Width ;
ctx.beginPath();
ctx.strokeStyle = "rgb(" + b_color.slice(0, 3).join()+ ")";
ctx.lineWidth = line_Width;
ctx.moveTo( p_Left+r, p_Top );
ctx.lineTo( p_Right-r, p_Top );
ctx.arc( p_Right-r, p_Top+r, r, -pi/2, 0, false);
ctx.lineTo( p_Right, p_Bottom-r );
ctx.arc( p_Right-r, p_Bottom-r, r, 0, pi/2, false);
ctx.lineTo( p_Left+r, p_Bottom);
ctx.arc( p_Left+r, p_Bottom-r, r, pi/2, pi, false);
ctx.lineTo( p_Left, p_Top+r);
ctx.arc( p_Left+r, p_Top+r, r, pi, pi*3/2, false);
ctx.closePath();
ctx.stroke();
ctx.beginPath();
ctx.fillStyle = "rgb(" + b_color.slice(0, 3).join()+ ")";
ctx.arc( p_Right+height/30, height/4, height/12, 0, pi*2, false);
ctx.closePath();
ctx.save();
ctx.clip();
ctx.fillRect( p_Right+height/20, 0, p_Right+height/10, p_Bottom);
ctx.restore();
ctx.beginPath();
ctx.fillStyle = "rgb(" + b_color.slice(0, 3).join()+ ")";
ctx.moveTo( height*1.2+height/6 + height/5, 0 );
ctx.lineTo( height*1.2+height/6 + height/20*3, height/5 );
ctx.lineTo( height*1.2+height/6 + height/20*5, height/5 );
ctx.lineTo( height*1.2+height/6 + height/20*1, height/2 );
ctx.lineTo( height*1.2+height/6 + height/20*2, height/4 );
ctx.lineTo( height*1.2+height/6 + height/20*0, height/4 );
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "rgb(" + m_color.join()+ ")";
ctx.lineWidth = line_Width;
var rectWidth = (p_Right-p_Left-s*2) * percent / 100;
ctx.moveTo( p_Left+r+s, p_Top+s );
ctx.lineTo( p_Right-(r+s), p_Top+s );
ctx.arc( p_Right-r, p_Top+r, r-s, -pi/2, 0, false);
ctx.lineTo( p_Right-s, p_Bottom-(r+s) );
ctx.arc( p_Right-r, p_Bottom-r, r-s, 0, pi/2, false);
ctx.lineTo( p_Left+(r+s), p_Bottom-s);
ctx.arc( p_Left+r, p_Bottom-r, r-s, pi/2, pi, false);
ctx.lineTo( p_Left+s, p_Top+(r+s));
ctx.arc( p_Left+r, p_Top+r, r-s, pi, pi*3/2, false);
ctx.closePath();
ctx.clip();
ctx.fillRect( p_Left+s, 0, rectWidth, p_Bottom);
return canvas.toDataURL("image/png");
}
線分は、座標が内側へ s ズレますが、円弧は、半径が s 減ります。
結果は、こんな感じです。
バッテリー残量の反映は、何度もやりましたので、もう大丈夫でしょうか。
こちらも、オリジナルと並べてみましょう!!
あらら・・・
これだけ色が違うと、とても気になりますね。
充電中の色を変更しましょう。
設定アプリの Lithium Ion から、Color Options を選択します。
Charging Color をタップして、色を指定してください。
右上の#をタップすると、カラーコードで指定できます。
詳しくは、脱獄アプリ一覧の Lithium Ion を参考にしてください。
もう一度、オリジナルと比べてみましょう。
だいたい同じ色になりました。
これで、必要なもの全てが描画できました。
このサンプルのダウンロード ー> basic15_4.zip
仕上げる
部品が揃いましたので、仕上げていきましょう。
そもそも、充電中を示す稲妻マークは、充電中しか出現しません。
最初に、これをやっつけましょう。
あとは、関数化もしましょう。
充電中かどうかで表示を変える
充電中かどうかで表示される部品が変わりますが、表示するキャンバスの大きさが変わることが一番のポイントかと思います。
部品の描画はもう出来ていますので、充電中かどうかでキャンバスの大きさを変更し、そのあとに描画するという流れにしましょう。
充電中かどうかで処理を変更するプログラムは、以下の通りです。
(height, percent, charge, low, lpm, m_color, b_color) {
var canvas = document.createElement("canvas");
canvas.height = height/2;
canvas.width = height * (charge ? 1.65:1.2);
ctx = canvas.getContext("2d");
var r = height / 12;
var line_Width = 1;
var p_Left = line_Width/2;
var p_Right = height*1.1 - line_Width/2;
var p_Top = line_Width/2;
var p_Bottom = canvas.height - line_Width/2;
var pi = Math.PI;
var s = 1;
s += line_Width ;
ctx.beginPath();
ctx.strokeStyle = "rgb(" + b_color.slice(0, 3).join()+ ")";
ctx.lineWidth = line_Width;
ctx.moveTo( p_Left+r, p_Top );
ctx.lineTo( p_Right-r, p_Top );
ctx.arc( p_Right-r, p_Top+r, r, -pi/2, 0, false);
ctx.lineTo( p_Right, p_Bottom-r );
ctx.arc( p_Right-r, p_Bottom-r, r, 0, pi/2, false);
ctx.lineTo( p_Left+r, p_Bottom);
ctx.arc( p_Left+r, p_Bottom-r, r, pi/2, pi, false);
ctx.lineTo( p_Left, p_Top+r);
ctx.arc( p_Left+r, p_Top+r, r, pi, pi*3/2, false);
ctx.closePath();
ctx.stroke();
ctx.beginPath();
ctx.fillStyle = "rgb(" + b_color.slice(0, 3).join()+ ")";
ctx.arc( p_Right+height/30, height/4, height/12, 0, pi*2, false);
ctx.closePath();
ctx.save();
ctx.clip();
ctx.fillRect( p_Right+height/20, 0, p_Right+height/10, p_Bottom);
ctx.restore();
ctx.beginPath();
ctx.fillStyle = "rgb(" + b_color.slice(0, 3).join()+ ")";
ctx.moveTo( height*1.2+height/6 + height/5, 0 );
ctx.lineTo( height*1.2+height/6 + height/20*3, height/5 );
ctx.lineTo( height*1.2+height/6 + height/20*5, height/5 );
ctx.lineTo( height*1.2+height/6 + height/20*1, height/2 );
ctx.lineTo( height*1.2+height/6 + height/20*2, height/4 );
ctx.lineTo( height*1.2+height/6 + height/20*0, height/4 );
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "rgb(" + m_color.join()+ ")";
ctx.lineWidth = line_Width;
var rectWidth = (p_Right-p_Left-s*2) * percent / 100;
ctx.moveTo( p_Left+r+s, p_Top+s );
ctx.lineTo( p_Right-(r+s), p_Top+s );
ctx.arc( p_Right-r, p_Top+r, r-s, -pi/2, 0, false);
ctx.lineTo( p_Right-s, p_Bottom-(r+s) );
ctx.arc( p_Right-r, p_Bottom-r, r-s, 0, pi/2, false);
ctx.lineTo( p_Left+(r+s), p_Bottom-s);
ctx.arc( p_Left+r, p_Bottom-r, r-s, pi/2, pi, false);
ctx.lineTo( p_Left+s, p_Top+(r+s));
ctx.arc( p_Left+r, p_Top+r, r-s, pi, pi*3/2, false);
ctx.closePath();
ctx.clip();
ctx.fillRect( p_Left+s, 0, rectWidth, p_Bottom);
return canvas.toDataURL("image/png");
}
if文で分岐させようと思っていたのですが、総括編ということもありますので、分岐編でやった条件演算子を使いました。
充電していなければ、キャンバス幅はステータスバー高さの1.2倍となり、充電中であれば、キャンバス幅はステータスバー高さの1.65倍になるという記述です。
そして、充電中を示す稲妻マークですが、充電中だけ描画しようと思っておりました。
しかし、常に描画していても、キャンバスからハミ出れば表示されませんので、この性質を利用して、キャンバス幅の算出に手を加えるだけで、実現できてしまいました。
結果は、こんな感じです。
このような通常表示ですが、充電し始めると・・・
キャンバスの幅が広くなり、稲妻マークが出現しました。
そして、充電をやめると・・・
キャンバスの幅が戻り、稲妻マークも消え、通常表示になりました。
ついでに1%増えました。
今回手を加えたのはキャンバスの幅だけですので、充電していない通常表示の時でも、稲妻マークは描画されており、表示されていないだけであることを覚えておいてください。
このサンプルのダウンロード ー> basic15_5.zip
関数化する
では、似たような部分を関数化しましょう。
と言っても、角丸四角形しかありませんね。
スキマの分だけズレることを考慮すれば関数化できます。
関数化したプログラムは、以下の通りです。
(height, percent, charge, low, lpm, m_color, b_color) {
function rounded_Rect( s ){
ctx.beginPath();
ctx.lineWidth = line_Width;
ctx.moveTo( p_Left+r+s, p_Top+s );
ctx.lineTo( p_Right-(r+s), p_Top+s );
ctx.arc( p_Right-r, p_Top+r, r-s, -pi/2, 0, false);
ctx.lineTo( p_Right-s, p_Bottom-(r+s) );
ctx.arc( p_Right-r, p_Bottom-r, r-s, 0, pi/2, false);
ctx.lineTo( p_Left+(r+s), p_Bottom-s);
ctx.arc( p_Left+r, p_Bottom-r, r-s, pi/2, pi, false);
ctx.lineTo( p_Left+s, p_Top+(r+s));
ctx.arc( p_Left+r, p_Top+r, r-s, pi, pi*3/2, false);
ctx.closePath();
}
var canvas = document.createElement("canvas");
canvas.height = height/2;
canvas.width = height * (charge ? 1.65:1.2);
ctx = canvas.getContext("2d");
var r = height / 12;
var line_Width = 1;
var p_Left = line_Width/2;
var p_Right = height*1.1 - line_Width/2;
var p_Top = line_Width/2;
var p_Bottom = canvas.height - line_Width/2;
var pi = Math.PI;
var s = 1;
s += line_Width ;
ctx.strokeStyle = "rgb(" + b_color.slice(0, 3).join()+ ")";
rounded_Rect( 0 );
ctx.stroke();
ctx.beginPath();
ctx.fillStyle = "rgb(" + b_color.slice(0, 3).join()+ ")";
ctx.arc( p_Right+height/30, height/4, height/12, 0, pi*2, false);
ctx.closePath();
ctx.save();
ctx.clip();
ctx.fillRect( p_Right+height/20, 0, p_Right+height/10, p_Bottom);
ctx.restore();
ctx.beginPath();
ctx.fillStyle = "rgb(" + b_color.slice(0, 3).join()+ ")";
ctx.moveTo( height*1.2+height/6 + height/5, 0 );
ctx.lineTo( height*1.2+height/6 + height/20*3, height/5 );
ctx.lineTo( height*1.2+height/6 + height/20*5, height/5 );
ctx.lineTo( height*1.2+height/6 + height/20*1, height/2 );
ctx.lineTo( height*1.2+height/6 + height/20*2, height/4 );
ctx.lineTo( height*1.2+height/6 + height/20*0, height/4 );
ctx.closePath();
ctx.fill();
ctx.fillStyle = "rgb(" + m_color.join()+ ")";
rounded_Rect( s );
var rectWidth = (p_Right-p_Left-s*2) * percent / 100;
ctx.clip();
ctx.fillRect( p_Left+s, 0, rectWidth, p_Bottom);
return canvas.toDataURL("image/png");
}
バッテリーの外枠とバッテリー残量を関数で描画しています。
その際、スキマがあるかどうかの違いしかありませんので、引数もスキマの s のみとなっております。
そのため、バッテリー残量を描画する部分が、そのまま関数になっています。
このサンプルのダウンロード ー> basic15_6.zip
当サイトの更新状況を、アラートで表示するかどうかの設定をします。
保存する