1

よくある質問だと思いますが、キャンバスにドットを表示するのに問題があります。私が最初に知りたいのは、このようにドットを描く方法です(拡大してください)。2つ目は、光源を中心にして、このドットのグリッドの各要素に影を描く方法です。

現時点で私が持っているもの

私のコードの一部:

context.fillStyle = "#ccc";

context.shadowColor = '#e92772';
context.shadowOffsetX = 15;
context.shadowOffsetY = 15;

while (--e >= 1) {
    x -= z;
    if(x < 0) {
        x = z*w;
        y -= z;
    }
    context.moveTo(x, y);
    context.fillRect( x, y, 1, 1 );
    outs = a[e];
}

また、「context.arc();」を使ってみたのですが、「context.fillRect();」だと思います。より簡単です。もう 1 つの瞬間、「while (--e >= 1)」の代わりに「while (--e >= 0)」を使用すると、上部にさらに 2 つのドットが表示されます。なんで?

いくつかの記事やチュートリアルを知っている場合は、それらへのリンクを教えてください。できればフレームワークを使用しないでください。ありがとう。

4

1 に答える 1

2

いくつかの三角法を使用して、光源で 3D ドットをシミュレートできます。

オンラインデモはこちら

これはあなたができる1つの方法であり、もちろん他にもあります(これが最初に思い浮かびました):

  • メインキャンバスにいくつかのドットでグリッドを描画します
  • オフスクリーン キャンバスに放射状グラデーションをレンダリングする
  • コンポジションモードを変更して、既存のピクセルに何かが描画されるようにします
  • 光源までの距離と角度を計算し、角度/距離でオフセットされた各グリッド ポイントにドットを描画します。

これを行うデモのコードを次に示します。

ドットでグリッドを描く

後で各ドットをグラデーションドットで塗りつぶすため、グリッドポイントを1つスキップします。そうしないと、隣接するドットが塗りつぶされます。

/// draw a grid of dots:
for (y = 0; y < ez.width; y += gridSize * 2) {
    for (x = 0; x < ez.height; x += gridSize * 2) {
        ctx.beginPath();
        ctx.arc(x + offset, y + offset, radius, 0, arcStop);
        ctx.closePath();
        ctx.fill();
    }
}

光の「反射」を作る

グラデーション ドットをオフスクリーン キャンバス ( dctx= dot-context ) に準備します。私はセットアップに easyCanvas を使用しており、中心点が既に計算されたオフスクリーン キャンバスを提供していますが、もちろんこれを手動でセットアップすることもできます。

grd = dctx.createRadialGradient(dot.centerX, dot.centerY, 0,
                                dot.centerX, dot.centerY, gridSize);
grd.addColorStop(0, '#fff');
grd.addColorStop(0.2, '#777'); // thighten up
grd.addColorStop(1, '#000');

dctx.fillStyle = grd;
dctx.fillRect(0, 0, gridSize, gridSize);

計算する

次に、すべての計算とオフセットを行います。

/// change composition mode
ctx.globalCompositeOperation = 'source-atop';

/// calc angle and distance to light source and draw each
/// dot gradient offset in relation to this
for (y = 0; y < ez.width; y += gridSize) {
    for (x = 0; x < ez.height; x += gridSize) {

        /// angle
        angle = Math.atan2(lightY - y, lightX - x);
        //if (angle < 0) angle += 2;

        /// distance
        dx = lightX - x;
        dy = lightY - y;
        dist = Math.sqrt(dx * dx + dy * dy);

        /// map distance to our max offset
        od = dist / maxLength * maxOffset * 2;
        if (od > maxOffset * 2) od = maxOffset * 2;

        /// now get new x and y position based on angle and offset
        offsetX = x + od * Math.cos(angle) - maxOffset * 0.5;
        offsetY = y + od * Math.sin(angle) - maxOffset * 0.5;

        /// draw the gradient dot at offset
        ctx.drawImage(dot.canvas, x + offsetX, y + offsetY);
    }
}

影については、既に描画されたピクセルの外側destination-overに描画する合成モードを使用しているときに、オフセットを逆にするだけです。

/// Shadow, same as offsetting light, but in opposite
/// direction and with a different composite mode
ctx.globalCompositeOperation = 'destination-over';

for (y = 0; y < ez.width; y += gridSize) {
    for (x = 0; x < ez.height; x += gridSize) {

        /// angle
        angle = Math.atan2(lightY - y, lightX - x);
        //if (angle < 0) angle += 2;

        /// distance
        dx = lightX - x;
        dy = lightY - y;
        dist = Math.sqrt(dx * dx + dy * dy);

        /// map distance to our max offset
        od = dist / maxLength * maxOffset * 2;
        if (od > maxOffset * 4) od = maxOffset * 4;

        /// now get new x and y position based on angle and offset
        offsetX = x - od * Math.cos(angle) + gridSize * 0.5;
        offsetY = y - od * Math.sin(angle) + gridSize * 0.5;

        ctx.beginPath();
        ctx.arc(x + offsetX, y + offsetY, radius, 0, arcStop);
        ctx.fill();

    }
}

もちろん、これはすべて 1 つのループ ペアに最適化できますが、概要を説明するためにコードを分けています。

追加

デモでは、マウス トラッキングを追加して、マウスが光源になり、マウスを動かしながらドット反射の変化を確認できるようにしました。最高のパフォーマンスを得るには、Chrome を使用してください。

必要に応じて、使用している値を縮小するか、大きなオフスクリーン キャンバスに描画し、それを使用drawImageしてメイン キャンバスに縮小します。

于 2013-08-09T16:23:57.347 に答える