HTML 画布聚光灯效果 [英] HTML canvas spotlight effect

查看:20
本文介绍了HTML 画布聚光灯效果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有以下代码.

// Find out window height and width
wwidth = $(window).width();
wheight = $(window).height();

// Place Canvas over current Window 
$("body").append($("<canvas id='test' style='position:absolute; top:0; left:0;'></canvas>"));
var context = document.getElementById("test").getContext("2d");
context.canvas.width = wwidth;
context.canvas.height = wheight;

// Paint the canvas black.
context.fillStyle = '#000';
context.clearRect(0, 0, context.canvas.width, context.canvas.height);
context.fillRect(0, 0, context.canvas.width, context.canvas.height);

// On Mousemove, create "Flashlight" around the mouse, to see through the canvas
$(window).mousemove(function(event){
  x = event.pageX;
  y = event.pageY;
  radius = 50;
  context = document.getElementById("test").getContext("2d");

  // Paint the canvas black.  Instead it will draw it white?!
  //context.fillStyle = '#000';
  //context.clearRect(0, 0, context.canvas.width, context.canvas.height);
  //context.fillRect(0, 0, context.canvas.width, context.canvas.height);

  context.beginPath();
  radialGradient = context.createRadialGradient(x, y, 1, x, y, radius);
  radialGradient.addColorStop(0, 'rgba(255,255,255,1)');
  radialGradient.addColorStop(1, 'rgba(0,0,0,0)');

  context.globalCompositeOperation = "destination-out";

  context.fillStyle = radialGradient;
  context.arc(x, y, radius, 0, Math.PI*2, false);
  context.fill();
  context.closePath();
});

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>Test</div>

对 mousemove 产生以下效果:

which generates the following effect on mousemove:

如何在绘制聚光灯之前用黑色重新填充画布?我已经尝试过注释掉的代码块中的内容,但它把所有东西都涂成白色.

How do I refill the canvas with black before the spotlight is drawn? I have already tried with what is in the commented-out code block, but it paints everything white.

我不想在图像上产生这种效果.相反,我想将画布放在整个网页上.我还希望画布始终为黑色,鼠标在其位置上生成一个聚光灯,以查看画布下方的内容,就像您在图片中看到的那样,或者在将 div 放置在空 html 页面中的代码段中测试"在里面.

I dont want this effect over an image. Instead i would like to place the Canvas over the whole Webpage. ALso I want the Canvas to be always black and the mouse generates a Spotlight over its position, to see what is under the Canvas just as u can see in the picture, or in the Snippet where a div was placed in an empty html page with "Test" in it.

推荐答案

您可以使用合成来创建手电筒效果:

  • 清除画布
  • 创建径向渐变以用作显露.
  • 填充径向渐变.
  • 使用source-atop 合成来绘制背景图像.图像将仅显示在径向渐变内部.
  • 使用 destination-over 合成用黑色填充画布.黑色将填充现有径向渐变图像的后面".
  • 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.

这是示例代码和演示:

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; }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Move mouse to reveal image with "flashlight"</h4>
<canvas id="canvas" width=300 height=300></canvas>

如果您的聚光灯半径永远不会改变,这里有一个更快的方法:

速度是通过将聚光灯缓存到第二个画布然后...

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

  1. 在画布上绘制图像.
  2. 在画布上绘制聚光灯.
  3. 使用 fillRect 将聚光灯外的 4 个矩形涂黑.
  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.

示例代码和演示:

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; }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Move mouse to reveal image with "flashlight"</h4>
<canvas id="canvas" width=300 height=300></canvas>

这篇关于HTML 画布聚光灯效果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆