特效 - 探照灯

使用组合绘制探照灯效果

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    html,body {
      width: 100%;
      height: 100%;
      overflow: hidden;
    }
    html {
      width: 100vw;
      height: 100vh;
    }
    body {
      background: url("https://img.xiaoyulive.top/img/date/20180913/005.jpg") no-repeat center;
      width: 100vw;
      min-height: 100%;
    }
  </style>
</head>
<body class="container">
  <canvas id="canvasOne" width="500" height="300"></canvas>
  <script>
    window.addEventListener('load', eventWindowLoaded, false);
    var Debugger = function () { };
    Debugger.log = function (message) {
      try {
        console.log(message);
      } catch (exception) {
        return;
      }
    }
    function eventWindowLoaded() {
      canvasApp();
    }
    function canvasApp() {
      Debugger.log('Drawing Canvas');
      var canvas = document.getElementById('canvasOne');
      var ctx = canvas.getContext('2d');
      var w = canvas.width = window.innerWidth;
      var h = canvas.height = window.innerHeight;
      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.addEventListener('mousemove', mouseMove, false);
      canvas.addEventListener('touchmove', mouseMove, false);
      function draw(cx, cy, radius) {
        ctx.save();
        ctx.clearRect(0, 0, w, h);
        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.fillStyle = '#000';
        ctx.fillRect(0, 0, w, h);
        ctx.globalCompositeOperation = 'destination-out';
        ctx.arc(cx, cy, radius, 0, Math.PI * 2, false);
        ctx.fillStyle = radialGradient;
        ctx.fill();
        ctx.restore();
      }
      function mouseMove(e) {
        e.preventDefault();
        e.stopPropagation();
        mouseX = parseInt(e.clientX - offsetX);
        mouseY = parseInt(e.clientY - offsetY);
        draw(mouseX, mouseY, 100);
      }
      draw(w / 2, h / 2, 100);
    }
  </script>
</body>
</html>

详见CodePen: Canvas: Spotlight Effect

使用剪裁制作探照灯特效

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    html {
      width: 100vw;
      height: 100vh;
      overflow: hidden;
    }
    body {
      /*background: url("https://img.xiaoyulive.top/img/date/20180913/005.jpg") no-repeat center;*/
      width: 100vw;
      min-height: 100%;
    }
  </style>
</head>
<body class="container">
  <canvas id="canvasOne" width="500" height="300"></canvas>
  <script>
    window.addEventListener('load', eventWindowLoaded, false);
    var Debugger = function () { };
    Debugger.log = function (message) {
      try {
        console.log(message);
      } catch (exception) {
        return;
      }
    }
    function eventWindowLoaded() {
      canvasApp();
    }
    function canvasApp() {
      Debugger.log('Drawing Canvas');
      var canvas = document.getElementById('canvasOne');
      var ctx = canvas.getContext('2d');
      var w = canvas.width = window.innerWidth;
      var h = canvas.height = window.innerHeight;
      var image = new Image();
      image.src = 'https://img.xiaoyulive.top/img/date/20180913/005.jpg';
      image.onload = function () {
        ctx.drawImage(image, 0, 0);
      }
      // 设置探照灯对象模型
      // @param (x, y): 表示圆心坐标
      // @param radius: 圆心半径
      // @param vx, vy: 水平和垂直方向的速度,通过他们控制速度大小
      var spotlight = {
        x: w / 2,
        y: h / 2,
        radius: 100,
        vx: Math.random() * 5 + 10,
        vy: Math.random() * 5 + 15
      };
      // 通过setInterval来更新模型的位置
      // 每40ms更新一次
      setInterval(function () {
        draw();
        update(w, h);
      }, 40);
      function draw() {
        ctx.clearRect(0, 0, w, h);
        ctx.save();
        ctx.beginPath();
        ctx.fillStyle = '#000';
        ctx.fillRect(0, 0, w, h);
        ctx.fill();
        ctx.save();
        ctx.beginPath();
        ctx.arc(spotlight.x, spotlight.y, spotlight.radius, 0, Math.PI * 2, false);
        ctx.fill();
        // 将上面的区域作为剪辑区域
        ctx.clip();
        // 由于使用clip(),画布背景图片会出现在clip()区域内
        ctx.drawImage(image, 0, 0);
        ctx.restore();
      }
      // 小球运动模型
      function update(w, h) {
        spotlight.x += spotlight.vx;
        spotlight.y += spotlight.vy;
        // 如果小球超出了左边的边界,则速度反向,x 点变为圆的半径
        if (spotlight.x - spotlight.radius <= 0) {
          spotlight.vx = -spotlight.vx;
          spotlight.x = spotlight.radius;
        }
        // 如果小球超出了右边的边界,则速度反向,x点变为画布宽度-圆的半径
        if (spotlight.x + spotlight.radius >= w) {
          spotlight.vx = -spotlight.vx;
          spotlight.x = w - spotlight.radius;
        }
        // Y轴方向处理
        if (spotlight.y - spotlight.radius <= 0) {
          spotlight.vy = -spotlight.vy;
          spotlight.y = spotlight.radius;
        }
        if (spotlight.y + spotlight.radius >= h) {
          spotlight.vy = -spotlight.vy;
          spotlight.y = h - spotlight.radius;
        }
      }
    }
  </script>
</body>
</html>

详见CodePen: Canvas: Spotlight Effect

MIT Licensed | Copyright © 2018-present 滇ICP备16006294号

Design by Quanzaiyu | Power by VuePress