【问题标题】:How to have a circular inner shadow for canvas shape?如何为画布形状设置圆形内阴影?
【发布时间】:2017-03-31 12:25:28
【问题描述】:

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

这里是代码和演示: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();,此设置将起作用,但它会使整个画布崩溃。

有没有办法为这个圆圈设置一个内阴影?

【问题讨论】:

    标签: javascript css canvas html5-canvas


    【解决方案1】:

    尝试在提供框架的弧之前绘制提供阴影的弧。保存 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();
    

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

    【讨论】:

      【解决方案2】:

      如果在诸如 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>

      【讨论】:

        【解决方案3】:

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

        插图.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();
        });
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-09-14
          • 1970-01-01
          • 2011-07-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多