テーマの基本 その13
(コピペ編)

これまでは、何かを紹介するためにネタを用意していましたが、今回はリベンジの意味合いが強いです。
前回の「図形切り抜き編」では、こんなバッテリーを作りました。


しかし、もともと作ろうとしていたのは、こんな感じのモノでした。

今回は、コイツをやっつけましょう!!

デザインを設計する

作り始める前に、デザインを決めましょう。
イメージが固まっていないと、行き詰まるだけですので・・・

寸法チェック

元となる画像の寸法を見てみましょう。
通信信号強度の画像は、通常時とロック時で大きさが違います。
それぞれ、寸法チェックしてみました。


円の直径が16と21とで違いがありますが、間隔はどちらも5でした。

大きさを決める

円の間隔がどちらも5だったので、見た感じではもう少し狭くても良さそうですが、円の間隔は5にします。
円の大きさは20を超えていたいのですが、最終的にはデバイスの違いに対応したいので、割り切れる数を狙いたいですね。
しかも、円の半径で計算をしていくので、半径が自然数になるように考えると、ステータスバー高さの5分の1か4分の1が妥当でしょう。
基本テストはiPhone6Plusで進めていますので、@3xデバイスでの数値で考えると、5分の1では円の直径は24、4分の1では円の直径は30となります。

30ということは、ステータスバーに表示される情報とほぼ同じ大きさなので、30で進めても良さそうなのですが、基本その12で 確認したように、やたら横長になることが分かっています。
ですので、円の大きさは、ステータスバー高さの5分の1とします。

動作を決める

動作と言っても、一般的な動作と変わりません。
ただ、今回はこれまでのような連続的なモノではなく、スキマによって表示領域が飛び飛びとなっているため、残量表示には工夫が必要です。

前回は、このスキマがあるために連続した図形に変更し、切り抜きも簡単だったのですが、スキマがあるということは同じような切り抜きができないということになります。
スキマに残量を表示できませんので、残量を5つに分けて表示することになります。
1つの円で20%を表現するわけですね。
そうすることにより、作るのも楽になるかと思います。
0%−20%は1つ目の円で表現し、21%〜40%は2つ目の円で表現する形になります。
ですので、70%の場合、  のように表示することができれば大成功となります。

プログラミング的に考える

イメージが固まりましたので、実際どのようにプログラミングしていくか考えましょう。

残量を5つに分ける

デザインが5つの円で構成されていますので、そこに表示するバッテリー残量も5つに分けなければいけません。
単純に5で割れば良いのですが、バッテリー残量は0〜100ですので、101コの数値を5つに分けるには、単純に5で割るだけでは無理があります。
先ほども文章内で説明しましたが、円の順番と円が表現する残量との関係を表にしてみます。

円と残量の関係

円の順番(左から) バッテリー残量
0% 〜 20%
21% 〜 40%
41% 〜 60%
61% 〜 80%
81% 〜 100%

1つ目の円で0%〜20%を表現することになるのですね。

円への振り分けを考える

残量20%までが1つ目の円、40%までが2つ目の円といった具合に考えられますので、残量を20で割った商+1が表における円の順番に対応します。
例えば、残量が75%だった場合、対応する円は左から4つ目ですので、4つ目の円で残量を反映させます。
つまり、4つ目の円は3/4だけ塗りつぶされた状態となるわけです。
3つ目までは完全に塗りつぶされた円を表示しますので、円をコピーして表示することにします。

図形をコピーする方法を知る

では、円を描画して、描画した円をコピーする方法を学びましょう。
コピーするには、以下のように記述します。
ctx.getImageData( 取得範囲の開始x座標, 取得範囲の開始y座標, 取得範囲の幅, 取得範囲の高さ ) 引数は4つ必要ですが、取得した画像を画像データとして格納する入れ物(変数)を用意しておきましょう。
そして、取得した画像(データ)を貼り付けるには、以下のように記述します。
ctx.putImageData( 配置する画像, 配置するx座標, 配置するy座標 ) 画像の大きさは決まっているので、引数は、配置する画像(データ)と配置する座標だけで実現できます。

このコピー機能を使って、円の枠線も塗りつぶしも1度だけの描画で済ませましょう。

今回の画像切り抜きは・・・

切り抜く円は特定できますし、clip を使う切り抜き方法も知っているので、そのままプログラミングを始めても良いのですが、clip を使わずに切り抜いてみましょう。

何を使って切り抜くかというと、「putImageData」です。
先ほど紹介したばかりなので、おや?と思う方が多いかと思いますが、間違いなく「putImageData」を使います。
実は、putImageData には、トリミングする機能もあります。
トリミングして配置するには、以下のように記述します。
ctx.putImageData( 配置する画像, 配置するx座標, 配置するy座標, 切抜範囲の開始x座標, 切抜範囲の開始y座標, 切抜範囲の幅, 切抜範囲の高さ ) putImageData による切り抜きは、その範囲の形状が矩形(四角形)に限定されますので、他の図形で切り抜きたい場合は clip を使いましょう。
切抜範囲の開始座標は、配置する画像の左上を (0, 0) とします。

バッテリーの外枠を描画する

では、バッテリーの外枠となる円を描画しましょう。

コピー元専用コンテキストを用意する

描画したものをコピーしますので、これまでのように、1つのコンテキストに描画して、それをコピーしようとすると、無理が生じます。
そもそも、コンテキストを用意するところから始めますので、コピー元専用のコンテキストを用意し、そこに描画したものをコピーし、バッテリー画像出力用のコンテキストに貼り付けるという流れにします。

コピー元専用コンテキストを ctx_stroke と命名します。
これは、外枠を stroke で描画するため、このように命名しました。
コンテキストを用意する部分は、以下のように記述します。
var r = height / 5;

var canvas_stroke = document.createElement("canvas");
canvas_stroke.height = r * 2;
canvas_stroke.width = canvas_stroke.height;
var ctx_stroke = canvas_stroke.getContext("2d");
円を描画するためだけのキャンバスを用意したので、大きさは円の大きさとなり、幅も高さも直径(半径の2倍)としてあります。
先に、コンテキストを ctx_stroke としたので、キャンバスは canvas_stroke としました。

コピー元専用コンテキストに円を描画する

コピー元専用コンテキストを用意しましたので、外枠となる円を描画しましょう。
円の描画は、以下のように記述します。
var r = height / 5;

var canvas_stroke = document.createElement("canvas");
canvas_stroke.height = r * 2;
canvas_stroke.width = canvas_stroke.height;
var ctx_stroke = canvas_stroke.getContext("2d");
ctx_stroke.strokeStyle="rgb(" + b_color.slice(0, 3).join()+ ")";
ctx_stroke.arc( r, r, r, 0, 2*Math.PI );
ctx_stroke.stroke();
何も問題ないかと思います。

コピーする

外枠となる円を描画しましたので、コピーしましょう。
円を描画してコピーするには、以下のように記述します。
var r = height / 5;

var canvas_stroke = document.createElement("canvas");
canvas_stroke.height = r * 2;
canvas_stroke.width = canvas_stroke.height;
var ctx_stroke = canvas_stroke.getContext("2d");
ctx_stroke.strokeStyle="rgb(" + b_color.slice(0, 3).join()+ ")";
ctx_stroke.arc( r, r, r, 0, 2*Math.PI );
ctx_stroke.stroke();
var img_stroke = ctx_stroke.getImageData(0, 0, canvas_stroke.width, canvas_stroke.height);
1行追加しただけですね。
この1行で、コピー元専用コンテキストに描画した円全体をコピーしています。

貼り付ける

貼り付けるには putImageData を使えば良いのですが、5つの円を描画するためのコンテキストが必要です。
5つの円を並べるのですが、円と円の間隔も必要です。
いろいろ用意するものがありますが、円を5つ貼り付ける全体のプログラムは、以下の通りです。
(height, percent, charge, low, lbr, m_color, b_color) {
 var r = height / 5;
 var m = 5;

 var canvas_stroke = document.createElement("canvas");
 canvas_stroke.height = r * 2;
 canvas_stroke.width = canvas_stroke.height;
 var ctx_stroke = canvas_stroke.getContext("2d");
 ctx_stroke.strokeStyle="rgb(" + b_color.slice(0, 3).join()+ ")";
 ctx_stroke.arc( r, r, r, 0, 2*Math.PI );
 ctx_stroke.stroke();
 var img_stroke = ctx_stroke.getImageData(0, 0, canvas_stroke.width, canvas_stroke.height);

 var canvas = document.createElement("canvas");
 canvas.height = height / 2;
 canvas.width = 2*r * 5 + m*4;
 var ctx = canvas.getContext("2d");
 var p_Center = canvas.height / 2 ;

 for ( i = 0 ; i < 5 ; i = i+1 ){
  ctx.putImageData(img_stroke, i*(2*r+m), p_Center-r);
 }

 return canvas.toDataURL("image/png");
}
円と円の間隔は、スキマの「マ」から m としました。
円の直径と、このスキマにより、キャンバスの幅を算出しています。
今までの流れもありますので、キャンバスの中心高さを p_Center としたままで進めています。
あとは for 文で貼り付けを繰り返すだけなのですが、for 文の()内には3つの区分があります。
1つ目では、i に0を代入していますが、ここで繰り返しの初期値を設定します。その際の変数は何でも良いのですが、i や j や k を使うのが通例となっております。
2つ目では、繰り返しの条件を指定します。
i < 5 ですので、i が5未満である限り繰り返しの処理が継続されることになります。
3つ目では、繰り返しのための変数(ここでは i)の増減を指定します。
i = i + 1 としているので、この例では、繰り返されるたびに i の値が1増えていくことになります。
この for 文で、i は0から4の値を取りながら、{}内の処理を繰り返します。つまり、{}内に記述された「貼り付ける」という処理を5回繰り返すということです。
なお、配置する座標を毎回算出するために、i を計算式に取り入れています。


結果は、こんな感じです。

おっと・・・
線幅を考えていませんでしたね。
部分的に欠けてしまっています。

以下のように、線幅を考えてやり直してみました。
(height, percent, charge, low, lbr, m_color, b_color) {
 var r = height / 5;
 var m = 5;
 var line_Width = 1;

 var canvas_stroke = document.createElement("canvas");
 canvas_stroke.height = r * 2;
 canvas_stroke.width = canvas_stroke.height;
 var ctx_stroke = canvas_stroke.getContext("2d");
 ctx_stroke.lineWidth = line_Width;
 ctx_stroke.strokeStyle="rgb(" + b_color.slice(0, 3).join()+ ")";
 ctx_stroke.arc( r, r, r-line_Width/2, 0, 2*Math.PI );
 ctx_stroke.stroke();
 var img_stroke = ctx_stroke.getImageData(0, 0, canvas_stroke.width, canvas_stroke.height);

 var canvas = document.createElement("canvas");
 canvas.height = height / 2;
 canvas.width = 2*r * 5 + m*4;
 var ctx = canvas.getContext("2d");
 var p_Center = canvas.height / 2 ;

 for ( i = 0 ; i < 5 ; i++ ){
  ctx.putImageData(img_stroke, i*(2*r+m), p_Center-r);
 }

 return canvas.toDataURL("image/png");
}
これで、線幅を変更しても対応できるようになりました。
for 文において、i の増減が i++ となっていますが、「次は1増やそう」という場合、このように記述することもできますので、ここで紹介しました。


結果は、こんな感じです。
線幅を1〜3まで変化させてみました。



これは細くても良さそうですね。


このサンプルのダウンロード ー> basic13_1.zip

円を塗りつぶして残量を表現する

バッテリー外枠の描画ができましたので、塗りつぶしてバッテリー残量を表現してみましょう。
バッテリー残量は塗りつぶしなので、専用のコンテキストをもう1つ用意することにします。
(基本的に、外枠描画と同じです)

コピー元専用コンテキストを用意する

今回は塗りつぶしの円のためのコンテキストなので、コピー元専用コンテキストを ctx_fill と命名します。
これは、円を fill で塗りつぶすため、このように命名しました。
コンテキストを用意する部分は、以下のように記述します。
var r = height / 5;

var canvas_fill = document.createElement("canvas");
canvas_fill.height = r * 2;
canvas_fill.width = canvas_fill.height;
var ctx_fill = canvas_fill.getContext("2d");
stroke を fill に変更しただけですね。

コピー元専用コンテキストで円を塗りつぶす

コピー元専用コンテキストを用意しましたので、円を塗りつぶしましょう。
円を塗りつぶすには、以下のように記述します。
var r = height / 5;

var canvas_fill = document.createElement("canvas");
canvas_fill.height = r * 2;
canvas_fill.width = canvas_fill.height;
var ctx_fill = canvas_fill.getContext("2d");
ctx_fill.fillStyle="rgb(" + b_color.slice(0, 3).join()+ ")";
ctx_fill.arc( r, r, r, 0, 2*Math.PI );
ctx_fill.fill();
こちらも stroke を fill に変更しただけですね。

コピーする

外枠と同様に、コピーしましょう。
円を塗りつぶしてコピーするには、以下のように記述します。
var r = height / 5;

var canvas_fill = document.createElement("canvas");
canvas_fill.height = r * 2;
canvas_fill.width = canvas_fill.height;
var ctx_fill = canvas_fill.getContext("2d");
ctx_fill.fillStyle="rgb(" + b_color.slice(0, 3).join()+ ")";
ctx_fill.arc( r, r, r, 0, 2*Math.PI );
ctx_fill.fill();
var img_fill = ctx_fill.getImageData(0, 0, canvas_fill.width, canvas_fill.height);
こちらも stroke を fill に変更しただけです。

貼り付ける

では、塗りつぶした図形を貼り付けましょう。
塗りつぶした円を5つ貼り付ける全体のプログラムは、以下の通りです。
(height, percent, charge, low, lbr, m_color, b_color) {
 var r = height / 5;
 var m = 5;

 var canvas_fill = document.createElement("canvas");
 canvas_fill.height = r * 2;
 canvas_fill.width = canvas_fill.height;
 var ctx_fill = canvas_fill.getContext("2d");
 ctx_fill.fillStyle="rgb(" + b_color.slice(0, 3).join()+ ")";
 ctx_fill.arc( r, r, r, 0, 2*Math.PI );
 ctx_fill.fill();
 var img_fill = ctx_fill.getImageData(0, 0, canvas_fill.width, canvas_fill.height);

 var canvas = document.createElement("canvas");
 canvas.height = height / 2;
 canvas.width = 2*r * 5 + m*4;
 var ctx = canvas.getContext("2d");
 var p_Center = canvas.height / 2 ;

 for ( i = 0 ; i < 5 ; i++ ){
  ctx.putImageData(img_fill, i*(2*r+m), p_Center-r);
 }

 return canvas.toDataURL("image/png");
}
こちらも stroke を fill に変更しただけです。


結果は、こんな感じです。

おっと・・・
線幅を考えていなくても、部分的に欠けていません。
線を引いていないので、線幅は関係ないのでしょうね。


このサンプルのダウンロード ー> basic13_2.zip

バッテリー残量を反映させる

コピーができるようになりましたので、実際にバッテリー残量を反映させていきましょう。

考え方を整理する

円を5つ並べましたが、バッテリー残量を反映させるには、どの円で切抜き表示をするかがポイントになると思います。
そのために表を作ったので、表を活かして考えていきましょう。

塗りつぶしても、塗りつぶさなくても、5つの円は必ず描画します。
繰り返して円を貼り付けるという作業は必ず行なうということです。
ということは、繰り返しの中で、どちらの円を貼り付けるのかを判断しながら貼り付けるということになります。

ポイントとなるのは、切抜き表示をする円です。
「残量を20で割った商+1が円の順番に対応する」というところまでは、表から導かれていますので、残量を20で割るところから始めましょう。
繰り返しの中で判断するので、これまで1番目としていた円を0番目とします。
人間が理解しやすいのは1〜5なのですが、実際に作業するのは人間ではありませんし、プログラムの所々で1を引いて計算しなければならないため、プログラミングでは主に0から数え始めるようにします

ここで、改めて、表を確認しましょう。
プログラミングを意識して、項目を増やしました。

円と残量の新たな関係

円の順番 (左から) バッテリー残量 残量 / 20
0% 〜 20% 0.00 〜 1.00
21% 〜 40% 1.05 〜 2.00
41% 〜 60% 2.05 〜 3.00
61% 〜 80% 3.05 〜 4.00
81% 〜 100% 4.05 〜 5.00

残量/20が円の順番を超えたとき、その円が切抜き対象の円と判断できます。
そして、切抜き対象の円までは、完全塗りつぶしの円を表示し、切抜き対象の円を描画した後は塗りつぶす必要がなくなります。

では、この表を基に、フローチャートを作ってみます。

残量/20がどの円の位置にあるかを判断します。
表において、残量/20の整数部分が円の順番となっているので、比較対象の円番号を残量/20が超えたとき、その円が切り抜き対象となります。
問題は、繰り返しの中で判断するということです。
比較対象の円番号を0からとしているため、切り抜き対象かどうかの前に、塗りつぶし対象かどうかの判断が必要になります。
i+1 がそうであり、次の円が切抜き対象なら、その円は塗りつぶし対象となります。
残量/20の小数点以下00のことを考えて「小なりイコール」とします。

使える武器を確認する

ここで言う「使える武器」とは、プログラムを組むための道具(命令)です。
これまで紹介したもので完成しますので、確認しましょう。

繰り返し
for( ... ) {
 繰り返す処理
}

条件処理
if ( 条件1 ) {
 条件1を満たしたときの処理
} else if ( 条件2 ) {
 条件1を満たさず条件2を満たしたときの処理
} else {
 条件1も条件2も満たさないときの処理
}

円弧の描画
ctx.arc(中心のX座標, 中心のY座標, 半径, 開始角, 終了角, 描画方向)
画像のコピー
ctx.getImageData( 取得範囲の開始x座標, 取得範囲の開始y座標, 取得範囲の幅, 取得範囲の高さ )
画像の貼り付け
ctx.putImageData( 配置する画像, 配置するx座標, 配置するy座標 )
こんな感じでしょうか。
色の指定は省きます。

プログラミングする

では、プログラミングしていきましょう。
外枠表示も円の塗りつぶしもすでに完了しているので、いきなりやってみます。

バッテリー残量を反映させたプログラムは、以下の通りです。
(height, percent, charge, low, lbr, m_color, b_color) {
 var line_Width = 1;
 var r = height / 5;
 var m = 5;
 var canvas_stroke = document.createElement("canvas");
 canvas_stroke.height = r * 2;
 canvas_stroke.width = canvas_stroke.height;
 var ctx_stroke = canvas_stroke.getContext("2d");
 ctx_stroke.lineWidth = line_Width;
 ctx_stroke.strokeStyle="rgb(" + b_color.slice(0, 3).join()+ ")";
 ctx_stroke.arc( r, r, r-line_Width/2 , 0, 2*Math.PI );
 ctx_stroke.stroke();
 var img_stroke = ctx_stroke.getImageData(0, 0, canvas_stroke.width, canvas_stroke.height);

 var canvas_fill = document.createElement("canvas");
 canvas_fill.height = r * 2;
 canvas_fill.width = canvas_fill.height;
 var ctx_fill = canvas_fill.getContext("2d");
 ctx_fill.fillStyle="rgb(" + m_color.join()+ ")";
 ctx_fill.arc( r, r, r, 0, 2*Math.PI );
 ctx_fill.fill();
 var img_fill = ctx_fill.getImageData(0, 0, canvas_fill.width, canvas_fill.height);

 var canvas = document.createElement("canvas");
 canvas.height = height / 2;
 canvas.width = 2*r * 5 + m*4;
 var ctx = canvas.getContext("2d");
 var p_Center = height / 4 ;

 for ( i = 0 ; i < 5 ; i++ ){
  ctx.putImageData(img_stroke, i*(2*r+m), p_Center-r);
  if ( i+1 <= percent/20 ) {
   ctx.putImageData(img_fill, i*(2*r+m), p_Center-r);
  }
  else if ( i < percent/20 ) {
   var rectWidth = 2*r * (percent%20) / 20;
   ctx.putImageData(img_fill, i*(2*r+m), p_Center-r, 0, 0, rectWidth, 2*r);
  }
 }

 return canvas.toDataURL("image/png");
}
for 文の繰り返しの中で条件判断をしています。
外枠は繰り返しの直後に無条件で描画し、条件判断において、完全塗りつぶし描画なのか切抜き描画なのか決めています。
ポイントは切抜き用の変数 rectWidth の計算です。
切り抜く円が決まったら、その円では0%〜19%を表現すれば良いので、残量を20で割った余りを円の直径に反映させています。


結果は、こんな感じです。


希望通りのバッテリーが表現できました。


このサンプルのダウンロード ー> basic13_3.zip

枠線を残す

希望通りのバッテリーが表現できましたが、同じ大きさの塗りつぶしの円によって、枠線が消えてしまっています。
これまで作ってきたサンプル同様に、枠線の内側に残量を表示しようと思います。

線幅を考慮するのですが、これもこれまでにやってきたので、いきなりやってみます。

線幅を考慮したプログラムは、以下の通りです。
(height, percent, charge, low, lbr, m_color, b_color) {
 var line_Width = 1;
 var r = height / 5;
 var m = 5;
 var canvas_stroke = document.createElement("canvas");
 canvas_stroke.height = r * 2;
 canvas_stroke.width = canvas_stroke.height;
 var ctx_stroke = canvas_stroke.getContext("2d");
 ctx_stroke.lineWidth = line_Width;
 ctx_stroke.strokeStyle="rgb(" + b_color.slice(0, 3).join()+ ")";
 ctx_stroke.arc( r, r, r-line_Width/2 , 0, 2*Math.PI );
 ctx_stroke.stroke();
 var img_stroke = ctx_stroke.getImageData(0, 0, canvas_stroke.width, canvas_stroke.height);

 var canvas_fill = document.createElement("canvas");
 canvas_fill.height = r * 2;
 canvas_fill.width = canvas_fill.height;
 var ctx_fill = canvas_fill.getContext("2d");
 ctx_fill.fillStyle="rgb(" + m_color.join()+ ")";
 ctx_fill.arc( r, r, r-line_Width, 0, 2*Math.PI );
 ctx_fill.fill();
 var img_fill = ctx_fill.getImageData(line_Width, line_Width, canvas_fill.width-2*line_Width, canvas_fill.height-2*line_Width);

 var canvas = document.createElement("canvas");
 canvas.height = height / 2;
 canvas.width = 2*r * 5 + m*4;
 var ctx = canvas.getContext("2d");
 var p_Center = height / 4 ;

 for ( i = 0 ; i < 5 ; i++ ){
  ctx.putImageData(img_stroke, i*(2*r+m), p_Center-r);
  if ( i+1 <= percent/20 ) {
   ctx.putImageData(img_fill, i*(2*r+m)+line_Width, p_Center-(r-line_Width));
  }
  else if ( i < percent/20 ) {
   var rectWidth = 2*(r-line_Width) * (percent%20) / 20;
   ctx.putImageData(img_fill, i*(2*r+m)+line_Width, p_Center-(r-line_Width), 0, 0, rectWidth, 2*(r-line_Width));
  }
 }

 return canvas.toDataURL("image/png");
}
外枠はそのままで、塗りつぶしだけに変更を加えています。
半径は線幅の分だけ短くなり、切り抜く幅は線幅の2倍狭くなっています。
貼り付ける場所も、線幅の分だけズラしています。


結果は、こんな感じです。

線幅の分だけ残して貼り付いているますが、枠線の4隅が消えています。
大失敗の匂いがプンプンしますね。

これは、コピーするときは四角形(矩形)でコピーし、貼り付けるときも四角形(矩形)で貼り付けることが原因になっていることが考えられます。
コピーの宿命ですので、これ以上の改善は見込めませんね・・・


このサンプルのダウンロード ー> basic13_4.zip

なんとか完成させる

何だかコピペの限界を感じてしまいましたが、枠線を残そうとしなければ完成しているので、無理に枠線に拘らなければ良いと思います。
しかし、枠線に掛からないくらいのスキマがあれば何とかなりそうなので、スキマを設けて対応してみようと思います。
スキマに関してもこれまでやってきたので、こちらもいきなりやってみます。

スキマを設けたプログラムは、以下の通りです。
(height, percent, charge, low, lbr, m_color, b_color) {
 var line_Width = 1;
 var r = height / 5;
 var s = 3;
 var m = 5;

 var canvas_stroke = document.createElement("canvas");
 canvas_stroke.height = r * 2;
 canvas_stroke.width = canvas_stroke.height;
 var ctx_stroke = canvas_stroke.getContext("2d");
 ctx_stroke.lineWidth = line_Width;
 ctx_stroke.strokeStyle="rgb(" + b_color.slice(0, 3).join()+ ")";
 ctx_stroke.arc( r, r, r-line_Width/2 , 0, 2*Math.PI );
 ctx_stroke.stroke();
 var img_stroke = ctx_stroke.getImageData(0, 0, canvas_stroke.width, canvas_stroke.height);

 var canvas_fill = document.createElement("canvas");
 canvas_fill.height = r * 2;
 canvas_fill.width = canvas_fill.height;
 var ctx_fill = canvas_fill.getContext("2d");
 ctx_fill.fillStyle="rgb(" + m_color.join()+ ")";
 ctx_fill.arc( r, r, r-(line_Width+s), 0, 2*Math.PI );
 ctx_fill.fill();
 var img_fill = ctx_fill.getImageData(line_Width+s, line_Width+s, canvas_fill.width-2*(line_Width+s), canvas_fill.height-2*(line_Width+s));

 var canvas = document.createElement("canvas");
 canvas.height = height / 2;
 canvas.width = 2*r * 5 + m*4;
 var ctx = canvas.getContext("2d");
 var p_Center = height / 4 ;

 for ( i = 0 ; i < 5 ; i++ ){
  ctx.putImageData(img_stroke, i*(2*r+m), p_Center-r);
  if ( i+1 <= percent/20 ) {
   ctx.putImageData(img_fill, i*(2*r+m)+line_Width+s, p_Center-r-line_Width+s);
  }
  else if ( i < percent/20 ) {
   var rectWidth = 2*(r-(line_Width+s)) * (percent%20) / 20;
   ctx.putImageData(img_fill, i*(2*r+m)+(line_Width+s), p_Center-(r-(line_Width+s)), 0, 0, rectWidth, 2*(r-(line_Width+s)));
  }
 }

 return canvas.toDataURL("image/png");
}
スキマはこれまで通り s としました。
スキマ s と線幅 line_Width を絡めていることがお分かりいただけるかと思います。


スキマを0から3まで変化させた結果は、こんな感じです。


スキマが3になると、枠線に掛からなくなりました。
ただ、これはiPhone6Plusでの結果ですので、デバイスに対応させなければなりませんね。
iPhone6Plusでのスキマが3ということですので、ステータスバー高さの20分の1でいけると思います。

s = height / 20 としてやってみた結果は、こんな感じです。


何とか完成形にたどり着いた感じですね。


このサンプルのダウンロード ー> basic13_5.zip



当サイトの更新状況を、アラートで表示するかどうかの設定をします。


保存する

その機能で月額1500円もするのですか??
その機能なら年額1500円で手に入りますよ!

当サイトもこちらのレンタルサーバーを利用しています。

Copyright (C) 2007 Bokechans.net All Rights Reserved.