サイトを雪で装飾するための、HTML5 Canvasでの大Year日のエンターテインメント(Canvasの動作を確認するための興味深い例です)。
私の話では
、 Giorgio Sardo コードに基づいて構築し
ます 。これは
、David Flanaganコードに基づいて
います 。

以下で説明するすべてのことは、JavaScriptコンソールを起動するだけで、開発ツールを備えた最新のブラウザーでHabréで直接試すことができます。 IE9では、F12キーを押すだけで、このページで直接テストする場合は、ブラウザーをInternet Explorer 9 Standard(Alt + 9)モードにすることを忘れないでください。 デフォルトでは、HabrにはIE8モードが必要です。
Canvasサポートの確認
まず、ブラウザーがCanvasをサポートしていることを確認することから始める必要があります。そのためには、Canvasエレメントを作成し、作業のコンテキストを取得する必要があります。
if ( document .createElement( 'canvas' ).getContext) {
...
}
else {
...
}
最初のケースでは、先に進んで雪片を開始できます。
キャンバスを作成する
雪片を描くために、フルスクリーンでキャンバス(キャンバス)を作成します:
var canvas = document .createElement( 'canvas' );
canvas.style.position = 'fixed' ;
canvas.style.top = '0px' ;
canvas.style.left = '0px' ;
canvas.style.zIndex = '-10' ;
canvas.width = document .body.offsetWidth;
canvas.height = window.innerHeight;
document .body.insertBefore(canvas, document .body.firstChild);
この場合、新しいCanvas要素を作成し、固定された場所を指定して、残りの要素と干渉しないように配置しようとします。
次に、レンダリングのコンテキストを取得します。
var sky = canvas.getContext( '2d' );
コッホスノーフレーク
habrayuzersにとって、
コッホ・スノーフレークが何であるかはよく知られているべきだと思うので、私は写真に自分自身を制限します:

この作品はフラクタルで、便利に再帰的に描かれています。 三角形を描くには、同じ描画パターンを各エッジに順番に適用する必要があります。

1本の線を引くことから始めましょう。 便利なレンダリングの場合、各ローカルレンダリングが水平な直線の描画のように見える
変換 (スケーリングと回転)を適用できます。 つまり、線の描画を回転させるのではなく、コンテキストを拡大縮小して回転させます(変換行列を変更します)。
変換マトリックスの状態を保存および復元するには、それぞれsave()およびrestore()関数を使用します。
作業中に、度をラジアンに変換する必要があります(ただし、必要に応じて、すぐにラジアンで記述できます)。
var deg = Math.PI / 180;
1つのエッジを描く再帰関数は次のようになります。
function leg(n, len) {
sky.save(); //
if (n == 0) { // -
sky.lineTo(len, 0); }
else {
sky.scale(1 / 3, 1 / 3); // 3
leg(n – 1, len); sky.rotate(60 * deg);
leg(n – 1, len); sky.rotate(-120 * deg);
leg(n – 1, len); sky.rotate(60 * deg); leg(n – 1, len); }
sky.restore(); //
sky.translate(len, 0); //
}
レンダリングを開始するには、次の関数を使用できます。
function drawFlake(x, y, len, n, stroke, fill) {
sky.save(); sky.strokeStyle = stroke;
sky.fillStyle = fill;
sky.beginPath();
sky.translate(x, y);
sky.moveTo(0, 0); leg(n, len); sky.closePath();
sky.fill();
sky.stroke();
sky.restore();
}
描画するには、パスの作成を開始する必要があることに注意してください。必要に応じて、パスを閉じてから、領域を塗りつぶして線を描画する必要があることを伝えます。 結果:

対応する回転でさらにいくつかのエッジを追加すると、雪片が得られます。
function drawFlake(x, y, len, n, stroke, fill) {
sky.save(); sky.strokeStyle = stroke;
sky.fillStyle = fill;
sky.beginPath();
sky.translate(x, y);
sky.moveTo(0, 0); leg(n, len); sky.rotate(-120 * deg);
leg(n, len); sky.rotate(-120 * deg);
leg(n, len); sky.closePath();
sky.fill();
sky.stroke();
sky.restore();
}
結果:

雪片の作成と移動
さらに、アイデアは非常に透明です。1)タイマーに雪片を追加して雪片のプールを作成し、2)タイマーで雪片の位置を変更して描画します。
雪片の追加
ランダムな値、雪片の配列、最大数の追加機能。 タイマーを設定します。
var rand = function (n) { return Math.floor(n * Math.random()); }
var flakes = []; var maxflakes = 20;
var snowspeed = 500;
var snowingTimer = setInterval(createSnowflake, snowspeed);
そして実際には、雪片の作成(適切なタイミングで、タイマーをクリーニングすることで新しい雪片の作成を停止します):
function createSnowflake() {
var order = 3;
var size = 10 + rand(50);
var x = rand( document .body.offsetWidth);
var y = window.pageYOffset;
flakes.push({ x: x, y: y, vx: 0, vy: 3 + rand(3), size: size, order: order, stroke: "#99f" , fill: "transparent" });
if (flakes.length > maxflakes) clearInterval(snowingTimer);
}
雪片の移動
画面サイズを変更するとtrueに設定される追加の変数invalidateMeasureが表示されます。 タイマーを設定して、位置と実際の移動機能を更新します(画面をクリアし、位置を更新->雪片を描画)。
var scrollspeed = 64;
setInterval(moveSnowflakes, scrollspeed);
function moveSnowflakes() {
sky.clearRect(0, 0, canvas.width, canvas.height);
var maxy = canvas.height;
for ( var i = 0; i < flakes.length; i++) {
var flake = flakes[i];
flake.y += flake.vy;
flake.x += flake.vx;
if (flake.y > maxy) flake.y = 0;
if (invalidateMeasure) {
flake.x = rand(canvas.width);
}
drawFlake(flake.x, flake.y, flake.size, flake.order, flake.stroke, flake.fill);
//
if (rand(4) == 1) flake.vx += (rand(11) - 5) / 10;
if (flake.vx > 2) flake.vx = 2;
if (flake.vx < -2) flake.vx = -2;
}
if (invalidateMeasure) invalidateMeasure = false ;
}
最終コード
さらに、雪片のランダムな回転と雪片のランダムな色+サイズに応じた詳細など、いくつかの詳細を追加できます。
( function () {
if ( document .createElement( 'canvas' ).getContext) {
if ( document .readyState === 'complete' )
snow();
else
window.addEventListener( 'DOMContentLoaded' , snow, false );
}
else {
return ;
}
var deg = Math.PI / 180;
var maxflakes = 20; var flakes = []; var scrollspeed = 64; var snowspeed = 500;
var canvas, sky;
var snowingTimer;
var invalidateMeasure = false ;
var strokes = [ "#6cf" , "#9cf" , "#99f" , "#ccf" , "#66f" , "#3cf" ];
function rand (n) {
return Math.floor(n * Math.random());
}
//
function snow() {
canvas = document .createElement( 'canvas' );
canvas.style.position = 'fixed' ;
canvas.style.top = '0px' ;
canvas.style.left = '0px' ;
canvas.style.zIndex = '-10' ;
document .body.insertBefore(canvas, document .body.firstChild);
sky = canvas.getContext( '2d' );
ResetCanvas();
snowingTimer = setInterval(createSnowflake, snowspeed);
setInterval(moveSnowflakes, scrollspeed);
window.addEventListener( 'resize' , ResetCanvas, false );
}
// Canvas
function ResetCanvas() {
invalidateMeasure = true ;
canvas.width = document .body.offsetWidth;
canvas.height = window.innerHeight;
}
//
function leg(n, len) {
sky.save(); //
if (n == 0) { // -
sky.lineTo(len, 0); }
else {
sky.scale(1 / 3, 1 / 3); // 3
leg(n - 1, len); sky.rotate(60 * deg);
leg(n - 1, len); sky.rotate(-120 * deg);
leg(n - 1, len); sky.rotate(60 * deg); leg(n - 1, len); }
sky.restore(); //
sky.translate(len, 0); //
}
//
function drawFlake(x, y, angle, len, n, stroke, fill) {
sky.save(); sky.strokeStyle = stroke;
sky.fillStyle = fill;
sky.beginPath();
sky.translate(x, y);
sky.moveTo(0, 0); sky.rotate(angle);
leg(n, len);
sky.rotate(-120 * deg);
leg(n, len); sky.rotate(-120 * deg);
leg(n, len); sky.closePath();
sky.fill();
sky.stroke();
sky.restore();
}
//
function createSnowflake() {
var order = 2+rand(2);
var size = 10*order+rand(10);
var x = rand( document .body.offsetWidth);
var y = window.pageYOffset;
var stroke = strokes[rand(strokes.length)];
flakes.push({ x: x, y: y, vx: 0, vy: 3 + rand(3), angle:0, size: size, order: order, stroke: stroke, fill: 'transparent' });
if (flakes.length > maxflakes) clearInterval(snowingTimer);
}
//
function moveSnowflakes() {
sky.clearRect(0, 0, canvas.width, canvas.height);
var maxy = canvas.height;
for ( var i = 0; i < flakes.length; i++) {
var flake = flakes[i];
flake.y += flake.vy;
flake.x += flake.vx;
if (flake.y > maxy) flake.y = 0;
if (invalidateMeasure) {
flake.x = rand(canvas.width);
}
drawFlake(flake.x, flake.y, flake.angle, flake.size, flake.order, flake.stroke, flake.fill);
//
if (rand(4) == 1) flake.vx += (rand(11) - 5) / 10;
if (flake.vx > 2) flake.vx = 2;
if (flake.vx < -2) flake.vx = -2;
if (rand(3) == 1) flake.angle = (rand(13) - 6) / 271;
}
if (invalidateMeasure) invalidateMeasure = false ;
}
} ());
* This source code was highlighted with Source Code Highlighter .
コードをコピーし、コンソールから実行して、サイトで降雪を取得します。