如何为帆布形状设置圆形内阴影?

时间:2015-01-11 20:02:48

标签: javascript css canvas html5-canvas

在我的画布中,我有一个随光标移动的圆形。 我试图给它一个内在的阴影,但它不起作用。

以下是代码和演示:JSFIDDLE

function writeMessage(canvas, message, x, y) {
    var context = canvas.getContext('2d');
    context.clearRect(0, 0, canvas.width, canvas.height);

    var pattern = context.createPattern(imageResized, 'no-repeat'); //Use imageResized, not imageObj.
    context.fillStyle = pattern;
    context.fill();

    context.font = '28pt Calibri';
    context.fillStyle = 'white';
    //context.fillText(message, x, y);
    context.beginPath();
    context.arc(x, y, 50, 0, 2 * Math.PI);
    context.stroke();


    context.beginPath();
    context.lineWidth = 5;
    context.shadowColor = 'black';
    context.strokeStyle = "rgba(0,0,0,1)";
    context.shadowBlur = 15;
    context.shadowOffsetX = 0;
    context.shadowOffsetY = 0;
    context.arc(x, y, 50, 0, 2 * Math.PI, false);
    context.stroke();
    context.restore();

}

我注意到如果我添加context.clip();,这个设置会起作用但是它会使整个画布崩溃。

想知道这个圈子有内在阴影吗?

3 个答案:

答案 0 :(得分:2)

尝试绘制弧,以便在提供帧的弧之前提供阴影。在beginPath之前保存上下文状态,并在阴影弧的中风后恢复它。您需要使阴影圆弧半径小于框架圆弧,以便阴影的外边缘被框架圆弧的笔划覆盖。阴影弧外部的外部阴影仍然被绘制,但被框架弧覆盖。

示例:

context.save();
context.beginPath();
context.lineWidth = 6;
context.shadowColor = 'black';
context.strokeStyle = "rgba(0,0,0,1)";
context.shadowBlur = 15;
context.shadowOffsetX = 0;
context.shadowOffsetY = 0;
context.arc(x, y, 47, 0, 2 * Math.PI, false);
context.stroke();
context.restore();

context.save();
context.beginPath();
context.lineWidth = 6;
context.arc(x, y, 50, 0, 2 * Math.PI);
context.stroke();
context.restore();

您需要调整弧的大小,颜色和线宽以获得所需的效果。

答案 1 :(得分:2)

enter image description here

如果在像mousemove这样繁忙的处理程序中执行.clip会导致浏览器崩溃,您可以在应用程序开始时使用内部阴影预先构建一个圆圈,然后重复使用预先构建的圆圈,而不会影响性能。

以下是如何创建包含内部阴影圆的内存中画布。是的,它使用.clip,但它只在应用程序的开头使用它一次。

var PI2=Math.PI*2;
var cut=document.createElement('canvas');
var cutCtx=cut.getContext('2d');
cut.width=100;
cut.height=100;
cutCtx.arc(50,50,50,0,Math.PI*2);
cutCtx.closePath();
cutCtx.clip();
cutCtx.shadowColor='black'
cutCtx.shadowBlur=15;
for(var i=0;i<15;i++){
    cutCtx.stroke();
}

然后在mousemove事件中绘制预先建立的圆圈并不是非常昂贵。

这是示例代码和演示:

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var scrollX=$canvas.scrollLeft();
var scrollY=$canvas.scrollTop();

var PI2=Math.PI*2;
var cut=document.createElement('canvas');
var cutCtx=cut.getContext('2d');
cut.width=100;
cut.height=100;
cutCtx.arc(50,50,50,0,Math.PI*2);
cutCtx.closePath();
cutCtx.clip();
cutCtx.shadowColor='black'
cutCtx.shadowBlur=15;
for(var i=0;i<15;i++){
  cutCtx.stroke();
}

ctx.fillStyle='white';
ctx.fillRect(0,0,cw,ch);

$("#canvas").mousemove(function(e){handleMouseMove(e);});


function applyCut(mx,my){
  // hide the background image by whiteing-out the canvas
  ctx.fillRect(0,0,cw,ch);

  // use compositing to "erase" a circle under the mouse
  ctx.globalCompositeOperation='destination-out';
  ctx.beginPath();
  ctx.arc(mx,my,50,0,PI2);
  ctx.closePath();
  ctx.fill();

  // draw the pre-built circle shadow under the mouse
  ctx.globalCompositeOperation='source-over';
  // Hint: the in-memory canvas can be an image source for
  // your on-screen canvas
  ctx.drawImage(cut,mx-50,my-50);
}


function handleMouseMove(e){
  // tell the browser we're handling this event
  e.preventDefault();
  e.stopPropagation();

  mouseX=parseInt(e.clientX-offsetX);
  mouseY=parseInt(e.clientY-offsetY);

  applyCut(mouseX,mouseY);

}
body{ background-color: ivory; }
#wrapper{position:relative;}
#bk,#canvas{position:absolute;}
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Move the mouse to reveal the image underneath</h4>
<div id=wrapper>
  <img id=bk src=https://dl.dropboxusercontent.com/u/139992952/stackoverflow/tiger.png />
  <canvas id="canvas" width=512 height=512></canvas>
</div>

答案 2 :(得分:0)

我刚刚为这种情况创建了Inset.js!

Inset.js

只需要设置ctx.shadowInset = true;

例如:http://codepen.io/patlillis/pen/RpEoKE

var ctx = canvas.getContext("2d");
var w = canvas.width = window.innerWidth;
var h = canvas.height = window.innerHeight;

// Set up circle styles.
ctx.shadowInset = true;
ctx.shadowBlur = 15;
ctx.shadowColor = 'black';
ctx.shadowOffsetX = 5;
ctx.shadowOffsetY = 5;
ctx.fillStyle = 'red';

// Set up mouse listener.
document.addEventListener('mousemove', function(e) {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.beginPath();
    ctx.arc(e.clientX, e.clientY, 30, 0, 2 * Math.PI);
    ctx.fill();
});

Inset circle demo