Skip to content

Instantly share code, notes, and snippets.

@omnizach
Last active February 29, 2016 20:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save omnizach/c44cd2a810d94734b053 to your computer and use it in GitHub Desktop.
Save omnizach/c44cd2a810d94734b053 to your computer and use it in GitHub Desktop.
Fireflies

Fireflies

A fun little demonstration of a visual I've had in the back of my mind for a long time.

Uses my Bezier library.

(function(){var t,n,r,e,i,h,o,p,u=function(t,n){return(+t%(n=+n)+n)%n},s=[].slice;i=function(){var t,n,r,e,i,h,o;for(i=function(){var n,r,e;for(e=[],n=0,r=arguments.length;r>n;n++)t=arguments[n],e.push(t.length);return e}.apply(this,arguments),e=Math.min.apply(Math,i),o=[],n=r=0,h=e;h>=0?h>r:r>h;n=h>=0?++r:--r)o.push(function(){var r,e,i;for(i=[],r=0,e=arguments.length;e>r;r++)t=arguments[r],i.push(t[n]);return i}.apply(this,arguments));return o},Function.prototype._getter=function(t,n){return Object.defineProperty(this.prototype,t,{get:n,configurable:!0})},t=1-1e-6,r=function(){function t(n,r){return this instanceof t?(this.x=n,void(this.y=r)):new t(n,r)}return t}(),n=function(){function t(n,r,e,i){return this instanceof t?(this.p0=n,this.p1=r,this.p2=e,void(this.p3=i)):new t(n,r,e,i)}return t.penPath=function(t){return"M "+t.p0.x+", "+t.p0.y+" C "+t.p1.x+", "+t.p1.y+" "+t.p2.x+", "+t.p2.y+" "+t.p3.x+", "+t.p3.y},t.paintPath=function(t){var n;return n=t/2,function(t){var r,e;return r=t.normal(0),e=t.normal(1),"M "+(t.p0.x-r.x*n)+", "+(t.p0.y-r.y*n)+" L "+(t.p0.x+r.x*n)+", "+(t.p0.y+r.y*n)+" L "+(t.p3.x+e.x*n)+", "+(t.p3.y+e.y*n)+" L "+(t.p3.x-e.x*n)+", "+(t.p3.y-e.y*n)+" Z"}},t.prototype._findT=function(t,n){var r;return t=Math.min(t,this.length),n=n||t/this.length,r=(this.lengthAt(n)-t)/this.length,Math.abs(r)<1e-4?n:this._findT(t,n-r/2)},t._base3=function(t,n,r,e,i){var h,o;return h=-3*n+9*r-9*e+3*i,o=t*h+6*n-12*r+6*e,t*o-3*n+3*r},t.prototype.lengthAt=function(n){var r,e,i;return null==n&&(n=1),n=n>1?1:0>n?0:n,i=n/2,e=function(n,r){var e;return e=i*n[0]+i,n[1]*Math.sqrt(Math.pow(t._base3(e,r.p0.x,r.p1.x,r.p2.x,r.p3.x),2)+Math.pow(t._base3(e,r.p0.y,r.p1.y,r.p2.y,r.p3.y),2))},i*function(){var t,n,i,h;for(i=[[-.1252,.2491],[.1252,.2491],[-.3678,.2335],[.3678,.2335],[-.5873,.2032],[.5873,.2032],[-.7699,.1601],[.7699,.1601],[-.9041,.1069],[.9041,.1069],[-.9816,.0472],[.9816,.0472]],h=[],t=0,n=i.length;n>t;t++)r=i[t],h.push(e(r,this));return h}.call(this).reduce(function(t,n){return t+n})},t._getter("length",function(){return null!=this._length?this._length:this._length=this.lengthAt(1)}),t.prototype.x=function(t){return null==t&&(t=0),Math.pow(1-t,3)*this.p0.x+3*Math.pow(1-t,2)*t*this.p1.x+3*(1-t)*Math.pow(t,2)*this.p2.x+Math.pow(t,3)*this.p3.x},t.prototype.y=function(t){return null==t&&(t=0),Math.pow(1-t,3)*this.p0.y+3*Math.pow(1-t,2)*t*this.p1.y+3*(1-t)*Math.pow(t,2)*this.p2.y+Math.pow(t,3)*this.p3.y},t.prototype.point=function(t){return null==t&&(t=0),r(this.x(t),this.y(t))},t.prototype.pointAtLength=function(t){return null==t&&(t=0),this.point(this._findT(t))},t.prototype.firstDerivative=function(t){return null==t&&(t=0),new r(3*Math.pow(1-t,2)*(this.p1.x-this.p0.x)+6*(1-t)*t*(this.p2.x-this.p1.x)+3*Math.pow(t,2)*(this.p3.x-this.p2.x),3*Math.pow(1-t,2)*(this.p1.y-this.p0.y)+6*(1-t)*t*(this.p2.y-this.p1.y)+3*Math.pow(t,2)*(this.p3.y-this.p2.y))},t.prototype.secondDerivative=function(t){return null==t&&(t=0),new r(6*(1-t)*(this.p2.x-2*this.p1.x+this.p0.x)+6*t*(this.p3.x-2*this.p2.x+this.p2.x),6*(1-t)*(this.p2.y-2*this.p1.y+this.p0.y)+6*t*(this.p3.y-2*this.p2.y+this.p2.y))},t.prototype.curvature=function(t){var n,r;return null==t&&(t=0),n=this.firstDerivative(t),r=this.secondDerivative(t),(n.x*r.y-n.y*r.x)/Math.pow(Math.pow(n.x,2)+Math.pow(n.y,2),1.5)},t.prototype.tangent=function(t){var n,e;return null==t&&(t=0),e=this.firstDerivative(t),n=Math.sqrt(e.x*e.x+e.y*e.y)||1,new r(e.x/n,e.y/n)},t.prototype.normal=function(t){var n;return null==t&&(t=0),n=this.tangent(t),new r(-n.y,n.x)},t.prototype.pointTransform=function(t){var n,r,e,i;return null==t&&(t=0),n=[this.x(t),this.y(t)],e=n[0],i=n[1],r=this.tangent(t),"translate("+e+", "+i+") rotate("+180*Math.atan2(r.y,r.x)/Math.PI+")"},t}(),e=function(){function e(t,n){var r;return null==n&&(n=!1),this instanceof e?(this.closed=n,this.curves=e.computeSpline(t.map(function(t){return t.x}),t.map(function(t){return t.y}),n),this.startLengths=function(){var t,n,e,i;for(e=this.curves,i=[],t=0,n=e.length;n>t;t++)r=e[t],i.push(r.startLength);return i}.call(this),this.endLengths=function(){var t,n,e,i;for(e=this.curves,i=[],t=0,n=e.length;n>t;t++)r=e[t],i.push(r.endLength);return i}.call(this),void(this.length=this.endLengths.slice(-1)[0])):new e(t,n)}return e.penPath=function(t){var r;return function(){var e,i,h,o;for(h=t.curves,o=[],e=0,i=h.length;i>e;e++)r=h[e],o.push(n.penPath(r));return o}().join(" ")},e.paintPath=function(t){var r;return r=n.paintPath(t),function(t){var n;return function(){var r,e,i,h;for(i=t.curves,h=[],r=0,e=i.length;e>r;r++)n=i[r],h.push(paintPath(n));return h}().join(" ")}},e.computeControlPoints=function(t){var n,r,e,i,h,o,p,u,s,a,l,c,f,y,v;for(n=function(t){return 0>=t?0:t>=u-1?2:1},e=function(t){return t>=u-1?0:1},u=t.length-1,a=new Array(u-1),l=new Array(u-1),r=function(){var t,n,r;for(r=[],i=t=0,n=u;n>=0?n>t:t>n;i=n>=0?++t:--t)r.push(4);return r}(),r[0]=2,r[u-1]=7,c=function(){var n,r,e;for(e=[],i=n=0,r=u-1;r>=0?r>n:n>r;i=r>=0?++n:--n)e.push(4*t[i]+2*t[i+1]);return e}(),c[0]=t[0]+2*t[1],c.push(8*t[u-1]+t[u]),i=h=0,f=r.length-1;f>=0?f>h:h>f;i=f>=0?++h:--h)p=n(i+1)/r[i],r[i+1]-=p*e(i),c[i+1]-=p*c[i];for(a[u-1]=c[u-1]/r[u-1],i=o=y=r.length-2;0>=y?0>=o:o>=0;i=0>=y?++o:--o)a[i]=(c[i]-e(i)*a[i+1])/r[i];for(i=s=0,v=r.length-1;v>=0?v>s:s>v;i=v>=0?++s:--s)l[i]=2*t[i+1]-a[i+1];return l[u-1]=.5*(t[u]+a[u-1]),{p1:a,p2:l}},e.computeSpline=function(t,h,o){var p,a,l,c,f,y,v,g,x,m,w,M,d,_,L,C,P,b,A,D,T;for(c=12,o&&(y=function(t){var n,r,e,i;for(i=[],n=r=0,e=c;e>=0?e>r:r>e;n=e>=0?++r:--r)i.push(t[u(n,t.length)]);return i},f=function(t){var n,r,e,i;for(i=[],n=r=e=c;0>=e?0>r:r>0;n=0>=e?++r:--r)i.push(t[u(t.length-n,t.length)]);return i},t=s.call(f(t)).concat(s.call(t),s.call(y(t))),h=s.call(f(h)).concat(s.call(h),s.call(y(h)))),a=e.computeControlPoints(t),l=e.computeControlPoints(h),T=0,o&&(t=t.slice(c,+-c+1||9e9),h=h.slice(c,+-c+1||9e9),a.p1=a.p1.slice(c,+-c+1||9e9),l.p1=l.p1.slice(c,+-c+1||9e9),a.p2=a.p2.slice(c,+-c+1||9e9),l.p2=l.p2.slice(c,+-c+1||9e9)),b=i(t.slice(0,-1),h.slice(0,-1),a.p1,l.p1,a.p2,l.p2,t.slice(1),h.slice(1)),D=[],v=g=0,x=b.length;x>g;v=++g)A=b[v],m=A[0],w=A[1],M=A[2],d=A[3],_=A[4],L=A[5],C=A[6],P=A[7],p=new n(new r(m,w),new r(M,d),new r(_,L),new r(C,P)),p.startLength=T,p.endLength=T+p.length,p.segmentOffset=v/(t.length-1),p.index=v,T+=p.length,D.push(p);return D},e._marshalCurve=function(n){return function(r){var e;return r=(0>r?0:r>t?t:r)*this.curves.length||0,e=Math.trunc(r),this.curves[e][n](r-e)}},e.prototype.x=e._marshalCurve("x"),e.prototype.y=e._marshalCurve("y"),e.prototype.point=e._marshalCurve("point"),e.prototype.pointAtLength=function(t){var n,r;return null==t&&(t=0),n=function(t,r,e,i){var h;switch(h=e+i>>>1,!1){case!((t[h-1]||0)<=r&&r<=t[h]):return h;case!(r<(t[h-1]||0)):return n(t,r,e,h);default:return n(t,r,h+1,i)}},r=n(this.endLengths,Math.min(t,this.endLengths[this.endLengths.length-1]),0,this.endLengths.length),this.curves[r].pointAtLength(t-this.startLengths[r])},e.prototype.firstDerivative=e._marshalCurve("firstDerivative"),e.prototype.secondDerivative=e._marshalCurve("secondDerivative"),e.prototype.curvature=e._marshalCurve("curvature"),e.prototype.tangent=e._marshalCurve("tangent"),e.prototype.normal=e._marshalCurve("normal"),e.prototype.pointTransform=e._marshalCurve("pointTransform"),e.prototype.normalize=function(t,n){var r,i;return null==t&&(t=this.length/n||1),null==n&&(n=Math.ceil(this.length/t)),i=function(){var e,i,h;for(h=[],r=e=0,i=n;i>=0?i>e:e>i;r=i>=0?++e:--e)h.push(this.pointAtLength(r*t));return h}.call(this),e(i,this.closed)},e}(),o=function(t){return t.x.bind(t)},p=function(t){return t.y.bind(t)},h=function(t){return t.pointTransform.bind(t)},this.bezier={Point:r,Curve:n,Spline:e,interpolateX:o,interpolateY:p,interpolateTransform:h}}).call(this);
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.curve {
fill: none;
stroke-width: 3px;
}
svg {
background-color: #000;
}
.curve {
stroke: #333;
stroke-width: 3px;
}
.firefly {
stroke: none;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="bezier.min.js"></script>
<script>
var margin = 20,
width = 960 - margin*2,
height = 500 - margin*2,
randWidth = d3.random.normal(width / 2, width / 6),
randHeight = d3.random.normal(height / 2, height / 6);
var svg = d3.select("body").append("svg")
.attr("width", width+margin*2)
.attr("height", height+margin*2)
.append('g')
.attr('transform', 'translate(' + margin + ',' + margin + ')');
function firefly() {
var knots = d3.range(10).map(function() {
return {
x: randWidth(),
y: randHeight()
};
}),
flight = bezier.Spline(knots, true),
step = 1 / flight.length;
return {
flight: flight,
step: step,
t: 0
};
}
var fs = svg.selectAll('.firefly')
.data(d3.range(50).map(function() { return firefly(); }))
.enter()
.append('circle')
.classed('firefly', true)
.attr('r', 2)
.style('fill', function() { return d3.hsl(Math.random() * 120, 1, 0.75); })
.style('opacity', 0.1),
glowCounter = 0;
d3.timer(function(elapsed) {
fs.each(function(d) {
d.t = (d.t + d.step) % 1;
var f = d3.select(this);
f.datum(d)
.attr('cx', d.flight.x(d.t))
.attr('cy', d.flight.y(d.t));
});
if (elapsed - glowCounter > 100) {
glowCounter = elapsed;
fs.filter(function() { return Math.random() < 0.01; })
.transition()
.duration(1500)
.style('opacity', 0.8)
.transition()
.delay(function() { return Math.random() * 1000 * 2; })
.duration(3000)
.style('opacity', 0.1);
}
});
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment