HTML canvas spotlight effect

前端 未结 3 1065
遇见更好的自我
遇见更好的自我 2020-12-03 23:56

Let\'s say I have the following code.

3条回答
  •  北海茫月
    2020-12-04 00:23

    You can use compositing to create your flashlight effect:

    • Clear the canvas
    • Create a radial gradient to use as a reveal.
    • Fill the radial gradient.
    • Use source-atop compositing to draw the background image. The image will display only inside the radial gradient.
    • Use destination-over compositing to fill the canvas with black. The black will fill "behind" the existing radial-gradient-image.

    Here's example code and a Demo:

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    var cw=canvas.width;
    var ch=canvas.height;
    function reOffset(){
      var BB=canvas.getBoundingClientRect();
      offsetX=BB.left;
      offsetY=BB.top;        
    }
    var offsetX,offsetY;
    reOffset();
    window.onscroll=function(e){ reOffset(); }
    window.onresize=function(e){ reOffset(); }
    
    $("#canvas").mousemove(function(e){handleMouseMove(e);});
    
    var radius=30;
    
    var img=new Image();
    img.onload=function(){
      draw(150,150,30);
    }
    img.src='https://dl.dropboxusercontent.com/u/139992952/multple/annotateMe.jpg'
    
    
    function draw(cx,cy,radius){
      ctx.save();
      ctx.clearRect(0,0,cw,ch);
      var radialGradient = ctx.createRadialGradient(cx, cy, 1, cx, cy, radius);
      radialGradient.addColorStop(0, 'rgba(0,0,0,1)');
      radialGradient.addColorStop(.65, 'rgba(0,0,0,1)');
      radialGradient.addColorStop(1, 'rgba(0,0,0,0)');
      ctx.beginPath();
      ctx.arc(cx,cy,radius,0,Math.PI*2);
      ctx.fillStyle=radialGradient;
      ctx.fill();
      ctx.globalCompositeOperation='source-atop';
      ctx.drawImage(img,0,0);
      ctx.globalCompositeOperation='destination-over';
      ctx.fillStyle='black';
      ctx.fillRect(0,0,cw,ch);
      ctx.restore();
    }
    
    
    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);
    
      draw(mouseX,mouseY,30);
    
    }
    body{ background-color: ivory; }
    #canvas{border:1px solid red; }
    
    

    Move mouse to reveal image with "flashlight"

    If your spotlight radius will never change, here's a much faster method:

    The speed is gained by caching the spotlight to a second canvas and then...

    1. Draw the image on the canvas.
    2. Draw the spotlight on the canvas.
    3. Use fillRect to black out the 4 rectangles outside the spotlight.

    Example code and a Demo:

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    var cw=canvas.width;
    var ch=canvas.height;
    function reOffset(){
      var BB=canvas.getBoundingClientRect();
      offsetX=BB.left;
      offsetY=BB.top;        
    }
    var offsetX,offsetY;
    reOffset();
    window.onscroll=function(e){ reOffset(); }
    window.onresize=function(e){ reOffset(); }
    
    var radius=50;
    
    var cover=document.createElement('canvas');
    var cctx=cover.getContext('2d');
    var size=radius*2+10;
    cover.width=size;
    cover.height=size;
    cctx.fillRect(0,0,size,size);
    var radialGradient = cctx.createRadialGradient(size/2, size/2, 1, size/2, size/2, radius);
    radialGradient.addColorStop(0, 'rgba(0,0,0,1)');
    radialGradient.addColorStop(.65, 'rgba(0,0,0,1)');
    radialGradient.addColorStop(1, 'rgba(0,0,0,0)');
    cctx.beginPath();
    cctx.arc(size/2,size/2,size/2,0,Math.PI*2);
    cctx.fillStyle=radialGradient;
    cctx.globalCompositeOperation='destination-out';
    cctx.fill();
    
    var img=new Image();
    img.onload=function(){
      $("#canvas").mousemove(function(e){handleMouseMove(e);});
      ctx.fillRect(0,0,cw,ch);
    }
    img.src='https://dl.dropboxusercontent.com/u/139992952/multple/annotateMe.jpg'
    
    
    function drawCover(cx,cy){
      var s=size/2;
      ctx.clearRect(0,0,cw,ch);
      ctx.drawImage(img,0,0);
      ctx.drawImage(cover,cx-size/2,cy-size/2);
      ctx.fillStyle='black';
      ctx.fillRect(0,0,cx-s,ch);
      ctx.fillRect(0,0,cw,cy-s);
      ctx.fillRect(cx+s,0,cw-cx,ch);
      ctx.fillRect(0,cy+s,cw,ch-cy);
    }
    
    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);
    
      drawCover(mouseX,mouseY);
    }
    body{ background-color: ivory; }
    #canvas{border:1px solid red; }
    
    

    Move mouse to reveal image with "flashlight"

提交回复
热议问题