Tunnel mouse trail/follow

@buggles - I am 99% close to getting this effect finished:

The full code is here:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Zooming Tunnel</title>

  <style>
    body {
      padding: 100px;
    }

    h1 {
      font-family: sans-serif;
      color: #333;
    }

    #myCanvas {
      width: 800px;
      height: 400px;
      border: 5px solid black;
      border-radius: 10px;
    }
  </style>
</head>

<body>
  <h1>Zooming Tunnel</h1>
  <canvas id="myCanvas">

  </canvas>

  <script>
    let canvasElement = document.querySelector("#myCanvas");
    let context = canvasElement.getContext("2d");

    let mouseX = 0;
    let mouseY = 0;

    normalizeCanvasSize(canvasElement);

    canvasElement.addEventListener("mousemove", mouseMoving, false);

    function mouseMoving(e) {
      let mousePosition = getPosition(canvasElement);
      mouseX = e.clientX - mousePosition.x;
      mouseY = e.clientY - mousePosition.y;
    }

    let rectangles = [];

    class Rectangle {
      constructor(context, color, delay) {
        this.context = context;
        this.step = 0;
        this.color = color;
        this.rectangleWidth = 10;
        this.rectangleHeight = 50;
        this.running = true;
      }

      draw(xPos, yPos) {
        if (this.running) {
          this.step += 5;

          if (this.step > 2000) {
            this.stop();
          }

          // the rectangle
          this.context.beginPath();

          this.context.rect(xPos - (this.rectangleWidth / 2) - this.step / 2, yPos - (this.rectangleHeight / 2) - this.step / 2, this.rectangleWidth + this.step, this.rectangleHeight + this.step);

          this.context.fillStyle = this.color;
          this.context.fill();
        }
      }

      stop() {
        this.running = false;
      }
    }

    function animate() {

      context.clearRect(0, 0, canvasElement.width, canvasElement.height);

      for (let i = 0; i < rectangles.length; i++) {
        let r = rectangles[i];
        r.draw(mouseX, mouseY);
      }

      requestAnimationFrame(animate);
    }

    let count = 0;
    //let colors = ["#FFAF87", "#FF8E72", "#ED6A5E", "#4CE0B3", "#377771", "#0D0221", "#0F084B", "#26408B"];

    let h_range = [0, 45];
    let s_range = [70, 90];
    let l_range = [0, 90];
    let a_range = [1, 1];

    function addRectangle() {
      let delay = 0;

      //let index = count % colors.length;
      let color = getRandomColor(h_range, s_range, l_range, a_range);
      console.log(color);

      let myRectangle = new Rectangle(context, color.hslaValue, delay);
      rectangles.push(myRectangle);

      count++;
    }

    function setup() {
      setInterval(addRectangle, 200);

      requestAnimationFrame(animate);
    }
    setup();



    function normalizeCanvasSize(canvas) {
      // look up the size the canvas is being displayed
      let rect = canvas.getBoundingClientRect();

      // increase the actual size of our canvas
      canvas.width = rect.width * devicePixelRatio;
      canvas.height = rect.height * devicePixelRatio;

      // ensure all drawing operations are scaled
      context.scale(devicePixelRatio, devicePixelRatio);

      // scale everything down using CSS
      canvas.style.width = rect.width + 'px';
      canvas.style.height = rect.height + 'px';
    }

    // Helper function to get an element's exact position
    function getPosition(el) {
      let xPos = 0;
      let yPos = 0;

      while (el) {
        if (el.tagName == "BODY") {
          // deal with browser quirks with body/window/document and page scroll
          let xScroll = el.scrollLeft || document.documentElement.scrollLeft;
          let yScroll = el.scrollTop || document.documentElement.scrollTop;

          xPos += (el.offsetLeft - xScroll + el.clientLeft);
          yPos += (el.offsetTop - yScroll + el.clientTop);
        } else {
          // for all other non-BODY elements
          xPos += (el.offsetLeft - el.scrollLeft + el.clientLeft);
          yPos += (el.offsetTop - el.scrollTop + el.clientTop);
        }

        el = el.offsetParent;
      }
      return {
        x: xPos,
        y: yPos
      };
    }

    function getRandomColor(h, s, l, a) {
      let hue = getRandomNumber(h[0], h[1]);
      let saturation = getRandomNumber(s[0], s[1]);
      let lightness = getRandomNumber(l[0], l[1]);
      let alpha = getRandomNumber(a[0] * 100, a[1] * 100) / 100;

      return {
        h: hue,
        s: saturation,
        l: lightness,
        a: alpha,
        hslaValue: getHSLAColor(hue, saturation, lightness, alpha)
      }
    }

    function getRandomNumber(low, high) {
      let r = Math.floor(Math.random() * (high - low + 1)) + low;
      return r;
    }

    function getHSLAColor(h, s, l, a) {
      return `hsl(${h}, ${s}%, ${l}%, ${a})`;
    }
  </script>
</body>

</html>

I am not happy about the infinitely growing rectangles array, but that is something I will deal with later. The code isn’t commenting, so do let me know if I can clarify anything there.

Cheers,
Kirupa :train2:

1 Like