Creating random fireflies with SnapSVG

Published
Last updated

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.