Skip to main content

Creating random fireflies with SnapSVG

··3 mins

You’ll need to get the SnapSVG library first. Create a container for the fireflies to be appended to, and make sure it’s visible with it’s own height and width. There’s a CodePen if you want to see this in action.

I used to have this on my homepage, but now it’s here.

    (function () {
      'use strict';

      var container = document.querySelector('#container'),
          width     = container.offsetWidth,
          height    = container.offsetHeight,
          svg       = Snap(width * 1.15, height * 1.15),
          svgWidth  = parseInt(svg.node.getAttribute('width')),
          svgHeight = parseInt(svg.node.getAttribute('height'));

      var MAX_FIREFLIES       = 35,
          FIREFLY_SPEED       = 15000,
          FIREFLY_BLINK_SPEED = 4000,
          // Each of my SVG paths are 275px x 275px
          BASE_PATH_WIDTH     = 275;

      container.appendChild(svg.node);

      function getRandomInt(min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
      }

      function FireFly(){
        this.group = generateGroup();
        this.path = this.group[0];
        this.circle = this.group[1];
      }

      // Translates to the left and down from the top, then randomly rotates
      function generateTransform(){
        var leftPosition = (svgWidth - BASE_PATH_WIDTH) / 2,
            topPosition  = (svgHeight - BASE_PATH_WIDTH) / 2;
        return 't' + leftPosition + ',' + topPosition + ',r' + getRandomInt(1, 359);
      }

      // Creates a path and circle. Puts the circle at the
      // beginning of the path, and then groups the path and circle,
      // transforming them.
      function generateGroup(){
        var group     = svg.g(),
            path      = generatePath(),
            coords    = path.getPointAtLength(0),
            circle    = generateCircle(coords.x, coords.y);

        group.add(path, circle);
        group.transform(generateTransform());
        return group;
      }

    // Random paths made with any svg image software
      var randomPath = [
        'M1.453125,-0.55859375 C75.5625,76.515625 152.230469,34.4414062 152.230469,34.4414062 C152.230469,34.4414062 276.964844,-36.1484375 250.523438,67.8125 C224.082031,171.773438 261.673768,157.95441 250.523438,195.105469 C239.373107,232.256527 293.597656,283.253906 194.042969,255.996094 C94.4882812,228.738281 90.96875,224.03125 54.3398438,255.996094 C17.7109375,287.960937 -22.921875,252.710938 25.265625,195.105469 C73.453125,137.5 64.2304688,137.5 47.7460938,118.441406 C31.2617188,99.3828125 22.0820312,80.8085938 32.0078125,57.625 C41.9335938,34.4414062 129.597656,-36.703125 154.746094,91.6640625 C179.894531,220.03125 264.859375,262.847656 264.859375,262.847656',
        'M0.5625,-0.078125 C0.5625,-0.078125 266.597656,77.9179687 261.859375,202.105469 C257.121094,326.292969 89.5748377,243.911913 53.8242188,192.550781 C18.0735998,141.189649 -26.9921875,-14.5625 89.265625,15.328125 C205.523438,45.21875 234.232847,74.6313182 251.5625,121.585938 C268.892153,168.540557 290.335938,281.546875 171.746094,238.808594 C53.15625,196.070312 240.042969,12.6601562 240.042969,12.6601562',
        'M1.08203125,-0.66796875 C-17.9377166,-21.4041628 9.15625,64.2929688 72.9335937,64.2929688 C136.710937,64.2929688 87.8177529,-21.0716058 150.488281,12.1445312 C213.15881,45.3606683 293.046875,52.3984375 260.488281,163.699219 C227.929687,275 148.199223,260.893557 94.5625,254.144531 C40.9257767,247.395506 -4.25,191.734375 14.7109375,132.773438 C33.671875,73.8125 173.96875,86.4023438 173.96875,86.4023438 C173.96875,86.4023438 284.410156,108.921875 217.449219,167.699219 C150.488281,226.476562 74.671875,186.03125 74.671875,186.03125 C74.671875,186.03125 -8.80859375,153.144531 77.96875,119.773438 C164.746094,86.4023438 254.339844,262.070312 254.339844,262.070312'
      ];

      function generatePath(){
        var path = svg.path( randomPath[getRandomInt(0, randomPath.length - 1)] ).attr({
          fill: 'none',
          strokeWidth: '0'
        });

        return path;
      }

      function generateCircle(cx, cy){
        var circle = svg.circle(5,5,2)
          .attr({
            fill: '#CFF09E',
            stroke: '#ffffff',
            strokeOpacity: 0.1,
            strokeWidth: 5,
            opacity: 0,
            class: 'firefly',
            zIndex: 1,
            cx: cx,
            cy: cy
          });

        return circle;
      }

    // Sets the initial time for fireflies to first start appearing
      FireFly.prototype.delay = function(){
        var self = this;
        setTimeout(function(){
          self.blink();
          self.fly();
        }, getRandomInt(1, 10) * 1000);
      };

    // Set's the blinking animation
      FireFly.prototype.blink = function(){
        var self = this;
        self.circle.animate({opacity: 1}, FIREFLY_BLINK_SPEED / 2, function(){
          this.animate({opacity: 0}, FIREFLY_BLINK_SPEED / 4);
        });
        setTimeout(function(){self.blink()}, FIREFLY_BLINK_SPEED);
      };

    // Sets the 'flying' animation which just sets the fireflies moving
    // along a path. Uncomment below to see how the paths are drawn
      FireFly.prototype.fly = function(){
          var self = this,
          length = self.path.getTotalLength();

    /*       self.path.attr({
             stroke: '#fff',
             strokeWidth: 1,
             fill: 'none',
             "stroke-dasharray": length + " " + length,
             "stroke-dashoffset": length
           }).animate({"stroke-dashoffset": 10}, FIREFLY_SPEED, mina.linear);*/

          Snap.animate(0, length, function( value ) {
             var movePoint = self.path.getPointAtLength( value );
             self.circle.attr({ cx: movePoint.x, cy: movePoint.y });
          }, FIREFLY_SPEED, mina.linear);

          setTimeout(function(){self.fly()}, FIREFLY_SPEED);
      };

      var fireFlies = [];

      for (var i = 0, l = MAX_FIREFLIES; i < l; i++) {
        fireFlies.push(new FireFly());
        fireFlies[i].delay();
      }

    })();

See the Pen Random Fireflies by Neal Fennimore ( @nealfennimore) on CodePen.