とりあえず、canvasのIDを取得するJavascript関数を作ります。
- function getCanvas (canvasID) {
- var canvasObj = document.getElementById(canvasID);
- if (canvasObj && canvasObj.getContext) {
- return canvasObj.getContext('2d');
- }
- return false;
- }
まず初めに満月を書いてみましょう。
- function drawMoon () {
- var c = getCanvas('TheMoon');
- // 月の半径
- var moon_r = 100;
- // グラデーションの設定
- var gd = c.createRadialGradient(135,135, moon_r*0.9, 140,140, moon_r*1.2);
- gd.addColorStop( 0, 'rgb(233, 84, 100)' );
- gd.addColorStop( 1, 'rgb(123, 74, 80)' );
- // 円を塗りつぶす
- c.beginPath();
- c.arc( 140, 140, moon_r, 0, Math.PI*2, true);
- c.fillStyle = gd;
- c.fill();
- }
- // HTML
- // <canvas id="TheMoon" width="280" height="280"></canvas>
drawMoon()
を実行すると、半径100pxの円形グラデーションが適用された円が表示されます。DEMO(月の色が変なのは気にしない)
次は、月が欠けた分だけ影を追加したいと思います。
上から黒で塗りつぶしても良いけど、芸が無いので、
globalCompositeOperation
プロパティを使って、円に重ねた影の領域を円から削除します。- c.globalCompositeOperation = 'destination-out';
次は、影の形を計算したいと思います。
ややこしいので、月の形を完全な球、月の軌道を完全な円にしてしまいます。
つまり、月齢0の時は全部影になって、右の方から光が当たり始めて、月齢7.5で半月(上弦の月)、月齢15で満月。
その後は右から徐々に影が増えて、月齢22.5で半月、月齢30(月齢0)で新月。
影の左右端はコサインで計算できそうだな。
月の中心座標を0,0として、影の左右端x座標をmoon_xとしよう。
月齢0~15のとき、moon_xが-moon_rから+moon_rに変化して、
月齢16~30のとき、moon_xが-moon_rから+moon_rに変化するんだから・・・
- var moon_grow = (age>15)? true: false;
- var moon_x = Math.cos(age/30*Math.PI*2) * moon_r * (moon_grow? -1: 1);
(age>15)? true: false;
って条件が反対じゃないかというツッコミが来そうですが、良いんです。後々、逆にしておく事で計算が簡単になるんだ。
半円の影とmoon_xを結ぶ片側が潰れた円を描けば良いので最終的にこうなります。
- function drawMoon (age) {
- var c = getCanvas('TheMoon');
- var a = 0.5522847;
- var moon_grow = (age>15)? true: false;
- var moon_r = 100;
- var rate = Math.cos(age/30*Math.PI*2);
- var moon_x = moon_r*rate * (moon_grow? -1: 1);
- var gd = c.createRadialGradient(135,135, moon_r*0.9, 140,140, moon_r*1.2);
- gd.addColorStop( 0, 'rgb(233, 84, 100)' );
- gd.addColorStop( 1, 'rgb(123, 74, 80)' );
- c.beginPath();
- c.arc( 140, 140, moon_r, 0, Math.PI*2, true);
- c.fillStyle = gd;
- c.fill();
- c.globalCompositeOperation = 'destination-out';
- c.beginPath();
- c.fillStyle = 'rgb(192, 70, 80)';
- c.arc( 140, 140, moon_r, Math.PI*1/2, Math.PI*3/2, moon_grow);
- c.bezierCurveTo( 140+a*moon_x,140-moon_r, 140+moon_x,140-a*moon_r, 140+moon_x,140);
- c.bezierCurveTo( 140+moon_x,140+a*moon_r, 140+a*moon_x,140+moon_r, 140,140+moon_r);
- c.fill();
- }
c.bezierCurveTo()
メソッドで3次ベジェ曲線を使って楕円を描画しています。制御点の計算が難しかったのですが、こちらを参考に係数をa=0.5522847として決めて様子見したところ、上手くいっていたのでそのまま採用しました。
c.arc( 140, 140, moon_r, Math.PI*1/2, Math.PI*3/2, moon_grow);
で月齢16を境に、右半円、左半円を切り替えているところがポイントですかね。そんなこんなで、色々とキャンバスの理解につながったので良かった。
「今日のお月さま」というサービスでアップしたので、良かったら見て下さい。
今日のお月さま作成にあたり参考にしたサイト
月齢カレンダー
http://koyomi.vis.ne.jp/moonage.htm
Canvasリファレンス - HTML5.JP
http://www.html5.jp/canvas/ref.html
s.h's page - [graphic] ベジエ曲線
http://park12.wakwak.com/~shp/cgi-bin/wiki.cgi/view/bezier_curve
月齢 - Wikipedia
http://ja.wikipedia.org/wiki/%E6%9C%88%E9%BD%A2
0 件のコメント:
コメントを投稿