Skip to content

Instantly share code, notes, and snippets.

@omnizach
Last active February 29, 2016 20:53
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save omnizach/886d9843b0fb176da2a7 to your computer and use it in GitHub Desktop.
That Bezier screensaver from Windows 2000

Bezier Screensaver

A reasonable replication of the Bezier screensaver from Windows 2000. It uses D3 and my bezier library.

(function(){var t,n,r,e,i,h,o,p,s=function(t,n){return(+t%(n=+n)+n)%n},u=[].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.computeControlPoints=function(t){var n,r,e,i,h,o,p,s,u,a,l,c,f,y,v;for(n=function(t){return 0>=t?0:t>=s-1?2:1},e=function(t){return t>=s-1?0:1},s=t.length-1,a=new Array(s-1),l=new Array(s-1),r=function(){var t,n,r;for(r=[],i=t=0,n=s;n>=0?n>t:t>n;i=n>=0?++t:--t)r.push(4);return r}(),r[0]=2,r[s-1]=7,c=function(){var n,r,e;for(e=[],i=n=0,r=s-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[s-1]+t[s]),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[s-1]=c[s-1]/r[s-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=u=0,v=r.length-1;v>=0?v>u:u>v;i=v>=0?++u:--u)l[i]=2*t[i+1]-a[i+1];return l[s-1]=.5*(t[s]+a[s-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,b,A,D,P,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[s(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[s(t.length-n,t.length)]);return i},t=u.call(f(t)).concat(u.call(t),u.call(y(t))),h=u.call(f(h)).concat(u.call(h),u.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)),A=i(t.slice(0,-1),h.slice(0,-1),a.p1,l.p1,a.p2,l.p2,t.slice(1),h.slice(1)),P=[],v=g=0,x=A.length;x>g;v=++g)D=A[v],m=D[0],w=D[1],M=D[2],d=D[3],_=D[4],L=D[5],C=D[6],b=D[7],p=new n(new r(m,w),new r(M,d),new r(_,L),new r(C,b)),p.startLength=T,p.endLength=T+p.length,p.segmentOffset=v/(t.length-1),p.index=v,T+=p.length,P.push(p);return P},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;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="bezier.min.js"></script>
<script>
var margin = 50,
width = 960 - margin*2,
height = 500 - margin*2;
var svg = d3.select("body").append("svg")
.attr("width", width+margin*2)
.attr("height", height+margin*2);
svg.append('rect')
.attr('width', width+margin*2)
.attr('height', height+margin*2)
.style('fill', '#000');
svg = svg.append('g')
.attr('transform', 'translate(' + margin + ',' + margin + ')');
var knots = d3.range(6).map(function() {
var angle = Math.random() * Math.PI * 2;
return {
x: Math.random() * width,
y: Math.random() * height,
dx: Math.cos(angle) * 2,
dy: Math.sin(angle) * 2
};
});
d3.range(10, 30).forEach(function(delay) {
var sp = svg.append('g')
.datum(JSON.parse(JSON.stringify(knots)));
var cs = sp.selectAll('.curve')
.data(bezier.Spline(knots, true).curves)
.enter()
.append('path')
.classed('curve', true);
d3.timer(function(elapsed) {
var ks = sp.datum().map(function(k) {
k.x += k.dx;
k.y += k.dy;
if (k.x < 0 || k.x > width) {
k.dx *= -1;
}
if (k.y < 0 || k.y > height) {
k.dy *= -1;
}
return k;
});
sp.datum(ks);
cs.data(bezier.Spline(ks, true).curves)
.attr('d', bezier.Curve.penPath)
.style('stroke', d3.hsl(elapsed/250 % 360, 0.75, 0.5));
return false; // loop forever
}, delay * 100);
});
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment