【问题标题】:How to create fading cursor trails on an image canvas?如何在图像画布上创建褪色光标轨迹?
【发布时间】:2019-07-21 17:00:06
【问题描述】:

我在图像画布上创建了一个光标轨迹,其中图像画布位于背景,光标轨迹位于图像画布顶部的第二个画布上。我目前面临的问题是我无法创建逐渐消失的轨迹。

我已经看到了有关如何使用 fillStyle 使其以纯背景淡化的技巧,但我不知道如何使淡化光标轨迹以图像为背景。

<!DOCTYPE html>
<html>
  <head>
    <style>
      .stack {
        position: relative;
      }

      .stack canvas {
        position: absolute;
        left: 0;
        top: 0;
      }

      .stack,
      #main_canvas {
        background-size: contain;
        width: 100%;
        margin: auto;
      }
    </style>
  </head>

  <body>
    <div class="stack">
      <canvas id="main_canvas"> main canvas</canvas>
    </div>

    <script>
      var SCREEN_WIDTH = window.innerWidth;
      var SCREEN_HEIGHT = window.innerHeight;

      var RADIUS = 70;

      var RADIUS_SCALE = 1;
      var RADIUS_SCALE_MIN = 1;
      var RADIUS_SCALE_MAX = 1.5;

      var QUANTITY = 25;

      var canvas;
      var canvas_bg;
      var context;
      var context_bg;
      var particles;
      var slider_image;

      var mouseX = SCREEN_WIDTH * 0.5;
      var mouseY = SCREEN_HEIGHT * 0.5;
      var mouseIsDown = false;

      var ind = 0;

      function init() {
        canvas = document.getElementById("main_canvas");
        canvas_bg = document.createElement("canvas"); //<canvas> predefined
        canvas.setAttribute("alt", "countless stars");

        if (canvas && canvas.getContext) {
          windowResizeHandler();

          //background canvas
          create_sliders();

          //main canvas for creating  mouse trails
          context = canvas.getContext("2d");

          // Register event listeners
          window.addEventListener("mousemove", documentMouseMoveHandler, false);
          window.addEventListener("mousedown", documentMouseDownHandler, false);
          window.addEventListener("mouseup", documentMouseUpHandler, false);
          document.addEventListener(
            "touchstart",
            documentTouchStartHandler,
            false
          );
          document.addEventListener(
            "touchmove",
            documentTouchMoveHandler,
            false
          );
          window.addEventListener("resize", windowResizeHandler, false);

          createParticles();
          setInterval(loop, 1000 / 60);
        }
      }

      function create_sliders() {
        slider_image = new Image();
        slider_image.src =
          "https://images.pexels.com/photos/956999/milky-way-starry-sky-night-sky-star-956999.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940";

        canvas_bg.width = canvas.width;
        canvas_bg.height = canvas.height;
        // insert into DOM on top:
        canvas.parentNode.insertBefore(canvas_bg, canvas);

        context_bg = canvas_bg.getContext("2d");
        context_bg.drawImage(slider_image, 0, 0, canvas.width, canvas.height);
      }

      function createParticles() {
        particles = [];

        for (var i = 0; i < QUANTITY; i++) {
          var particle = {
            size: 1,
            position: { x: mouseX, y: mouseY },
            offset: { x: 0, y: 0 },
            shift: { x: mouseX, y: mouseY },
            speed: 0.01 + Math.random() * 0.04,
            targetSize: 1,
            fillColor:
              "#" + ((Math.random() * 0x404040 + 0xaaaaaa) | 0).toString(16),
            orbit: RADIUS * 0.5 + RADIUS * 0.5 * Math.random()
          };
          particles.push(particle);
        }
      }

      function documentMouseMoveHandler(event) {
        mouseX = event.clientX - (window.innerWidth - SCREEN_WIDTH) * 0.5;
        mouseY = event.clientY - (window.innerHeight - SCREEN_HEIGHT) * 0.5;
      }

      function documentMouseDownHandler(event) {
        mouseIsDown = true;
      }

      function documentMouseUpHandler(event) {
        mouseIsDown = false;
      }

      function documentTouchStartHandler(event) {
        if (event.touches.length == 1) {
          event.preventDefault();

          mouseX =
            event.touches[0].pageX - (window.innerWidth - SCREEN_WIDTH) * 0.5;
          mouseY =
            event.touches[0].pageY - (window.innerHeight - SCREEN_HEIGHT) * 0.5;
        }
      }

      function documentTouchMoveHandler(event) {
        if (event.touches.length == 1) {
          event.preventDefault();

          mouseX =
            event.touches[0].pageX - (window.innerWidth - SCREEN_WIDTH) * 0.5;
          mouseY =
            event.touches[0].pageY - (window.innerHeight - SCREEN_HEIGHT) * 0.5;
        }
      }

      function windowResizeHandler() {
        SCREEN_WIDTH = window.innerWidth;
        SCREEN_HEIGHT = window.innerHeight;

        canvas.width = SCREEN_WIDTH;
        canvas.height = SCREEN_HEIGHT;
      }

      function loop() {
        if (mouseIsDown) {
          RADIUS_SCALE += (RADIUS_SCALE_MAX - RADIUS_SCALE) * 0.02;
        } else {
          RADIUS_SCALE -= (RADIUS_SCALE - RADIUS_SCALE_MIN) * 0.02;
        }

        RADIUS_SCALE = Math.min(RADIUS_SCALE, RADIUS_SCALE_MAX);

        // context.fillStyle = 'rgba(0,0,0,0.05)';
        context.fillStyle = "rgba(0, 0, 0, 0)";
        context.fillRect(0, 0, context.canvas.width, context.canvas.height);

        for (i = 0, len = particles.length; i < len; i++) {
          var particle = particles[i];

          var lp = { x: particle.position.x, y: particle.position.y };

          // Rotation
          particle.offset.x += particle.speed;
          particle.offset.y += particle.speed;

          // Follow mouse with some lag
          particle.shift.x += (mouseX - particle.shift.x) * particle.speed;
          particle.shift.y += (mouseY - particle.shift.y) * particle.speed;

          // Apply position
          particle.position.x =
            particle.shift.x +
            Math.cos(i + particle.offset.x) * (particle.orbit * RADIUS_SCALE);
          particle.position.y =
            particle.shift.y +
            Math.sin(i + particle.offset.y) * (particle.orbit * RADIUS_SCALE);

          // Limit to screen bounds
          particle.position.x = Math.max(
            Math.min(particle.position.x, SCREEN_WIDTH),
            0
          );
          particle.position.y = Math.max(
            Math.min(particle.position.y, SCREEN_HEIGHT),
            0
          );

          particle.size += (particle.targetSize - particle.size) * 0.05;

          if (Math.round(particle.size) == Math.round(particle.targetSize)) {
            particle.targetSize = 1 + Math.random() * 7;
          }

          if (particle.position) context.beginPath();
          context.fillStyle = particle.fillColor;
          context.strokeStyle = particle.fillColor;
          context.lineWidth = particle.size;
          context.moveTo(lp.x, lp.y);
          context.lineTo(particle.position.x, particle.position.y);
          context.stroke();
          context.arc(
            particle.position.x,
            particle.position.y,
            particle.size / 2,
            0,
            Math.PI * 2,
            true
          );
          context.fill();
        }
      }
      window.onload = init;
    </script>
  </body>
</html>

目前,较旧的小径不会消失,它正在创造一种更像是我不想要的绘画效果的东西。

【问题讨论】:

  • 我想你会发现这非常有用:Drawing Object Trails - p5.js Tutorial。尽管他使用的是 p5.js,但您可以轻松地将其转换为纯 javascript
  • 感谢您的参考 =) 我一定会去看看!

标签: javascript html html5-canvas


【解决方案1】:

淡出粒子的一种方法是将(当前透明的)drawRect 调用替换为 drawImage,在将粒子添加到当前帧之前,在每一帧上绘制背景图像的半透明副本:

  In your loop() function:

  // Instead of this:
  // context.fillStyle = "rgba(0, 0, 0, 0)";
  // context.fillRect(0, 0, context.canvas.width, context.canvas.height);

  // Do this:
  context.save();
  context.globalAlpha = 0.1;
  context.drawImage(slider_image, 0, 0, canvas.width, canvas.height);
  context.restore();

  for (i = 0, len = particles.length; i < len; i++) {
    ...

【讨论】:

  • 哇,这太棒了!你的代码就像一个魅力!非常感谢! =D
猜你喜欢
  • 2021-12-20
  • 1970-01-01
  • 2014-10-02
  • 1970-01-01
  • 2016-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多