如何为 canvas 形状设置圆形内阴影?
How to have a circular inner shadow for canvas shape?
在我的 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();
,此设置将起作用,但它会使整个 canvas 崩溃。
知道要为这个圆圈添加内阴影吗?
尝试在提供框架的弧之前绘制提供阴影的弧。保存 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();
您需要调整圆弧的大小、颜色和线宽以获得您想要的效果。
如果在诸如 mousemove 之类的繁忙处理程序中执行 .clip 会使浏览器崩溃,您可以 pre-build 在您的应用程序开始时使用内部阴影的圆圈一次,然后重新使用该 pre-built 圆圈对性能影响不大。
以下是如何创建一个 in-memory canvas 包含带内阴影的圆圈。是的,它使用.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 事件中绘制那个 pre-built 圆圈并不是很昂贵。
这是示例代码和演示:
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/Whosebug/tiger.png />
<canvas id="canvas" width=512 height=512></canvas>
</div>
我刚刚针对这种情况创建了 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();
});
在我的 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();
,此设置将起作用,但它会使整个 canvas 崩溃。
知道要为这个圆圈添加内阴影吗?
尝试在提供框架的弧之前绘制提供阴影的弧。保存 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();
您需要调整圆弧的大小、颜色和线宽以获得您想要的效果。
如果在诸如 mousemove 之类的繁忙处理程序中执行 .clip 会使浏览器崩溃,您可以 pre-build 在您的应用程序开始时使用内部阴影的圆圈一次,然后重新使用该 pre-built 圆圈对性能影响不大。
以下是如何创建一个 in-memory canvas 包含带内阴影的圆圈。是的,它使用.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 事件中绘制那个 pre-built 圆圈并不是很昂贵。
这是示例代码和演示:
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/Whosebug/tiger.png />
<canvas id="canvas" width=512 height=512></canvas>
</div>
我刚刚针对这种情况创建了 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();
});