34

私のプロジェクトでは、キャンバスを使用して別の同じサイズとパターン画像に1つの異なるカラー画像を実装する必要があり、画像は円形または長方形ではありません。すべてが波の形をしており、すべてのonclick機能に複数のグラフィックを表示するために単一のメイン背景画像に適用されます。

重なっている画像は、選択した別の色に変更する必要があります。私の質問キャンバスを使用して、キャンバスで描画される画像の色を変更できる方法はありますか、または常に異なる画像を使用してCSS / jQueryで適用する必要があります.

キャンバス イメージのマスキングとオーバーラップについて読みました。しかし、それは正方形や円形ではないため、私の画像では理解できません。最初に、単一の画像に複数の波形を描く方法を説明します。検索したことについてはわかりませんが、完璧な解決策を検索できませんでした。

私の必要性は、キャンバスに1つの波の画像を描画し、クリック機能からその色を変更し、背景画像で別のdivを設定するだけで、2つ以上のキャンバスが重なります。これは可能ですか?

(つまり、この機能は、車に複数のグラフィックを作成または設定するためのものであり、各グラフィック イメージをキャンバスに設定する必要があり、別のグラフィックを div と最初のキャンバスに重ねる必要があります)

4

2 に答える 2

59

現状の質問は、IMO が少し不明確です。クリッピングが必要なシナリオに適用できるより一般的な答えを与えるには、(少なくとも) 2 つのアプローチを使用できます。

方法 1 - コンポジット モードを使用してクリップする

合成モードは最も単純な方法ですが、クリッピング マスクを透明な背景 (通常は PNG) を持つ画像として事前に定義する必要があるため、柔軟性が最も低くなります。

画像のソリッド部分を使用して次に描画されるものを切り取るか、透明な領域を使用して塗りつぶすことができます。

これは、ソリッド パーツを使用して次に描画される形状/画像を切り取る方法です。

/// draw the shape we want to use for clipping
ctx1.drawImage(imgClip, 0, 0);

/// change composite mode to use that shape
ctx1.globalCompositeOperation = 'source-in';

/// draw the image to be clipped
ctx1.drawImage(img, 0, 0);

ここではglobalCompositeOperationが に変更されてsource-inいます。これは、ソース イメージ (デスティネーションの次に描画するイメージ) が既存のソリッド データ内に描画されることを意味します。透明な領域には何も描画されません。

クリッピング マスクが次のようになっている場合 (ネットからのランダムなフェアユース):

クリップマスク

そして、私たちのイメージは次のようになります:

メイン画像

結果は次のようになります。

合成画像

方法 2 - パスを使用してクリップする

クリッピングのパスを定義することもできます。必要に応じてパスを調整したり、アニメーション化したりできるため、これは非常に柔軟です。

注: Path を使用したクリッピングは現在、ブラウザーでは少し「壊れやすい」ため、ブラウザーは現時点でクリップをリセットできないため、クリップ パスを設定して使用する前と後にsave()使用することを検討する必要があります (デフォルトのクリップ = キャンバス全体);restore()restore

簡単なジグザグ パスを定義しましょう (これはあなたの場合は波になります)。

/// use save when using clip Path
ctx2.save();

ctx2.beginPath();
ctx2.moveTo(0, 20);
ctx2.lineTo(50,0);
/// ... more here - see demo
ctx2.lineTo(400, 20);
ctx2.lineTo(400, 100);
ctx2.lineTo(0, 100);
ctx2.closePath();

/// define this Path as clipping mask
ctx2.clip();

/// draw the image
ctx2.drawImage(img, 0, 0);

/// reset clip to default
ctx2.restore();

キャンバスに描画されたものを使用してクリッピング マスクを設定したのでclip、次に、その形状の内側に収まるようにクリッピングします (形状が開始した場所で終了できることを確認してください)。

パスのクリップ画像

于 2013-08-22T17:35:39.920 に答える
52

コンテキスト合成を使用して、画像の一部を置き換えることができます。

たとえば、この青いロゴが既に画像としてある場合:

ここに画像の説明を入力

ロゴの上部を紫色にしたい場合:

ここに画像の説明を入力

合成を使用して、画像の上部の色を変更できます。

まず、お気に入りの画像エディターを使用して、色を変更したくない部分をトリミングします。

残ったものはオーバーレイと呼ばれます。

画像のこのオーバーレイ部分は、プログラムで色を変更するものです。

ここに画像の説明を入力

このオーバーレイは、プログラムで任意の色に色を変更できます。

ここに画像の説明を入力ここに画像の説明を入力

オーバーレイがプログラムによってどのように再色付けされたか:

  1. 空のキャンバスにオーバーレイを描画します。
  2. 合成モードを「source-in」に設定します。
  3. 効果:既存のピクセルのみが置き換えられます。透明ピクセルは透明のままです。
  4. キャンバスを覆う任意の色の長方形を描画します
  5. (既存のオーバーレイのみが新しい色に置き換えられることに注意してください)

オーバーレイの色を変えてロゴを完成させる方法

  1. 合成モードを「destination-atop」に設定</li>
  2. 効果:透明なピクセルのみが置き換えられます。既存のピクセルは変更されません。
  3. オリジナルのロゴを描きます
  4. (既存の色付きオーバーレイは置き換えられないことに注意してください)

この「上にデスティネーション」合成効果は、「下に描画」と呼ばれることがあります。

このオーバーレイは、テクスチャに置き換えることもできます!

ここに画像の説明を入力

ここにコードとフィドルがあります: http://jsfiddle.net/m1erickson/bfUPr/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<style>
    body{ background-color: ivory; padding:20px; }
    #canvas{border:1px solid red;}
</style>

<script>
$(function(){

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");

    var truck,logo,overlay;
    var newColor="red";

    var imageURLs=[];
    var imagesOK=0;
    var imgs=[];
    imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/boxTruck.png");
    imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/TVlogoSmall.png");
    imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/TVlogoSmallOverlay.png");
    loadAllImages();

    function loadAllImages(){
        for (var i = 0; i < imageURLs.length; i++) {
          var img = new Image();
          imgs.push(img);
          img.onload = function(){ imagesOK++; imagesAllLoaded(); };
          img.src = imageURLs[i];
        }      
    }

    var imagesAllLoaded = function() {
      if (imagesOK==imageURLs.length ) {
         // all images are fully loaded an ready to use
         truck=imgs[0];
         logo=imgs[1];
         overlay=imgs[2];
         start();
      }
    };


    function start(){

        // save the context state
        ctx.save();

        // draw the overlay
        ctx.drawImage(overlay,150,35);

        // change composite mode to source-in
        // any new drawing will only overwrite existing pixels
        ctx.globalCompositeOperation="source-in";

        // draw a purple rectangle the size of the canvas
        // Only the overlay will become purple
        ctx.fillStyle=newColor;
        ctx.fillRect(0,0,canvas.width,canvas.height);

        // change the composite mode to destination-atop
        // any new drawing will not overwrite any existing pixels
        ctx.globalCompositeOperation="destination-atop";

        // draw the full logo
        // This will NOT overwrite any existing purple overlay pixels
        ctx.drawImage(logo,150,35);

        // draw the truck
        // This will NOT replace any existing pixels
        // The purple overlay will not be overwritten
        // The blue logo will not be overwritten
        ctx.drawImage(truck,0,0);

        // restore the context to it's original state
        ctx.restore();

    }


}); // end $(function(){});
</script>

</head>

<body>
    <canvas id="canvas" width=500 height=253></canvas>
</body>
</html>
于 2013-08-22T17:44:39.810 に答える