javascript
  • html
  • canvas
  • 2015-09-07 119 views 3 likes 
    3

    假设我有以下代码。HTML canvas聚光灯效果

    // 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>

    生成鼠标移动上产生以下影响:

    Here you can see the above scripted effect

    如何补充聚光灯前用黑色画布绘制?我已经尝试了注释代码块中的内容,但它将所有内容都绘制成白色。

    编辑:我不想在图像上产生这种效果。相反,我想将Canvas放置在整个网页上。此外,我希望Canvas始终为黑色,并且鼠标在其位置上生成Spotlight,以查看Canvas下面的内容,就像您可以在图片中看到的一样,或者在Snippet中将div放在空白的html页面中“测试”中。

    +2

    你看过http://stackoverflow.com/questions/2142535/how-to-clear-the-canvas-for-redrawing?这里 –

    +1

    几个问题。我们无法重现你的例子,例如'giveCanvasContext'不是天真的功能。注意用黑色填充画布,你不需要'beginPath'或'endPath'。 –

    +0

    @ CI_是的,我做到了,但它似乎像画布将绘制白色,而不是与黑色再次填补了.. – TeaTime

    回答

    3

    可以使用合成来创建你的手电筒效应:

    • 清除画布
    • 创建一个径向渐变以用作揭示。
    • 填充径向渐变。使用source-atop合成来绘制背景图像。图像将仅在径向渐变内显示。
    • 使用destination-over合成填充黑色画布。黑色将填充现有径向梯度图像“后面”。

    enter image description hereenter image description here

    这里的示例代码和演示:

    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>

    如果你的焦点半径不会改变,这里有一个更快的方法:

    速度由缓存聚光灯到第二画布然​​后获得...

    1. 画出画布上的图像。
    2. 在画布上绘制聚光灯。
    3. 使用fillRect将聚光灯外的4个矩形遮光。

    实施例的代码和一个演示:

    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>

    0

    此代码的工作对我来说:

    x = event.pageX; 
    y = event.pageY; 
    radius = 10; 
    context = canvas.getContext("2d"); 
    
    context.fillStyle = "black"; 
    context.fillRect(0, 0, context.canvas.width, context.canvas.height); 
    
    context.beginPath(); 
    var radialGradient= context.createRadialGradient(x,y,1,x,y,radius); 
    radialGradient.addColorStop(0,"rgba(255,255,255,1"); 
    radialGradient.addColorStop(1,"rgba(0,0,0,1)"); 
    //context.globalCompositeOperation = "destination-out"; 
    context.fillStyle = radialGradient; 
    context.arc(x, y, radius, 0, Math.PI*2, false); 
    context.fill(); 
    context.closePath(); 
    

    看来,这条线被搞乱它context.globalCompositeOperation = "destination-out";

    也有无意义线在你的代码等之后填充矩形并填充()函数之前beginnig路径灌装通道

    +0

    此代码使聚光灯效果不错,但它不会实际显示什么是我想要的帆布下 – TeaTime

    1

    可以通过直接在图像上定位画布实现聚光灯效果。使画布大小与图像相同,合成操作设置为xor,这样在同一个地方画两个黑像素相互抵消。

    context.globalCompositeOperation = 'xor'; 
    

    现在,您可以将画布涂成黑色并在鼠标光标周围填充黑色圆圈。结果是在黑色表面出现一个洞,显示下面的图像。

    // Paint the canvas black. 
    context.fillStyle = '#000'; 
    context.clearRect(0, 0, width, height); 
    context.fillRect(0, 0, width, height); 
    // Paint a black circle around x, y. 
    context.beginPath(); 
    context.arc(x, y, spotlightRadius, 0, 2 * Math.PI); 
    context.fillStyle = '#000'; 
    context.fill(); 
    // With xor compositing, the result is a circular hole. 
    

    使聚光灯与模糊的边缘,限定中心鼠标位置的径向梯度和填充在其周围的正方形。

    var gradient = context.createRadialGradient(x, y, 0, x, y, spotlightRadius); 
    gradient.addColorStop(0, 'rgba(0, 0, 0, 1)'); 
    gradient.addColorStop(0.9, 'rgba(0, 0, 0, 1)'); 
    gradient.addColorStop(1, 'rgba(0, 0, 0, 0)'); 
    context.fillStyle = gradient; 
    context.fillRect(x - spotlightRadius, y - spotlightRadius, 
           2 * spotlightRadius, 2 * spotlightRadius); 
    

    以下代码片段演示了使用纯JavaScript的两种方法。若要从一个清晰的边聚光灯变成一个模糊的边缘聚光灯,点击上图中的复选框。

    function getOffset(element, ancestor) { 
     
        var left = 0, 
     
         top = 0; 
     
        while (element != ancestor) { 
     
        left += element.offsetLeft; 
     
        top += element.offsetTop; 
     
        element = element.parentNode; 
     
        } 
     
        return { left: left, top: top }; 
     
    } 
     
    
     
    function getMousePosition(event) { 
     
        event = event || window.event; 
     
        if (event.pageX !== undefined) { 
     
        return { x: event.pageX, y: event.pageY }; 
     
        } 
     
        return { 
     
        x: event.clientX + document.body.scrollLeft + 
     
         document.documentElement.scrollLeft, 
     
        y: event.clientY + document.body.scrollTop + 
     
         document.documentElement.scrollTop 
     
        }; 
     
    } 
     
    
     
    window.onload = function() { 
     
        var spotlightRadius = 60, 
     
         container = document.getElementById('container'), 
     
         canvas = document.createElement('canvas'), 
     
         image = container.getElementsByTagName('img')[0], 
     
         width = canvas.width = image.width, 
     
         height = canvas.height = image.height, 
     
         context = canvas.getContext('2d'); 
     
        context.globalCompositeOperation = 'xor'; 
     
        container.insertBefore(canvas, image.nextSibling); 
     
        container.style.width = width + 'px'; 
     
        container.style.height = height + 'px'; 
     
        var offset = getOffset(canvas, document.body); 
     
         clear = function() { 
     
         context.fillStyle = '#000'; 
     
         context.clearRect(0, 0, width, height); 
     
         context.fillRect(0, 0, width, height); 
     
         }; 
     
        clear(); 
     
        image.style.visibility = 'visible'; 
     
        canvas.onmouseout = clear; 
     
        canvas.onmouseover = canvas.onmousemove = function (event) { 
     
        var mouse = getMousePosition(event), 
     
         x = mouse.x - offset.left, 
     
         y = mouse.y - offset.top; 
     
        clear(); 
     
        if (document.getElementById('blurry').checked) { 
     
         var gradient = context.createRadialGradient(x, y, 0, x, y, spotlightRadius); 
     
         gradient.addColorStop(0, 'rgba(0, 0, 0, 1)'); 
     
         gradient.addColorStop(0.875, 'rgba(0, 0, 0, 1)'); 
     
         gradient.addColorStop(1, 'rgba(0, 0, 0, 0)'); 
     
         context.fillStyle = gradient; 
     
         context.fillRect(x - spotlightRadius, y - spotlightRadius, 
     
             2 * spotlightRadius, 2 * spotlightRadius); 
     
        } else { 
     
         context.beginPath(); 
     
         context.arc(x, y, spotlightRadius, 0, 2 * Math.PI); 
     
         context.fillStyle = '#000'; 
     
         context.fill(); 
     
        } 
     
        }; 
     
    };
    * { 
     
        margin: 0; 
     
        padding: 0; 
     
    } 
     
    .control { 
     
        font-family: sans-serif; 
     
        font-size: 15px; 
     
        padding: 10px; 
     
    } 
     
    #container { 
     
        position: relative; 
     
    } 
     
    #container img, #container canvas { 
     
        position: absolute; 
     
        left: 0; 
     
        top: 0; 
     
    } 
     
    #container img { 
     
        visibility: hidden; 
     
    } 
     
    #container canvas { 
     
        cursor: none; 
     
    }
    <p class="control"> 
     
        <input type="checkbox" id="blurry" /> blurry edges 
     
    </p> 
     
    
     
    <div id="container"> 
     
        <img src="https://dl.dropboxusercontent.com/u/139992952/multple/annotateMe.jpg" /> 
     
    </div>

    相关问题