2017年7月更新
この回答が与えられたので、新しいブラウザで利用できる新しいオプション、コンテキストのフィルタプロパティがあります。現在、すべてのブラウザがサポートしているわけではないことに注意してください。
ブラウザーの場合、次のように一時的なキャンバスを削除するだけでなく、コードを削減できます。
var ctx = demo.getContext('2d');
ctx.fillStyle = '#f90';
ctx.fillRect(0, 0, demo.width, demo.height);
clipArc(ctx, 200, 200, 150, 40);
function clipArc(ctx, x, y, r, f) {
ctx.globalCompositeOperation = 'destination-out';
ctx.filter = "blur(25px)"; // "feather"
ctx.beginPath();
ctx.arc(x, y, r, 0, 2 * Math.PI);
ctx.fill();
// reset comp. mode and filter
ctx.globalCompositeOperation = 'destination-out';
ctx.filter = "none";
}
body {background:#07c}
<canvas id="demo" width=400 height=400></canvas>
古い答え
技術
これは、次の手順を組み合わせることで実現できます。
- オフスクリーン キャンバスを使用する
- シャドー機能を使う(隠し味)
- 複合モードを使用する
ぼやけた影を利用してブラウザ内部で羽を作ってもらう、というのがコンセプトです。これは、JavaScript でのぼかしよりもはるかに高速です。あらゆるオブジェクトの影を作成できるため、複雑なぼかしマスクを作成できます。
オフスクリーン キャンバスは、影だけを描画するために使用されます。これを実現するには、実際の形状をキャンバスの外に移動し、それに応じて影をオフセットします。その結果、実際の形状は「見えない」一方で、画面外のキャンバスに影が描画されます。
これでシェイプのぼかしバージョンができたので、それを合成モードのマスクとして使用できます。destination-out
影が描かれる場所をクリートするかdestination-in
、マスクを反転するかを選択します。
例
すべてのステップを実行するラッパー関数を作成しましょう
オンラインデモはこちら
function clipArc(ctx, x, y, r, f) { /// context, x, y, radius, feather size
/// create off-screen temporary canvas where we draw in the shadow
var temp = document.createElement('canvas'),
tx = temp.getContext('2d');
temp.width = ctx.canvas.width;
temp.height = ctx.canvas.height;
/// offset the context so shape itself is drawn outside canvas
tx.translate(-temp.width, 0);
/// offset the shadow to compensate, draws shadow only on canvas
tx.shadowOffsetX = temp.width;
tx.shadowOffsetY = 0;
/// black so alpha gets solid
tx.shadowColor = '#000';
/// "feather"
tx.shadowBlur = f;
/// draw the arc, only the shadow will be inside the context
tx.beginPath();
tx.arc(x, y, r, 0, 2 * Math.PI);
tx.closePath();
tx.fill();
/// now punch a hole in main canvas with the blurred shadow
ctx.save();
ctx.globalCompositeOperation = 'destination-out';
ctx.drawImage(temp, 0, 0);
ctx.restore();
}
それだけです。
利用方法
clipArc(context, centerX, centerY, radius, featherSize);
デモの背景あり(フィドルを参照):
ctx.fillStyle = '#ffa';
ctx.fillRect(0, 0, demo.width, demo.height);
clipArc(ctx, 200, 200, 150, 40);
結果:
センターをそのまま維持したい場合は、コンポジットモードを に置き換えてくださいdestination-in
。
逆フェザーマスクのデモ