=M&&(M=b+1);!(w=y[M])&&++M=0;)(r=o[i])&&(a&&a!==r.nextSibling&&a.parentNode.insertBefore(r,a),a=r);return this},Uo=function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=x);for(var e=this._groups,r=e.length,o=new Array(r),i=0;i1?this.each((null==n?z:"function"==typeof n?C:S)(t,n,null==e?"":e)):qo(r=this.node()).getComputedStyle(r,null).getPropertyValue(t)},Wo=function(t,n){return arguments.length>1?this.each((null==n?N:"function"==typeof n?j:A)(t,n)):this.node()[t]};E.prototype={add:function(t){var n=this._names.indexOf(t);n<0&&(this._names.push(t),this._node.setAttribute("class",this._names.join(" ")))},remove:function(t){var n=this._names.indexOf(t);n>=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var Ro=function(t,n){var e=D(t+"");if(arguments.length<2){for(var r=L(this.node()),o=-1,i=e.length;++o=240?t-240:t+120,o,r),dt(t,o,r),dt(t<120?t+240:t-120,o,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1}}));var wi=Math.PI/180,bi=180/Math.PI,Mi=18,Ti=.95047,ki=1,zi=1.08883,Si=4/29,Ci=6/29,Ni=3*Ci*Ci,Ai=Ci*Ci*Ci;ai(yt,gt,nt(et,{brighter:function(t){return new yt(this.l+Mi*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new yt(this.l-Mi*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return t=ki*vt(t),n=Ti*vt(n),e=zi*vt(e),new st(xt(3.2404542*n-1.5371385*t-.4985314*e),xt(-.969266*n+1.8760108*t+.041556*e),xt(.0556434*n-.2040259*t+1.0572252*e),this.opacity)}})),ai(Mt,bt,nt(et,{brighter:function(t){return new Mt(this.h,this.c,this.l+Mi*(null==t?1:t),this.opacity)},darker:function(t){return new Mt(this.h,this.c,this.l-Mi*(null==t?1:t),this.opacity)},rgb:function(){return pt(this).rgb()}}));var ji=-.14861,Di=1.78277,Li=-.29227,Ei=-.90649,Yi=1.97294,Ui=Yi*Ei,Xi=Yi*Di,Fi=Di*Li-Ei*ji;ai(zt,kt,nt(et,{brighter:function(t){return t=null==t?si:Math.pow(si,t),new zt(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?ui:Math.pow(ui,t),new zt(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*wi,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),o=Math.sin(t);return new st(255*(n+e*(ji*r+Di*o)),255*(n+e*(Li*r+Ei*o)),255*(n+e*(Yi*r)),this.opacity)}}));var Oi,Bi,Hi,Pi,Zi=function(t){return function(){return t}},qi=function t(n){function e(t,n){var e=r((t=ut(t)).r,(n=ut(n)).r),o=r(t.g,n.g),i=r(t.b,n.b),a=jt(t.opacity,n.opacity);return function(n){return t.r=e(n),t.g=o(n),t.b=i(n),t.opacity=a(n),t+""}}var r=At(n);return e.gamma=t,e}(1),Ii=function(t,n){var e,r=n?n.length:0,o=t?Math.min(r,t.length):0,i=new Array(r),a=new Array(r);for(e=0;ei&&(o=n.slice(i,o),u[a]?u[a]+=o:u[++a]=o),(e=e[0])===(r=r[0])?u[a]?u[a]+=r:u[++a]=r:(u[++a]=null,s.push({i:a,x:Ri(e,r)})),i=$i.lastIndex;return iba&&e.stateau)if(Math.abs(c*u-s*l)>au&&o){var f=e-i,d=r-a,p=u*u+s*s,g=f*f+d*d,y=Math.sqrt(p),m=Math.sqrt(h),v=o*Math.tan((ou-Math.acos((p+h-g)/(2*y*m)))/2),x=v/m,_=v/y;Math.abs(x-1)>au&&(this._+="L"+(t+x*l)+","+(n+x*c)),this._+="A"+o+","+o+",0,0,"+ +(c*f>l*d)+","+(this._x1=t+_*u)+","+(this._y1=n+_*s)}else this._+="L"+(this._x1=t)+","+(this._y1=n);else;},arc:function(t,n,e,r,o,i){t=+t,n=+n,e=+e;var a=e*Math.cos(r),u=e*Math.sin(r),s=t+a,l=n+u,c=1^i,h=i?r-o:o-r;if(e<0)throw new Error("negative radius: "+e);null===this._x1?this._+="M"+s+","+l:(Math.abs(this._x1-s)>au||Math.abs(this._y1-l)>au)&&(this._+="L"+s+","+l),e&&(h>uu?this._+="A"+e+","+e+",0,1,"+c+","+(t-a)+","+(n-u)+"A"+e+","+e+",0,1,"+c+","+(this._x1=s)+","+(this._y1=l):(h<0&&(h=h%iu+iu),this._+="A"+e+","+e+",0,"+ +(h>=ou)+","+c+","+(this._x1=t+e*Math.cos(o))+","+(this._y1=n+e*Math.sin(o))))},rect:function(t,n,e,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)+"h"+ +e+"v"+ +r+"h"+-e+"Z"},toString:function(){return this._}};var su="$";Dn.prototype=Ln.prototype={constructor:Dn,has:function(t){return su+t in this},get:function(t){return this[su+t]},set:function(t,n){return this[su+t]=n,this},remove:function(t){var n=su+t;return n in this&&delete this[n]},clear:function(){for(var t in this)t[0]===su&&delete this[t]},keys:function(){var t=[];for(var n in this)n[0]===su&&t.push(n.slice(1));return t},values:function(){var t=[];for(var n in this)n[0]===su&&t.push(this[n]);return t},entries:function(){var t=[];for(var n in this)n[0]===su&&t.push({key:n.slice(1),value:this[n]});return t},size:function(){var t=0;for(var n in this)n[0]===su&&++t;return t},empty:function(){for(var t in this)if(t[0]===su)return!1;return!0},each:function(t){for(var n in this)n[0]===su&&t(this[n],n.slice(1),this)}};var lu=Ln.prototype;En.prototype=Yn.prototype={constructor:En,has:lu.has,add:function(t){return t+="",this[su+t]=t,this},remove:lu.remove,clear:lu.clear,values:lu.keys,size:lu.size,empty:lu.empty,each:lu.each};var cu=function(t){function n(t,n){var r,o,i=e(t,function(t,e){return r?r(t,e-1):(o=t,void(r=n?Xn(t,n):Un(t)))});return i.columns=o,i}function e(t,n){function e(){if(c>=l)return a;if(o)return o=!1,i;var n,e=c;if(34===t.charCodeAt(e)){for(var r=e;r++t||t>o||r>n||n>i))return this;var a,u,s=o-e,l=this._root;switch(u=(n<(r+i)/2)<<1|t<(e+o)/2){case 0:do a=new Array(4),a[u]=l,l=a;while(s*=2,o=e+s,i=r+s,t>o||n>i);break;case 1:do a=new Array(4),a[u]=l,l=a;while(s*=2,e=o-s,i=r+s,e>t||n>i);break;case 2:do a=new Array(4),a[u]=l,l=a;while(s*=2,o=e+s,r=i-s,t>o||r>n);break;case 3:do a=new Array(4),a[u]=l,l=a;while(s*=2,e=o-s,r=i-s,e>t||r>n)}this._root&&this._root.length&&(this._root=l)}return this._x0=e,this._y0=r,this._x1=o,this._y1=i,this},mu=function(){var t=[];return this.visit(function(n){if(!n.length)do t.push(n.data);while(n=n.next)}),t},vu=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]},xu=function(t,n,e,r,o){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=o},_u=function(t,n,e){var r,o,i,a,u,s,l,c=this._x0,h=this._y0,f=this._x1,d=this._y1,p=[],g=this._root;for(g&&p.push(new xu(g,c,h,f,d)),null==e?e=1/0:(c=t-e,h=n-e,f=t+e,d=n+e,e*=e);s=p.pop();)if(!(!(g=s.node)||(o=s.x0)>f||(i=s.y0)>d||(a=s.x1)=m)<<1|t>=y)&&(s=p[p.length-1],p[p.length-1]=p[p.length-1-l],p[p.length-1-l]=s)}else{var v=t-+this._x.call(null,g.data),x=n-+this._y.call(null,g.data),_=v*v+x*x;if(_=(u=(p+y)/2))?p=u:y=u,(c=a>=(s=(g+m)/2))?g=s:m=s,n=d,!(d=d[h=c<<1|l]))return this;if(!d.length)break;(n[h+1&3]||n[h+2&3]||n[h+3&3])&&(e=n,f=h)}for(;d.data!==t;)if(r=d,!(d=d.next))return this;return(o=d.next)&&delete d.next,r?(o?r.next=o:delete r.next,this):n?(o?n[h]=o:delete n[h],(d=n[0]||n[1]||n[2]||n[3])&&d===(n[3]||n[2]||n[1]||n[0])&&!d.length&&(e?e[f]=d:this._root=d),this):(this._root=o,this)},bu=function(){return this._root},Mu=function(){var t=0;return this.visit(function(n){if(!n.length)do++t;while(n=n.next)}),t},Tu=function(t){var n,e,r,o,i,a,u=[],s=this._root;for(s&&u.push(new xu(s,this._x0,this._y0,this._x1,this._y1));n=u.pop();)if(!t(s=n.node,r=n.x0,o=n.y0,i=n.x1,a=n.y1)&&s.length){var l=(r+i)/2,c=(o+a)/2;(e=s[3])&&u.push(new xu(e,l,c,i,a)),(e=s[2])&&u.push(new xu(e,r,c,l,a)),(e=s[1])&&u.push(new xu(e,l,o,i,c)),(e=s[0])&&u.push(new xu(e,r,o,l,c))}return this},ku=function(t){var n,e=[],r=[];for(this._root&&e.push(new xu(this._root,this._x0,this._y0,this._x1,this._y1));n=e.pop();){
+var o=n.node;if(o.length){var i,a=n.x0,u=n.y0,s=n.x1,l=n.y1,c=(a+s)/2,h=(u+l)/2;(i=o[0])&&e.push(new xu(i,a,u,c,h)),(i=o[1])&&e.push(new xu(i,c,u,s,h)),(i=o[2])&&e.push(new xu(i,a,h,c,l)),(i=o[3])&&e.push(new xu(i,c,h,s,l))}r.push(n)}for(;n=r.pop();)t(n.node,n.x0,n.y0,n.x1,n.y1);return this},zu=function(t){return arguments.length?(this._x=t,this):this._x},Su=function(t){return arguments.length?(this._y=t,this):this._y},Cu=qn.prototype=In.prototype;Cu.copy=function(){var t,n,e=new In(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=Wn(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var o=0;o<4;++o)(n=r.source[o])&&(n.length?t.push({source:n,target:r.target[o]=new Array(4)}):r.target[o]=Wn(n));return e},Cu.add=gu,Cu.addAll=Bn,Cu.cover=yu,Cu.data=mu,Cu.extent=vu,Cu.find=_u,Cu.remove=wu,Cu.removeAll=Hn,Cu.root=bu,Cu.size=Mu,Cu.visit=Tu,Cu.visitAfter=ku,Cu.x=zu,Cu.y=Su;var Nu,Au=function(t,n){if((e=(t=n?t.toExponential(n-1):t.toExponential()).indexOf("e"))<0)return null;var e,r=t.slice(0,e);return[r.length>1?r[0]+r.slice(2):r,+t.slice(e+1)]},ju=function(t){return t=Au(Math.abs(t)),t?t[1]:NaN},Du=function(t,n){return function(e,r){for(var o=e.length,i=[],a=0,u=t[0],s=0;o>0&&u>0&&(s+u+1>r&&(u=Math.max(1,r-s)),i.push(e.substring(o-=u,o+u)),!((s+=u+1)>r));)u=t[a=(a+1)%t.length];return i.reverse().join(n)}},Lu=function(t,n){t=t.toPrecision(n);t:for(var e,r=t.length,o=1,i=-1;o0&&(i=0)}return i>0?t.slice(0,i)+t.slice(e+1):t},Eu=function(t,n){var e=Au(t,n);if(!e)return t+"";var r=e[0],o=e[1],i=o-(Nu=3*Math.max(-8,Math.min(8,Math.floor(o/3))))+1,a=r.length;return i===a?r:i>a?r+new Array(i-a+1).join("0"):i>0?r.slice(0,i)+"."+r.slice(i):"0."+new Array(1-i).join("0")+Au(t,Math.max(0,n+i-1))[0]},Yu=function(t,n){var e=Au(t,n);if(!e)return t+"";var r=e[0],o=e[1];return o<0?"0."+new Array(-o).join("0")+r:r.length>o+1?r.slice(0,o+1)+"."+r.slice(o+1):r+new Array(o-r.length+2).join("0")},Uu={"":Lu,"%":function(t,n){return(100*t).toFixed(n)},b:function(t){return Math.round(t).toString(2)},c:function(t){return t+""},d:function(t){return Math.round(t).toString(10)},e:function(t,n){return t.toExponential(n)},f:function(t,n){return t.toFixed(n)},g:function(t,n){return t.toPrecision(n)},o:function(t){return Math.round(t).toString(8)},p:function(t,n){return Yu(100*t,n)},r:Yu,s:Eu,X:function(t){return Math.round(t).toString(16).toUpperCase()},x:function(t){return Math.round(t).toString(16)}},Xu=/^(?:(.)?([<>=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i,Fu=function(t){return new Rn(t)};Rn.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(null==this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(null==this.precision?"":"."+Math.max(0,0|this.precision))+this.type};var Ou,Bu,Hu,Pu=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"],Zu=function(t){function n(t){function n(t){var n,o,s,v=p,x=g;if("c"===d)x=y(t)+x,t="";else{t=+t;var _=(t<0||1/t<0)&&(t*=-1,!0);if(t=y(t,f),_)for(n=-1,o=t.length,_=!1;++ns||s>57){x=(46===s?i+t.slice(n+1):t.slice(n))+x,t=t.slice(0,n);break}}h&&!l&&(t=r(t,1/0));var w=v.length+t.length+x.length,b=w>1)+v+t+x+b.slice(w)}return b+v+t+x}t=Fu(t);var e=t.fill,a=t.align,u=t.sign,s=t.symbol,l=t.zero,c=t.width,h=t.comma,f=t.precision,d=t.type,p="$"===s?o[0]:"#"===s&&/[boxX]/.test(d)?"0"+d.toLowerCase():"",g="$"===s?o[1]:/[%p]/.test(d)?"%":"",y=Uu[d],m=!d||/[defgprs%]/.test(d);return f=null==f?d?6:12:/[gprs]/.test(d)?Math.max(1,Math.min(21,f)):Math.max(0,Math.min(20,f)),n.toString=function(){return t+""},n}function e(t,e){var r=n((t=Fu(t),t.type="f",t)),o=3*Math.max(-8,Math.min(8,Math.floor(ju(e)/3))),i=Math.pow(10,-o),a=Pu[8+o/3];return function(t){return r(i*t)+a}}var r=t.grouping&&t.thousands?Du(t.grouping,t.thousands):Gn,o=t.currency,i=t.decimal;return{format:n,formatPrefix:e}};Vn({decimal:".",thousands:",",grouping:[3],currency:["$",""]});var qu=function(t){return Math.max(0,-ju(Math.abs(t)))},Iu=function(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(ju(n)/3)))-ju(Math.abs(t)))},Wu=function(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,ju(n)-ju(t))+1},Ru=function(){return new $n};$n.prototype={constructor:$n,reset:function(){this.s=this.t=0},add:function(t){Jn(Gu,t,this.t),Jn(this,Gu.s,this.s),this.s?this.t+=Gu.t:this.s=Gu.t},valueOf:function(){return this.s}};var Gu=new $n,Vu=1e-6,$u=Math.PI,Ju=$u/2,Qu=$u/4,Ku=2*$u,ts=$u/180,ns=Math.abs,es=Math.atan,rs=Math.atan2,os=Math.cos,is=Math.sin,as=Math.sqrt,us=(Ru(),Ru(),Ru(),function(){var t,n=[];return{point:function(n,e){t.push([n,e])},lineStart:function(){n.push(t=[])},lineEnd:te,rejoin:function(){n.length>1&&n.push(n.pop().concat(n.shift()))},result:function(){var e=n;return n=[],t=null,e}}}),ss=function(t,n){return ns(t[0]-n[0])=0;--i)o.point((c=l[i])[0],c[1]);else r(f.x,f.p.x,-1,o);f=f.p}f=f.o,l=f.z,d=!d}while(!f.v);o.lineEnd()}}},cs=(Ru(),Ru(),Ru(),Ru()),hs=function(t,n){var e=n[0],r=n[1],o=[is(e),-os(e),0],i=0,a=0;cs.reset();for(var u=0,s=t.length;u=0?1:-1,T=M*b,k=T>$u,z=p*_;if(cs.add(rs(z*M*is(T),g*w+z*os(T))),i+=k?b+M*Ku:b,k^f>=e^v>=e){var S=ee(ne(h),ne(m));re(S);var C=ee(o,S);re(C);var N=(k^b>=0?-1:1)*Kn(C[2]);(r>N||r===N&&(S[0]||S[1]))&&(a+=k^b>=0?1:-1)}}return(i<-Vu||i0){for(_||(i.polygonStart(),_=!0),i.lineStart(),t=0;t1&&2&o&&a.push(a.pop().concat(a.shift())),p.push(a.filter(ae))}var d,p,g,y=n(i),m=o.invert(r[0],r[1]),v=us(),x=n(v),_=!1,w={point:a,lineStart:s,lineEnd:l,polygonStart:function(){w.point=c,w.lineStart=h,w.lineEnd=f,p=[],d=[]},polygonEnd:function(){w.point=a,w.lineStart=s,w.lineEnd=l,p=io(p);var t=hs(d,m);p.length?(_||(i.polygonStart(),_=!0),ls(p,ue,t,e,i)):t&&(_||(i.polygonStart(),_=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),_&&(i.polygonEnd(),_=!1),p=d=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}};return w}};fs(function(){return!0},se,ce,[-$u,-Ju]);var ds=(os(30*ts),he(function(t){return as(2/(1+t))}));ds.invert=fe(function(t){return 2*Kn(t/2)});var ps=he(function(t){return(t=Qn(t))&&t/is(t)});ps.invert=fe(function(t){return t});var gs=function(t){var n,e,r,o,i=this,a=[i];do for(n=a.reverse(),a=[];i=n.pop();)if(t(i),e=i.children)for(r=0,o=e.length;r=0;--e)o.push(n[e]);return this},ms=function(t){for(var n,e,r,o=this,i=[o],a=[];o=i.pop();)if(a.push(o),n=o.children)for(e=0,r=n.length;e=0;)e+=r[o].value;n.value=e})},xs=function(t){return this.eachBefore(function(n){n.children&&n.children.sort(t)})},_s=function(t){for(var n=this,e=de(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var o=r.length;t!==e;)r.splice(o,0,t),t=t.parent;return r},ws=function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},bs=function(){var t=[];return this.each(function(n){t.push(n)}),t},Ms=function(){var t=[];return this.eachBefore(function(n){n.children||t.push(n)}),t},Ts=function(){var t=this,n=[];return t.each(function(e){e!==t&&n.push({source:e.parent,target:e})}),n};xe.prototype=pe.prototype={constructor:xe,each:gs,eachAfter:ms,eachBefore:ys,sum:vs,sort:xs,path:_s,ancestors:ws,descendants:bs,leaves:Ms,links:Ts,copy:ge};_e.prototype=Object.create(xe.prototype);var ks=([].slice,{}),zs=function(t,n){function r(t){var n,e=c.status;if(!e&&Se(c)||e>=200&&e<300||304===e){if(a)try{n=a.call(o,c)}catch(t){return void s.call("error",o,t)}else n=c;s.call("load",o,n)}else s.call("error",o,t)}var o,i,a,u,s=e("beforesend","progress","load","error"),l=Ln(),c=new XMLHttpRequest,h=null,f=null,d=0;if("undefined"==typeof XDomainRequest||"withCredentials"in c||!/^(http(s)?:)?\/\//.test(t)||(c=new XDomainRequest),"onload"in c?c.onload=c.onerror=c.ontimeout=r:c.onreadystatechange=function(t){c.readyState>3&&r(t)},c.onprogress=function(t){s.call("progress",o,t)},o={header:function(t,n){return t=(t+"").toLowerCase(),arguments.length<2?l.get(t):(null==n?l.remove(t):l.set(t,n+""),o)},mimeType:function(t){return arguments.length?(i=null==t?null:t+"",o):i},responseType:function(t){return arguments.length?(u=t,o):u},timeout:function(t){return arguments.length?(d=+t,o):d},user:function(t){return arguments.length<1?h:(h=null==t?null:t+"",o)},password:function(t){return arguments.length<1?f:(f=null==t?null:t+"",o)},response:function(t){return a=t,o},get:function(t,n){return o.send("GET",t,n)},post:function(t,n){return o.send("POST",t,n)},send:function(n,e,r){return c.open(n,t,!0,h,f),null==i||l.has("accept")||l.set("accept",i+",*/*"),c.setRequestHeader&&l.each(function(t,n){c.setRequestHeader(n,t)}),null!=i&&c.overrideMimeType&&c.overrideMimeType(i),null!=u&&(c.responseType=u),d>0&&(c.timeout=d),null==r&&"function"==typeof e&&(r=e,e=null),null!=r&&1===r.length&&(r=ze(r)),null!=r&&o.on("error",r).on("load",function(t){r(null,t)}),s.call("beforesend",o,c),c.send(null==e?null:e),o},abort:function(){return c.abort(),o},on:function(){var t=s.on.apply(s,arguments);return t===s?o:t}},null!=n){if("function"!=typeof n)throw new Error("invalid callback: "+n);return o.get(n)}return o},Ss=function(t,n){return function(e,r){var o=zs(e).mimeType(t).response(n);if(null!=r){if("function"!=typeof r)throw new Error("invalid callback: "+r);return o.get(r)}return o}};Ss("text/html",function(t){return document.createRange().createContextualFragment(t.responseText)});var Cs=Ss("application/json",function(t){return JSON.parse(t.responseText)});Ss("text/plain",function(t){return t.responseText}),Ss("application/xml",function(t){var n=t.responseXML;if(!n)throw new Error("parse error");return n});var Ns=function(t,n){return function(e,r,o){arguments.length<3&&(o=r,r=null);var i=zs(e).mimeType(t);return i.row=function(t){return arguments.length?i.response(Ce(n,r=t)):r},i.row(r),o?i.get(o):i}};Ns("text/csv",fu),Ns("text/tab-separated-values",pu);var As=Array.prototype,js=As.map,Ds=As.slice,Ls=function(t){return function(){return t}},Es=function(t){return+t},Ys=[0,1],Us=function(t,e,r){var o,i=t[0],a=t[t.length-1],u=n(i,a,null==e?10:e);switch(r=Fu(null==r?",f":r),r.type){case"s":var s=Math.max(Math.abs(i),Math.abs(a));return null!=r.precision||isNaN(o=Iu(u,s))||(r.precision=o),Hu(r,s);case"":case"e":case"g":case"p":case"r":null!=r.precision||isNaN(o=Wu(u,Math.max(Math.abs(i),Math.abs(a))))||(r.precision=o-("e"===r.type));break;case"f":case"%":null!=r.precision||isNaN(o=qu(u))||(r.precision=o-2*("%"===r.type))}return Bu(r)},Xs=new Date,Fs=new Date,Os=Fe(function(){},function(t,n){t.setTime(+t+n)},function(t,n){return n-t});Os.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?Fe(function(n){n.setTime(Math.floor(n/t)*t)},function(n,e){n.setTime(+n+e*t)},function(n,e){return(e-n)/t}):Os:null};var Bs=1e3,Hs=6e4,Ps=36e5,Zs=864e5,qs=6048e5,Is=(Fe(function(t){t.setTime(Math.floor(t/Bs)*Bs)},function(t,n){t.setTime(+t+n*Bs)},function(t,n){return(n-t)/Bs},function(t){return t.getUTCSeconds()}),Fe(function(t){t.setTime(Math.floor(t/Hs)*Hs)},function(t,n){t.setTime(+t+n*Hs)},function(t,n){return(n-t)/Hs},function(t){return t.getMinutes()}),Fe(function(t){var n=t.getTimezoneOffset()*Hs%Ps;n<0&&(n+=Ps),t.setTime(Math.floor((+t-n)/Ps)*Ps+n)},function(t,n){t.setTime(+t+n*Ps)},function(t,n){return(n-t)/Ps},function(t){return t.getHours()}),Fe(function(t){t.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*Hs)/Zs},function(t){return t.getDate()-1})),Ws=Oe(0),Rs=Oe(1),Gs=(Oe(2),Oe(3),Oe(4),Oe(5),Oe(6),Fe(function(t){t.setDate(1),t.setHours(0,0,0,0)},function(t,n){t.setMonth(t.getMonth()+n)},function(t,n){return n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())},function(t){return t.getMonth()}),Fe(function(t){t.setMonth(0,1),t.setHours(0,0,0,0)},function(t,n){t.setFullYear(t.getFullYear()+n)},function(t,n){return n.getFullYear()-t.getFullYear()},function(t){return t.getFullYear()}));Gs.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Fe(function(n){n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)},function(n,e){n.setFullYear(n.getFullYear()+e*t)}):null};var Vs=(Fe(function(t){t.setUTCSeconds(0,0)},function(t,n){t.setTime(+t+n*Hs)},function(t,n){return(n-t)/Hs},function(t){return t.getUTCMinutes()}),Fe(function(t){t.setUTCMinutes(0,0,0)},function(t,n){t.setTime(+t+n*Ps)},function(t,n){return(n-t)/Ps},function(t){return t.getUTCHours()}),Fe(function(t){t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+n)},function(t,n){return(n-t)/Zs},function(t){return t.getUTCDate()-1})),$s=Be(0),Js=Be(1),Qs=(Be(2),Be(3),Be(4),Be(5),Be(6),Fe(function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCMonth(t.getUTCMonth()+n)},function(t,n){return n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())},function(t){return t.getUTCMonth()}),Fe(function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCFullYear(t.getUTCFullYear()+n)},function(t,n){return n.getUTCFullYear()-t.getUTCFullYear()},function(t){return t.getUTCFullYear()}));Qs.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Fe(function(n){n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)},function(n,e){n.setUTCFullYear(n.getUTCFullYear()+e*t)}):null};var Ks,tl,nl,el,rl,ol={"-":"",_:" ",0:"0"},il=/^\s*\d+/,al=/^%/,ul=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;Fr({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});var sl="%Y-%m-%dT%H:%M:%S.%LZ",ll=(Date.prototype.toISOString?Or:el(sl),+new Date("2000-01-01T00:00:00.000Z")?Br:rl(sl),function(t){return t.match(/.{6}/g).map(function(t){return"#"+t})});ll("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf"),ll("393b795254a36b6ecf9c9ede6379398ca252b5cf6bcedb9c8c6d31bd9e39e7ba52e7cb94843c39ad494ad6616be7969c7b4173a55194ce6dbdde9ed6"),ll("3182bd6baed69ecae1c6dbefe6550dfd8d3cfdae6bfdd0a231a35474c476a1d99bc7e9c0756bb19e9ac8bcbddcdadaeb636363969696bdbdbdd9d9d9"),ll("1f77b4aec7e8ff7f0effbb782ca02c98df8ad62728ff98969467bdc5b0d58c564bc49c94e377c2f7b6d27f7f7fc7c7c7bcbd22dbdb8d17becf9edae5"),ua(kt(300,.5,0),kt(-240,.5,1));ua(kt(-100,.75,.35),kt(80,1.5,.8)),ua(kt(260,.75,.35),kt(80,1.5,.8)),kt();Hr.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._context.lineTo(t,n)}}};Wr.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:Ir(this,this._t0,qr(this,this._t0))}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){var e=NaN;if(t=+t,n=+n,t!==this._x1||n!==this._y1){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,Ir(this,qr(this,e=Zr(this,t,n)),e);break;default:Ir(this,this._t0,e=Zr(this,t,n))}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n,this._t0=e}}},(Rr.prototype=Object.create(Wr.prototype)).point=function(t,n){Wr.prototype.point.call(this,n,t)},Gr.prototype={moveTo:function(t,n){this._context.moveTo(n,t)},closePath:function(){this._context.closePath()},lineTo:function(t,n){this._context.lineTo(n,t)},bezierCurveTo:function(t,n,e,r,o,i){this._context.bezierCurveTo(n,t,r,e,i,o)}};oi("body").append("link").attr("href","https://fonts.googleapis.com/css?family=Inconsolata").attr("rel","stylesheet");var cl={svg:{height:650,width:650},axis:{left:70,right:520,top:100,bottom:550,color:"white"},grid:{spacing:10,lineWidth:.5,color:"#D0D0D0",crosshairs:{opacity:.06,color:"gray",label:{font:"sans-serif",fontSize:"10px",padX:4,padY:11,duration:200}}},shadow:{dx:5,dy:5,std:8,scale:.2},legend:{left:70,right:520,top:565,bottom:590,rx:10,ry:10,padX:15,padY:5,fill:"none",stroke:"none",font:"sans-serif",fontSize:"10px",rows:2,columns:7,glyph:{width:6,height:6,textX:5,textY:3.5,content:[{idx:0,label:"Positive",group:"c4"},{idx:1,label:"Polar -OH",group:"c7"},{idx:2,label:"Hydrophobic",group:"c0"},{idx:3,label:"Cysteine",group:"c2"},{idx:7,label:"Negative",group:"c5"},{idx:8,label:"Polar -CON",group:"c6"},{idx:9,label:"Aromatic",group:"c1"}]},magnitude:{idx:4,textX:13,textY:3.5,shiftX:43,offsets:[-27,-16,-7,0,5],radii:[6,5,4,3,2]},cmap:{idx:11,leftX:-25,leftY:3.5,rightX:26,rightY:3.5,shiftX:30,height:6,width:42,blocks:7}},logo:{data:[],font:["Inconsolata","sans-serif"],height:25,fontScale:.2,bitScale:4,opacity:1,pad:2,axis:{pad:2,max:Math.log2(20),majorTicks:[0,1,2,3,4],minorTicks:[.5,1.5,2.5],majorLength:2.5,minorLength:1,textX:-6,stroke:"black",strokeWidth:.5},zoom:{height:60,lift:40,width:150,radius:5,fontScale:1.5,duration:100,destroyDuration:150,delay:0,opacity:0,easeFun:Sn,underline:{color:"gray",width:.5,pad:2.5,notchRadius:2.5,notchHeight:3,duration:300,delay:75}}},couplings:{data:[],fill:"#B8B8B8",highlight:"gray",matchColor:"white",stroke:"white",strokeWidth:.5,maxRadius:3.5},times:{globalTick:10,destroyDuration:0,buildDuration:300,matchedTimeThreshold:150},matrix:{x:335,y:650,cellSize:15,opacity:.8,gridColor:"#D0D0D0",gridWidth:.5,textUp:2,textOver:2.5,font:"Inconsolata",fontSize:"20px",background:{fill:"white",stroke:"#D0D0D0",strokeWidth:.5,padRight:19,padTop:19,padLeft:5,padBottom:5,opacity:.8},cscale:Xe().domain([-1,0,1]).range(["#3374FF","white","#FFBE33"])},state:{viewerLoaded:0,x:0,y:0,i:0,j:0,iOld:0,jOld:0,focus:-1,zoomBuilt:0,matchedTime:0,matchedBuilt:0}};cl.aaGroups={".":"gr","-":"gr",G:"c0",A:"c0",I:"c0",V:"c0",L:"c0",M:"c0",F:"c1",Y:"c1",W:"c1",H:"c4",C:"c2",P:"c3",K:"c4",R:"c4",D:"c5",E:"c5",Q:"c6",N:"c6",S:"c7",T:"c7",B:"c8",Z:"c8",X:"c8","?":"c9","*":"c8",U:"bl"},cl.groupColors={gr:"grey",bl:"black",m0:"blue",m1:"red",c0:"#33cc00",c1:"#009900",c2:"#ffff00",c3:"#33cc00",c4:"#cc0000",c5:"#0033ff",c6:"#6600cc",c7:"#0099ff",c8:"#666666",c9:"#999999"},cl.groupOrder=["c0","c1","c2","c3","c4","c5","c6","c7"],cl.plotWidth=function(){return cl.axis.right-cl.axis.left},cl.plotHeight=function(){return cl.axis.bottom-cl.axis.top},cl.iToX=function(t){return cl.axis.left+t*(cl.axis.right-cl.axis.left)/cl.logo.data.length},cl.jToY=function(t){return cl.axis.top+t*(cl.axis.bottom-cl.axis.top)/cl.logo.data.length},cl.focusLength=function(t){return t*(cl.axis.right-cl.axis.left)/cl.logo.data.length},cl.barWidth=function(){return(cl.axis.right-cl.axis.left)/cl.logo.data.length},cl.radiusFun=function(t){return cl.couplings.maxRadius*Math.sqrt(t)},cl.tick=function(){var t=cl.state.i!=cl.state.iOld||cl.state.j!=cl.state.jOld;cl.state.viewerLoaded>0&&(0!=cl.state.matchedBuilt||t?cl.state.matchedTime=0:cl.state.matchedTime+=cl.times.globalTick);var n=cl.state.matchedTime-cl.times.matchedTimeThreshold;n>0&&ncl.axis.top&&cl.state.ycl.axis.left&&cl.state.xcl.times.matchedTimeThreshold;if(cl.state.viewerLoaded>0&&(r||o&&0==cl.state.matchedBuilt)){if(e&&(0==cl.state.matchedBuilt&&o||1==cl.state.matchedBuilt&&r)){cl.state.matchedBuilt=1;for(var i=-1,a=0;a=0&&(u=Vr(cl.state.i,cl.state.j,t[cl.state.focus].i-1,t[cl.state.focus].j-1)-cl.radiusFun(t[cl.state.focus].score)),u>cl.logo.zoom.radius){ii("#legendCmap").transition().attr("opacity",0).delay(0).duration(cl.times.destroyDuration),oi("#matrixBG").transition().attr("opacity",0).delay(0).duration(cl.times.buildDuration);for(var s=0;s<20;s++)for(var l=0;l<20;l++)oi("#disp"+s+"-"+l).transition().style("opacity",0).delay(0).duration(cl.times.destroyDuration),oi("#biC"+s).transition().style("opacity",0).delay(0).duration(cl.times.destroyDuration),oi("#bjC"+l).transition().style("opacity",0).delay(0).duration(cl.times.destroyDuration);cl.state.focus=-1,cl.state.matchedBuilt=0,cl.state.matchedTime=0}if(i>=0&&i!=cl.state.focus){console.log("Zooming at "+(cl.state.i+1)+", "+(cl.state.j+1));for(var s=0;s<20;s++)for(var l=0;l<20;l++)cl.matrix.nodes.cells[s][l].transition().style("opacity",0).delay(0).duration(cl.times.destroyDuration),cl.matrix.nodes.iLabels[s].transition().style("opacity",0),cl.matrix.nodes.jLabels[l].transition().style("opacity",0);cl.state.i+1,cl.state.j+1;cl.couplings.nodes.circles[i].transition().attr("fill",cl.couplings.fill).delay(0).duration(cl.times.buildDuration);var c=cl.iToX(cl.state.i)+cl.matrix.background.padLeft,h=cl.jToY(cl.state.j)+cl.matrix.background.padTop,f=t[i].matrix.length*cl.matrix.cellSize+cl.matrix.background.padRight+cl.matrix.background.padLeft,d=t[i].matrix[0].length*cl.matrix.cellSize+cl.matrix.background.padTop+cl.matrix.background.padBottom;ii("#legendCmap").transition().attr("opacity",1).delay(cl.times.destroyDuration).duration(cl.times.buildDuration),oi("#matrixBG").attr("x",c-cl.matrix.background.padLeft).attr("y",h-cl.matrix.background.padTop).attr("width",0).attr("height",0),oi("#matrixBG").transition().attr("width",f).attr("height",d).attr("opacity",cl.matrix.background.opacity).delay(cl.times.destroyDuration).duration(cl.times.buildDuration);for(var s=0;s=cl.state.i-cl.logo.zoom.radius&&t[a].i-1<=cl.state.i+cl.logo.zoom.radius||t[a].j-1>=cl.state.j-cl.logo.zoom.radius&&t[a].j-1<=cl.state.j+cl.logo.zoom.radius)?cl.couplings.nodes.circles[a].attr("fill",cl.couplings.highlight):cl.couplings.nodes.circles[a].attr("fill",cl.couplings.fill)}if(1==cl.state.zoomBuilt&&!e){console.log("Contracting logo");for(var y=Math.max(0,cl.state.iOld-cl.logo.zoom.radius),m=Math.min(n.length-1,cl.state.iOld+cl.logo.zoom.radius),s=y;s<=m;s++)for(var b=0,l=0;lm)for(var b=0,l=0;lm)for(var b=0,l=0;ln.bits?1:0:au?1:0})}},cl.prepareCouplings=function(){cl.couplings.data.sort(function(t,n){return t.score>n.score?-1:t.scoret&&(t=cl.couplings.data[n].score);for(var n=0;ne&&(e=Math.abs(cl.couplings.data[n].matrix[r][o]));for(var n=0;nn&&(cl.state.viewerLoaded=1)},0);setInterval(cl.tick,cl.times.globalTick)},cl.initialize=function(){var t="",n=oi("#evzoom-viewer");n.empty()||(t=n.node().getAttribute("data-couplings"));for(var e="",r=/([^&=]+)=?([^&]*)/g,o=window.location.search.substring(1);e=r.exec(o);)e.length>2&&"data"==e[1]&&(t=e[2]);console.log("Loading "+t),Cs(t).on("progress",function(){null!=mo&&mo.hasAttribute("loaded")&&console.log("progress",mo.loaded)}).on("load",cl.prepareData).on("error",function(t){console.log("failure!",t)}).get()},cl.initialize()});
diff --git a/evzoom.sublime-project b/evzoom.sublime-project
new file mode 100644
index 0000000..568a013
--- /dev/null
+++ b/evzoom.sublime-project
@@ -0,0 +1,15 @@
+{
+ "folders":
+ [
+ {
+ "path": "."
+ }
+ ],
+ "build_systems":
+ [
+ {
+ "name": "Build",
+ "shell_cmd": "npm run build"
+ }
+ ]
+}
diff --git a/example/evzoom.html b/example/evzoom.html
new file mode 100755
index 0000000..c348cb0
--- /dev/null
+++ b/example/evzoom.html
@@ -0,0 +1,7 @@
+
+
+EVzoom
+
+
+
+
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100755
index 0000000..7b6a566
--- /dev/null
+++ b/package.json
@@ -0,0 +1,29 @@
+{
+ "name": "evzoom",
+ "version": "0.1.0",
+ "description": "",
+ "main": "dist/evzoom.js",
+ "scripts": {
+ "build": "rollup -c && uglifyjs build/evzoom.dev.js -cm > dist/evzoom.js"
+ },
+ "homepage": "https://github.com/debbiemarkslab/EVzoom",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/debbiemarkslab/EVzoom.git"
+ },
+ "bugs": {
+ "url": "https://github.com/debbiemarkslab/EVzoom/issues"
+ },
+ "author": "John Ingraham ",
+ "contributors": [],
+ "license": "",
+ "keywords": [
+ "Coevolution",
+ "Undirected graphical model"
+ ],
+ "devDependencies": {
+ "d3": "^4.0.0",
+ "rollup-plugin-node-resolve": "^2.0.0"
+ },
+ "dependencies": {}
+}
\ No newline at end of file
diff --git a/rollup.config.js b/rollup.config.js
new file mode 100755
index 0000000..be90514
--- /dev/null
+++ b/rollup.config.js
@@ -0,0 +1,9 @@
+import npm from "rollup-plugin-node-resolve";
+
+export default {
+ entry: "src/evzoom.js",
+ dest: "build/evzoom.dev.js",
+ format: "umd",
+ moduleName: "d3",
+ plugins: [npm({jsnext: true})]
+};
\ No newline at end of file
diff --git a/src/README.md b/src/README.md
new file mode 100755
index 0000000..770ea94
--- /dev/null
+++ b/src/README.md
@@ -0,0 +1,17 @@
+
+# Compiling EVzoom
+Note: The following is only required for development. A compiled, ready-to-run version of EVzoom is provided at dist/evzoom.js.
+
+## Install dependencies
+EVzoom is bundled and minified with the Node.js packages `rollup` and `uglifyjs`. After installing Node, these dependencies can be globally installed with
+
+ npm install -g rollup
+ npm install -g uglify-js
+
+## Building
+To build EVzoom, run
+
+ npm install
+ npm run build
+
+This will build evzoom into dist/evzoom.js.
\ No newline at end of file
diff --git a/src/evzoom.js b/src/evzoom.js
new file mode 100755
index 0000000..b202d82
--- /dev/null
+++ b/src/evzoom.js
@@ -0,0 +1,1438 @@
+/**
+ * @file evzoom
+ * @private
+ * @author John Ingraham
+ */
+
+import * as d3 from "d3";
+
+// Utility functions
+function dist(xi, yi, xj, yj) { return Math.sqrt((xi - xj) * (xi - xj) + (yi - yj) * (yi - yj)); }
+
+// Monospace from Google Fonts for Logo text
+d3.select("body")
+ .append("link")
+ .attr("href", "https://fonts.googleapis.com/css?family=Inconsolata")
+ .attr("rel", "stylesheet")
+
+var EVzoom = {
+ svg: {
+ height: 650,
+ width: 650
+ },
+ axis: {
+ left: 70,
+ right: 520,
+ top: 100,
+ bottom: 550,
+ color: "white"
+ },
+ grid: {
+ spacing: 10,
+ lineWidth: 0.5,
+ color: "#D0D0D0",
+ crosshairs: {
+ opacity: 0.06,
+ color: "gray",
+ label: {
+ font: "sans-serif",
+ fontSize: "10px",
+ padX: 4,
+ padY: 11,
+ duration: 200
+ }
+ }
+ },
+ shadow: {
+ dx: 5,
+ dy: 5,
+ std: 8,
+ scale: 0.2
+ },
+ legend: {
+ left: 70,
+ right: 520,
+ top: 565,
+ bottom: 590,
+ rx: 10,
+ ry: 10,
+ padX: 15,
+ padY: 5,
+ fill: "none",
+ stroke: "none",
+ font: "sans-serif",
+ fontSize: "10px",
+ rows: 2,
+ columns: 7,
+ glyph: {
+ width: 6,
+ height: 6,
+ textX: 5,
+ textY: 3.5,
+ content: [
+ {idx: 0, label: "Positive", group: "c4"},
+ {idx: 1, label: "Polar -OH", group: "c7"},
+ {idx: 2, label: "Hydrophobic", group: "c0"},
+ {idx: 3, label: "Cysteine", group: "c2"},
+ {idx: 7, label: "Negative", group: "c5"},
+ {idx: 8, label: "Polar -CON", group: "c6"},
+ {idx: 9, label: "Aromatic", group: "c1"}
+ ]
+ },
+ magnitude: {
+ idx: 4,
+ textX: 13,
+ textY: 3.5,
+ shiftX: 43,
+ offsets: [-27, -16, -7, 0, 5],
+ radii: [6, 5, 4, 3, 2]
+ },
+ cmap: {
+ idx: 11,
+ leftX: -25,
+ leftY: 3.5,
+ rightX: 26,
+ rightY: 3.5,
+ shiftX: 30,
+ height: 6,
+ width: 42,
+ blocks: 7
+ }
+ },
+ logo: {
+ data: [],
+ font: ["Inconsolata", "sans-serif"],
+ height: 25,
+ fontScale: 0.2,
+ bitScale: 4,
+ opacity: 1.0,
+ pad: 2,
+ axis: {
+ pad: 2,
+ max: Math.log2(20),
+ majorTicks: [0, 1, 2, 3, 4],
+ minorTicks: [0.5, 1.5, 2.5],
+ majorLength: 2.5,
+ minorLength: 1,
+ textX: -6,
+ stroke: "black",
+ strokeWidth: 0.5
+ },
+ zoom: {
+ height: 60,
+ lift: 40,
+ width: 150,
+ radius: 5,
+ fontScale: 1.5,
+ duration: 100,
+ destroyDuration: 150,
+ delay: 0,
+ opacity: 0,
+ easeFun: d3.easeCubic,
+ underline: {
+ color: "gray",
+ width: 0.5,
+ pad: 2.5,
+ notchRadius: 2.5,
+ notchHeight: 3,
+ duration: 300,
+ delay: 75
+ }
+ }
+ },
+ couplings: {
+ data: [],
+ fill: "#B8B8B8",
+ highlight: "gray",
+ matchColor: "white",
+ stroke: "white",
+ strokeWidth: 0.5,
+ maxRadius: 3.5
+ },
+ times: {
+ globalTick: 10,
+ destroyDuration: 0,
+ buildDuration: 300,
+ matchedTimeThreshold: 150
+ },
+ matrix: {
+ x: 335,
+ y: 650,
+ cellSize: 15,
+ opacity: 0.8,
+ gridColor: "#D0D0D0",
+ gridWidth: 0.5,
+ textUp: 2,
+ textOver: 2.5,
+ font: "Inconsolata",
+ fontSize: "20px",
+ background: {
+ fill: "white",
+ stroke: "#D0D0D0",
+ strokeWidth: 0.5,
+ padRight: 19,
+ padTop: 19,
+ padLeft: 5,
+ padBottom: 5,
+ opacity: 0.8
+ },
+ cscale: d3.scaleLinear().domain([-1, 0, 1]).range(["#3374FF", "white", "#FFBE33"]) // Orange and Blue
+ // cscale: d3.scaleLinear().domain([-1, 0, 1]).range(["#018AFF", "white", "#FF7601"]) // Mandarin and Light Blue
+ // cscale: d3.scaleLinear().domain([-1, 1]).range(["black", "white"])
+ // cscale: d3.scaleLinear().domain([-1, 0, 1]).range(["#FF01A5", "white", "#01FF5B"]) // Magenta and Lime
+ // cscale: d3.scaleLinear().domain([-2, -0.8, 0, 0.8, 2]).range(["#253259", "#1F4E88", "white", "#E29C29", "#c87711"])
+ // cscale: d3.scaleLinear().domain([-2, -0.8, 0, 0.8, 2]).range(["#253259", "#1F4E88", "white", "#E261A4", "#42124B"])
+ // cscale: d3.scaleLinear().domain([-1, 0, 1]).range(["blue", "white", "orange"])
+ },
+ state: {
+ viewerLoaded: 0,
+ x: 0,
+ y: 0,
+ i: 0,
+ j: 0,
+ iOld: 0,
+ jOld: 0,
+ focus: -1,
+ zoomBuilt: 0,
+ matchedTime: 0,
+ matchedBuilt: 0
+ }
+}
+
+// Color scheme from MSAviewer.org
+EVzoom.aaGroups = { ".":"gr", "-":"gr", "G":"c0", "A":"c0", "I":"c0", "V":"c0",
+ "L":"c0", "M":"c0", "F":"c1", "Y":"c1", "W":"c1", "H":"c4",
+ "C":"c2", "P":"c3", "K":"c4", "R":"c4", "D":"c5", "E":"c5",
+ "Q":"c6", "N":"c6", "S":"c7", "T":"c7", "B":"c8", "Z":"c8",
+ "X":"c8", "?":"c9", "*":"c8", "U":"bl"};
+EVzoom.groupColors = { gr:"grey", bl:"black", m0:"blue", m1:"red", c0:"#33cc00",
+ c1:"#009900", c2:"#ffff00", c3:"#33cc00", c4:"#cc0000",
+ c5:"#0033ff", c6:"#6600cc", c7:"#0099ff", c8:"#666666",
+ c9:"#999999"};
+EVzoom.groupOrder = ["c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7"];
+
+// Functions for the coordinate system
+EVzoom.plotWidth = function() { return EVzoom.axis.right - EVzoom.axis.left; };
+EVzoom.plotHeight = function() { return EVzoom.axis.bottom - EVzoom.axis.top; };
+EVzoom.iToX = function(i) { return EVzoom.axis.left + i * (EVzoom.axis.right - EVzoom.axis.left) / EVzoom.logo.data.length; };
+EVzoom.jToY = function(j) { return EVzoom.axis.top + j * (EVzoom.axis.bottom - EVzoom.axis.top) / EVzoom.logo.data.length; };
+EVzoom.focusLength = function(d) { return d * (EVzoom.axis.right - EVzoom.axis.left) / EVzoom.logo.data.length; };
+EVzoom.barWidth = function() { return (EVzoom.axis.right - EVzoom.axis.left) / EVzoom.logo.data.length; };
+EVzoom.radiusFun = function(r) { return EVzoom.couplings.maxRadius * Math.sqrt(r);}
+
+EVzoom.tick = function() {
+ // Timer for counting things
+ var coordsChanged = ((EVzoom.state.i != EVzoom.state.iOld) || (EVzoom.state.j != EVzoom.state.jOld));
+ if (EVzoom.state.viewerLoaded > 0) {
+ if (EVzoom.state.matchedBuilt == 0 && !coordsChanged) {
+ EVzoom.state.matchedTime += EVzoom.times.globalTick;
+ } else {
+ EVzoom.state.matchedTime = 0;
+ }
+ }
+
+ var matchedDelay = EVzoom.state.matchedTime - EVzoom.times.matchedTimeThreshold;
+ if (matchedDelay > 0 && matchedDelay < EVzoom.times.globalTick) EVzoom.update();
+}
+
+EVzoom.update = function() {
+ var couplings = EVzoom.couplings.data;
+ var logo = EVzoom.logo.data;
+
+ // State changes since last tick
+ var onPlot = EVzoom.state.y > EVzoom.axis.top && EVzoom.state.y < EVzoom.axis.bottom
+ && EVzoom.state.x > EVzoom.axis.left && EVzoom.state.x < EVzoom.axis.right;
+ var coordsChanged = ((EVzoom.state.i != EVzoom.state.iOld) || (EVzoom.state.j != EVzoom.state.jOld));
+ var delayOver = EVzoom.state.matchedTime > EVzoom.times.matchedTimeThreshold;
+
+ if (EVzoom.state.viewerLoaded > 0 && (coordsChanged || (delayOver && EVzoom.state.matchedBuilt == 0))) {
+ // Matrix drawing
+ if (onPlot && (((EVzoom.state.matchedBuilt == 0) && delayOver)
+ || ((EVzoom.state.matchedBuilt == 1) && coordsChanged))) {
+ EVzoom.state.matchedBuilt = 1;
+ // Test if currently focused on contact
+ var match = -1;
+ for (var c = 0; c < couplings.length; c++) {
+ if ((couplings[c].i - 1 == EVzoom.state.i) && (couplings[c].j - 1 == EVzoom.state.j)) match = c;
+ }
+
+ // Destroy if we find something new or we get too far
+ var focusDist = 0;
+ if (EVzoom.state.focus >= 0) {
+ focusDist = dist(EVzoom.state.i, EVzoom.state.j, couplings[EVzoom.state.focus].i - 1, couplings[EVzoom.state.focus].j - 1)
+ - EVzoom.radiusFun(couplings[EVzoom.state.focus].score);
+ }
+ if (focusDist > EVzoom.logo.zoom.radius) {
+ d3.selectAll("#legendCmap")
+ .transition()
+ .attr("opacity", 0)
+ .delay(0)
+ .duration(EVzoom.times.destroyDuration);
+ d3.select("#matrixBG")
+ .transition()
+ .attr("opacity", 0)
+ .delay(0)
+ .duration(EVzoom.times.buildDuration);
+ for (var i = 0; i < 20; i++) {
+ for (var j = 0; j < 20; j++) {
+ d3.select("#" + "disp" + i + "-" + j)
+ .transition()
+ .style("opacity", 0)
+ .delay(0)
+ .duration(EVzoom.times.destroyDuration);
+ d3.select("#" + "biC" + i)
+ .transition()
+ .style("opacity", 0)
+ .delay(0)
+ .duration(EVzoom.times.destroyDuration);
+ d3.select("#" + "bjC" + j)
+ .transition()
+ .style("opacity", 0)
+ .delay(0)
+ .duration(EVzoom.times.destroyDuration);
+ }
+ }
+ EVzoom.state.focus = -1;
+ EVzoom.state.matchedBuilt = 0;
+ EVzoom.state.matchedTime = 0;
+ }
+
+ //======================== Begin Display Widget ==========================\
+ // Expand matrix at new match
+ if ((match >= 0) && (match != EVzoom.state.focus)) {
+ console.log("Zooming at " + (EVzoom.state.i + 1) + ", " + (EVzoom.state.j + 1))
+ // Destroy old
+ for (var i = 0; i < 20; i++) {
+ for (var j = 0; j < 20; j++) {
+ EVzoom.matrix.nodes.cells[i][j]
+ .transition()
+ .style("opacity", 0)
+ .delay(0)
+ .duration(EVzoom.times.destroyDuration);
+ EVzoom.matrix.nodes.iLabels[i]
+ .transition()
+ .style("opacity", 0);
+ EVzoom.matrix.nodes.jLabels[j]
+ .transition()
+ .style("opacity", 0);
+ }
+ }
+ // Build new
+ var ix = EVzoom.state.i + 1;
+ var jx = EVzoom.state.j + 1;
+ EVzoom.couplings.nodes.circles[match]
+ .transition()
+ .attr("fill", EVzoom.couplings.fill)
+ .delay(0)
+ .duration(EVzoom.times.buildDuration);
+
+ // Move display widget
+ var subX = EVzoom.iToX(EVzoom.state.i) + EVzoom.matrix.background.padLeft;
+ var subY = EVzoom.jToY(EVzoom.state.j) + EVzoom.matrix.background.padTop;
+ var matWidth = couplings[match].matrix.length * EVzoom.matrix.cellSize
+ + EVzoom.matrix.background.padRight + EVzoom.matrix.background.padLeft;
+ var matHeight = couplings[match].matrix[0].length * EVzoom.matrix.cellSize
+ + EVzoom.matrix.background.padTop + EVzoom.matrix.background.padBottom;
+ // Background
+ d3.selectAll("#legendCmap")
+ .transition()
+ .attr("opacity", 1)
+ .delay(EVzoom.times.destroyDuration)
+ .duration(EVzoom.times.buildDuration);
+ d3.select("#matrixBG")
+ .attr("x", subX - EVzoom.matrix.background.padLeft)
+ .attr("y", subY - EVzoom.matrix.background.padTop)
+ .attr("width", 0)
+ .attr("height", 0);
+ d3.select("#matrixBG")
+ .transition()
+ .attr("width", matWidth)
+ .attr("height", matHeight)
+ .attr("opacity", EVzoom.matrix.background.opacity)
+ .delay(EVzoom.times.destroyDuration)
+ .duration(EVzoom.times.buildDuration);
+ // Matrix
+ for (var i = 0; i < couplings[match].matrix.length; i++) {
+ for (var j = 0; j < couplings[match].matrix[i].length; j++) {
+ EVzoom.matrix.nodes.cells[i][j]
+ .style("opacity", 0)
+ .attr("x", subX)
+ .attr("y", subY)
+ .attr("width", 0)
+ .attr("height", 0);
+ EVzoom.matrix.nodes.cells[i][j]
+ .transition()
+ .style("opacity", EVzoom.matrix.opacity)
+ .style("stroke", EVzoom.matrix.gridColor)
+ .style("stroke-width", EVzoom.matrix.gridWidth)
+ .style("fill", EVzoom.matrix.cscale(couplings[match].matrix[i][j]))
+ .attr("x", subX + i * EVzoom.matrix.cellSize)
+ .attr("y", subY + j * EVzoom.matrix.cellSize)
+ .attr("width", EVzoom.matrix.cellSize)
+ .attr("height", EVzoom.matrix.cellSize)
+ .delay(EVzoom.times.destroyDuration)
+ .duration(EVzoom.times.buildDuration);
+ // Text move
+ var xshift = subX + i * EVzoom.matrix.cellSize + EVzoom.matrix.textOver;
+ var yshift = subY - EVzoom.matrix.textUp;
+ EVzoom.matrix.nodes.iLabels[i]
+ .attr("transform", "translate(" + xshift + "," + yshift + ")")
+ .text(couplings[match].iC[i])
+ .transition()
+ .style("fill", EVzoom.groupColors[EVzoom.aaGroups[couplings[match].iC[i]]])
+ .style("opacity", 1)
+ .delay(EVzoom.times.destroyDuration)
+ .duration(EVzoom.times.buildDuration);
+ xshift = subX + couplings[match].matrix.length * EVzoom.matrix.cellSize + EVzoom.matrix.textUp;
+ yshift = subY + j * EVzoom.matrix.cellSize + EVzoom.matrix.textOver;
+ EVzoom.matrix.nodes.jLabels[j]
+ .text(couplings[match].jC[j])
+ .attr("transform", "translate(" + xshift + "," + yshift + ") rotate(90)")
+ .transition()
+ .style("fill", EVzoom.groupColors[EVzoom.aaGroups[couplings[match].jC[j]]])
+ .style("opacity", 1)
+ .delay(EVzoom.times.destroyDuration)
+ .duration(EVzoom.times.buildDuration);
+ }
+ }
+ EVzoom.state.focus = match;
+ }
+ }
+ //========================= End Display Widget ===========================
+
+
+ if (coordsChanged) {
+ console.log("Moving focus window")
+ // Move the crosshairs if on the grid
+ if ((EVzoom.state.zoomBuilt == 1) && onPlot) {
+ var starti = Math.max(0, EVzoom.state.i - EVzoom.logo.zoom.radius);
+ var stopi = Math.min(logo.length - 1, EVzoom.state.i + EVzoom.logo.zoom.radius);
+ var startj = Math.max(0, EVzoom.state.j - EVzoom.logo.zoom.radius);
+ var stopj = Math.min(logo.length - 1, EVzoom.state.j + EVzoom.logo.zoom.radius);
+ d3.select("#wVert")
+ .attr("x", EVzoom.iToX(starti))
+ .attr("width", EVzoom.jToY(stopi) - EVzoom.jToY(starti))
+ .attr("opacity", EVzoom.grid.crosshairs.opacity);
+ d3.select("#wHoriz")
+ .attr("y", EVzoom.jToY(startj))
+ .attr("height", EVzoom.jToY(stopj) - EVzoom.jToY(startj))
+ .attr("opacity", EVzoom.grid.crosshairs.opacity);
+ // Label the vertical axis (horizontal crosshair)
+ var jString = EVzoom.map.indices[EVzoom.state.j].toString();
+ if (EVzoom.map.letters[EVzoom.state.j] != "-") {
+ jString += " " + EVzoom.map.letters[EVzoom.state.j].toString();
+ }
+ d3.select("#vZoomIndex")
+ .attr("x", EVzoom.axis.left - EVzoom.grid.crosshairs.label.padX)
+ .attr("y", EVzoom.jToY(EVzoom.state.j))
+ .attr("opacity", 1)
+ .text(jString);
+ // Label the horizontal axis (vertical crosshair)
+ var iString = EVzoom.map.indices[EVzoom.state.i].toString();
+ if (EVzoom.map.letters[EVzoom.state.i] != "-") {
+ iString += " " + EVzoom.map.letters[EVzoom.state.i].toString();
+ }
+ d3.select("#hZoomIndex")
+ .attr("x", EVzoom.iToX(EVzoom.state.i))
+ .attr("y", EVzoom.axis.bottom + EVzoom.grid.crosshairs.label.padY)
+ .attr("opacity", 1)
+ .text(iString);
+ } else {
+ // Hide if off
+ d3.select("#wVert")
+ .attr("opacity", 0);
+ d3.select("#wHoriz")
+ .attr("opacity", 0);
+ d3.select("#vZoomIndex")
+ .transition()
+ .attr("opacity", 0)
+ .duration(EVzoom.grid.crosshairs.label.duration)
+ .delay(0);
+ d3.select("#hZoomIndex")
+ .transition()
+ .attr("opacity", 0)
+ .duration(EVzoom.grid.crosshairs.label.duration)
+ .delay(0);
+ }
+
+ // Highlight the relevant couplings
+ for (var c = 0; c < couplings.length; c++) {
+ if (onPlot &&
+ ((couplings[c].i - 1 >= EVzoom.state.i - EVzoom.logo.zoom.radius && couplings[c].i - 1 <= EVzoom.state.i + EVzoom.logo.zoom.radius) ||
+ (couplings[c].j - 1 >= EVzoom.state.j - EVzoom.logo.zoom.radius && couplings[c].j - 1 <= EVzoom.state.j + EVzoom.logo.zoom.radius))) {
+ EVzoom.couplings.nodes.circles[c]
+ .attr("fill", EVzoom.couplings.highlight);
+ } else {
+ EVzoom.couplings.nodes.circles[c]
+ .attr("fill", EVzoom.couplings.fill);
+ }
+ }
+ }
+
+ if ((EVzoom.state.zoomBuilt == 1) && !onPlot) {
+ console.log("Contracting logo")
+ // Contract Horizontal
+ var starti = Math.max(0, EVzoom.state.iOld - EVzoom.logo.zoom.radius);
+ var stopi = Math.min(logo.length - 1, EVzoom.state.iOld + EVzoom.logo.zoom.radius);
+ for (var i = starti; i <= stopi; i++) {
+ var cumulative = 0;
+ for (var j = 0; j < logo[i].length; j++) {
+ var xshift = EVzoom.iToX(i);
+ var yshift = EVzoom.axis.top - EVzoom.logo.pad - cumulative;
+ var scale = logo[i][j].bits / EVzoom.logo.bitScale;
+ var blockHeight = (logo[i][j].bits / EVzoom.logo.bitScale) * EVzoom.logo.height;
+ // Transition letters
+ EVzoom.logo.nodes.hLetters[i][j]
+ .transition()
+ .attr("transform", "translate(" + xshift + "," + yshift + ") rotate(0) scale(" + EVzoom.logo.fontScale + "," + scale + ")")
+ .duration(EVzoom.logo.zoom.destroyDuration)
+ .delay(EVzoom.logo.zoom.delay);
+ // Transition blocks
+ EVzoom.logo.nodes.hBlocks[i][j]
+ .transition()
+ .attr("opacity", EVzoom.logo.opacity)
+ .attr("x", xshift)
+ .attr("y", yshift - blockHeight)
+ .attr("width", EVzoom.barWidth())
+ .attr("height", blockHeight)
+ .duration(EVzoom.logo.zoom.destroyDuration)
+ .delay(EVzoom.logo.zoom.delay);
+ cumulative = cumulative + blockHeight;
+ }
+ }
+ // Contract Vertical
+ starti = Math.max(0, EVzoom.state.jOld - EVzoom.logo.zoom.radius);
+ stopi = Math.min(logo.length - 1, EVzoom.state.jOld + EVzoom.logo.zoom.radius);
+ for (var i = 0; i < logo.length; i++) {
+ var cumulative = 0;
+ for (var j = 0; j < logo[i].length; j++) {
+ var yshift = EVzoom.jToY(i);
+ var xshift = EVzoom.axis.right + EVzoom.logo.pad + cumulative;
+ var scale = logo[i][j].bits / EVzoom.logo.bitScale;
+ var blockHeight = (logo[i][j].bits / EVzoom.logo.bitScale) * EVzoom.logo.height;
+ // Transitions
+ EVzoom.logo.nodes.vLetters[i][j]
+ .transition()
+ .attr("transform", "translate(" + xshift + "," + yshift + ") rotate(90) scale(" + EVzoom.logo.fontScale + "," + scale + ")")
+ .duration(EVzoom.logo.zoom.destroyDuration)
+ .delay(EVzoom.logo.zoom.delay);
+ // Transition blocks
+ EVzoom.logo.nodes.vBlocks[i][j]
+ .transition()
+ .attr("x", xshift)
+ .attr("y", yshift)
+ .attr("opacity", EVzoom.logo.opacity)
+ .attr("width", blockHeight)
+ .attr("height", EVzoom.barWidth())
+ .duration(EVzoom.logo.zoom.destroyDuration)
+ .delay(EVzoom.logo.zoom.delay);
+ cumulative = cumulative + blockHeight;
+ }
+ }
+ // Destroy zoom lines
+ d3.select("#hZoomLine")
+ .transition()
+ .attr("opacity", 0)
+ .duration(EVzoom.logo.zoom.duration)
+ .delay(EVzoom.logo.zoom.delay);
+ d3.select("#hZoomNotch")
+ .transition()
+ .attr("d", notchPath1)
+ .attr("opacity", 0)
+ .duration(EVzoom.logo.zoom.duration)
+ .delay(EVzoom.logo.zoom.delay);
+ d3.select("#vZoomLine")
+ .transition()
+ .attr("opacity", 0)
+ .duration(EVzoom.logo.zoom.duration)
+ .delay(EVzoom.logo.zoom.delay);
+ d3.select("#vZoomNotch")
+ .transition()
+ .attr("d", notchPath1)
+ .attr("opacity", 0)
+ .duration(EVzoom.logo.zoom.duration)
+ .delay(EVzoom.logo.zoom.delay);
+ EVzoom.state.zoomBuilt = 0;
+ }
+
+ // Logo zooming
+ if (onPlot && coordsChanged) {
+ // Horizontal update
+ // Determine any new positions
+ var starti = Math.max(0, EVzoom.state.i - EVzoom.logo.zoom.radius);
+ var stopi = Math.min(logo.length - 1, EVzoom.state.i + EVzoom.logo.zoom.radius);
+ if (EVzoom.state.i != EVzoom.state.iOld) {
+ /// Expand focused columns
+ var zoomLetterWidth = EVzoom.logo.zoom.width / (1 + 2 * EVzoom.logo.zoom.radius);
+ var xcenter = EVzoom.iToX(EVzoom.state.i);
+ for (var i = starti; i <= stopi; i++) {
+ var cumulative = 0;
+ for (var j = 0; j < logo[i].length; j++) {
+ var xshift = xcenter + (i - EVzoom.state.i - 0.5) * zoomLetterWidth;
+ var yshift = EVzoom.axis.top - EVzoom.logo.zoom.lift - cumulative;
+ var blockHeight = (logo[i][j].bits / EVzoom.logo.bitScale) * EVzoom.logo.zoom.height;
+ var scale = logo[i][j].bits / EVzoom.logo.bitScale * 4;
+ // Transition letters
+ EVzoom.logo.nodes.hLetters[i][j]
+ .transition()
+ .attr("transform", "translate(" + xshift + "," + yshift + ") rotate(0) scale(" + EVzoom.logo.zoom.fontScale + "," + scale + ")")
+ .duration(EVzoom.logo.zoom.duration)
+ .delay(EVzoom.logo.zoom.delay)
+ .ease(EVzoom.logo.zoom.easeFun);
+ // Transition blocks
+ EVzoom.logo.nodes.hBlocks[i][j]
+ .transition()
+ .attr("x", xshift)
+ .attr("y", yshift - blockHeight)
+ // .attr("opacity", 0.4 * Math.abs(i - EVzoom.state.i) / EVzoom.logo.zoom.radius * Math.abs(i - EVzoom.state.i) / EVzoom.logo.zoom.radius)
+ // .attr("opacity", 0.5 / (Math.abs(i - EVzoom.state.i)**2 + 1))
+ // .attr("opacity", (i == EVzoom.state.i ? 0 : 0))
+ .attr("opacity", EVzoom.logo.zoom.opacity)
+ .attr("width", zoomLetterWidth)
+ .attr("height", blockHeight)
+ .duration(EVzoom.logo.zoom.duration)
+ .delay(EVzoom.logo.zoom.delay)
+ .ease(EVzoom.logo.zoom.easeFun);
+ cumulative = cumulative + blockHeight;
+ }
+ }
+ // Contract unfocused columns
+ var oldstarti = Math.max(0, EVzoom.state.iOld - EVzoom.logo.zoom.radius);
+ var oldstopi = Math.min(logo.length - 1, EVzoom.state.iOld + EVzoom.logo.zoom.radius);
+ for (var i = oldstarti; i <= oldstopi; i++) {
+ if (i < starti | i > stopi) {
+ var cumulative = 0;
+ for (var j = 0; j < logo[i].length; j++) {
+ var xshift = EVzoom.iToX(i);
+ var yshift = EVzoom.axis.top - EVzoom.logo.pad - cumulative;
+ var scale = logo[i][j].bits / EVzoom.logo.bitScale;
+ var blockHeight = (logo[i][j].bits / EVzoom.logo.bitScale) * EVzoom.logo.height;
+ // Transition letters
+ EVzoom.logo.nodes.hLetters[i][j]
+ .transition()
+ .attr("transform", "translate(" + xshift + "," + yshift + ") rotate(0) scale(" + EVzoom.logo.fontScale + "," + scale + ")")
+ .duration(EVzoom.logo.zoom.duration)
+ .delay(EVzoom.logo.zoom.delay)
+ .ease(EVzoom.logo.zoom.easeFun);
+ // Transition blocks
+ EVzoom.logo.nodes.hBlocks[i][j]
+ .transition()
+ .attr("x", xshift)
+ .attr("y", yshift - blockHeight)
+ .attr("opacity", EVzoom.logo.opacity)
+ .attr("width", EVzoom.barWidth())
+ .attr("height", blockHeight)
+ .duration(EVzoom.logo.zoom.duration)
+ .delay(EVzoom.logo.zoom.delay)
+ .ease(EVzoom.logo.zoom.easeFun);
+ cumulative = cumulative + blockHeight;
+ }
+ }
+ }
+ // Move the underline
+ var xleft = xcenter + (starti - EVzoom.state.i - 0.5) * zoomLetterWidth;
+ var xright = xcenter + (stopi + 1 - EVzoom.state.i - 0.5) * zoomLetterWidth;
+ var yshift = EVzoom.axis.top - EVzoom.logo.zoom.lift + EVzoom.logo.zoom.underline.pad;
+ d3.select("#hZoomLine")
+ .transition()
+ .attr("x1", xcenter)
+ .attr("x2", xcenter)
+ .attr("y1", yshift)
+ .attr("y2", yshift)
+ .attr("opacity", 1)
+ .duration(0)
+ .delay(0)
+ .transition()
+ .attr("x1", xleft)
+ .attr("x2", xright)
+ .duration(EVzoom.logo.zoom.underline.duration)
+ .delay(EVzoom.logo.zoom.underline.delay);
+ var rad = EVzoom.logo.zoom.underline.notchRadius;
+ var notchPath1 = "M" + (xcenter - rad) + "," + yshift
+ + "L" + (xcenter + rad) + "," + yshift
+ + "L" + xcenter + "," + yshift + "Z";
+ var notchPath2 = "M" + (xcenter - rad) + "," + yshift
+ + "L" + (xcenter + rad) + "," + yshift
+ + "L" + xcenter + "," + (yshift + EVzoom.logo.zoom.underline.notchHeight) + "Z";
+ d3.select("#hZoomNotch")
+ .transition()
+ .attr("d", notchPath1)
+ .attr("opacity", 1)
+ .duration(0)
+ .delay(0)
+ .transition()
+ .attr("d", notchPath2)
+ .duration(EVzoom.logo.zoom.underline.duration)
+ .delay(EVzoom.logo.zoom.underline.delay);
+ }
+
+ // Vertical update
+ // Determine any new positions
+ var starti = Math.max(0, EVzoom.state.j - EVzoom.logo.zoom.radius);
+ var stopi = Math.min(logo.length - 1, EVzoom.state.j + EVzoom.logo.zoom.radius);
+ if (EVzoom.state.j != EVzoom.state.jOld) {
+ var zoomLetterWidth = EVzoom.logo.zoom.width / (1 + 2 * EVzoom.logo.zoom.radius);
+ // Expand focused columns
+ var ycenter = EVzoom.jToY(EVzoom.state.j);
+ for (var i = starti; i <= stopi; i++) {
+ var cumulative = 0;
+ for (var j = 0; j < logo[i].length; j++) {
+ var yshift = ycenter + (i - EVzoom.state.j - 0.5) * zoomLetterWidth;
+ var xshift = EVzoom.axis.right + EVzoom.logo.zoom.lift + cumulative;
+ var blockHeight = (logo[i][j].bits / EVzoom.logo.bitScale) * EVzoom.logo.zoom.height;
+ var scale = logo[i][j].bits / EVzoom.logo.bitScale * 4;
+ // Transitions
+ EVzoom.logo.nodes.vLetters[i][j]
+ .transition()
+ .attr("transform", "translate(" + xshift + "," + yshift + ") rotate(90) scale(" + EVzoom.logo.zoom.fontScale + "," + scale + ")")
+ .duration(EVzoom.logo.zoom.duration)
+ .delay(EVzoom.logo.zoom.delay)
+ .ease(EVzoom.logo.zoom.easeFun);
+ // Transition blocks
+ EVzoom.logo.nodes.vBlocks[i][j]
+ .transition()
+ .attr("x", xshift)
+ .attr("y", yshift)
+ .attr("opacity", EVzoom.logo.zoom.opacity)
+ .attr("width", blockHeight)
+ .attr("height", zoomLetterWidth)
+ .duration(EVzoom.logo.zoom.duration)
+ .delay(EVzoom.logo.zoom.delay)
+ .ease(EVzoom.logo.zoom.easeFun);
+ cumulative = cumulative + blockHeight;
+ }
+ }
+ // Contract unfocused columns
+ var oldstarti = Math.max(0, EVzoom.state.jOld - EVzoom.logo.zoom.radius);
+ var oldstopi = Math.min(logo.length - 1, EVzoom.state.jOld + EVzoom.logo.zoom.radius);
+ for (var i = oldstarti; i <= oldstopi; i++) {
+ if (i < starti | i > stopi) {
+ var cumulative = 0;
+ for (var j = 0; j < logo[i].length; j++) {
+ var yshift = EVzoom.jToY(i);
+ var xshift = EVzoom.axis.right + EVzoom.logo.pad + cumulative;
+ var scale = logo[i][j].bits / EVzoom.logo.bitScale;
+ var blockHeight = (logo[i][j].bits / EVzoom.logo.bitScale) * EVzoom.logo.height;
+ // Transitions
+ EVzoom.logo.nodes.vLetters[i][j]
+ .transition()
+ .attr("transform", "translate(" + xshift + "," + yshift + ") rotate(90) scale(" + EVzoom.logo.fontScale + "," + scale + ")")
+ .duration(EVzoom.logo.zoom.duration)
+ .delay(EVzoom.logo.zoom.delay)
+ .ease(EVzoom.logo.zoom.easeFun);
+ // Transition blocks
+ EVzoom.logo.nodes.vBlocks[i][j]
+ .transition()
+ .attr("x", xshift)
+ .attr("y", yshift)
+ .attr("opacity", EVzoom.logo.opacity)
+ .attr("width", blockHeight)
+ .attr("height", EVzoom.barWidth())
+ .duration(EVzoom.logo.zoom.duration)
+ .delay(EVzoom.logo.zoom.delay)
+ .ease(EVzoom.logo.zoom.easeFun);
+ cumulative = cumulative + blockHeight;
+ }
+ }
+ }
+ // Move the underline
+ var ytop = ycenter + (starti - EVzoom.state.j - 0.5) * zoomLetterWidth;
+ var ybottom = ycenter + (stopi + 1 - EVzoom.state.j - 0.5) * zoomLetterWidth;
+ var xshift = EVzoom.axis.right + EVzoom.logo.zoom.lift - EVzoom.logo.zoom.underline.pad;
+ // console.log([ytop, ybottom])
+ d3.select("#vZoomLine")
+ .transition()
+ .attr("x1", xshift)
+ .attr("x2", xshift)
+ .attr("y1", ycenter)
+ .attr("y2", ycenter)
+ .attr("opacity", 1)
+ .duration(0)
+ .delay(0)
+ .transition()
+ .attr("y1", ytop)
+ .attr("y2", ybottom)
+ .duration(EVzoom.logo.zoom.underline.duration)
+ .delay(EVzoom.logo.zoom.underline.delay);
+ var rad = EVzoom.logo.zoom.underline.notchRadius;
+ var notchPath1 = "M" + xshift + "," + (ycenter - rad)
+ + "L" + xshift + "," + (ycenter + rad)
+ + "L" + xshift + "," + ycenter + "Z";
+ var notchPath2 = "M" + xshift + "," + (ycenter - rad)
+ + "L" + xshift + "," + (ycenter + rad)
+ + "L" + (xshift - EVzoom.logo.zoom.underline.notchHeight) + "," + ycenter + "Z";
+ d3.select("#vZoomNotch")
+ .transition()
+ .attr("d", notchPath1)
+ .attr("opacity", 1)
+ .duration(0)
+ .delay(0)
+ .transition()
+ .attr("d", notchPath2)
+ .duration(EVzoom.logo.zoom.underline.duration)
+ .delay(EVzoom.logo.zoom.underline.delay);
+ }
+ EVzoom.state.zoomBuilt = 1;
+ }
+ }
+ // Update state
+ EVzoom.state.iOld = EVzoom.state.i;
+ EVzoom.state.jOld = EVzoom.state.j;
+} // End of EVzoom.update()
+
+EVzoom.focusIJ = function() {
+ var L = EVzoom.logo.data.length;
+ var ix = Math.floor((EVzoom.state.x - EVzoom.axis.left) / (EVzoom.axis.right - EVzoom.axis.left) * L);
+ var jx = Math.floor((EVzoom.state.y - EVzoom.axis.top) / (EVzoom.axis.bottom - EVzoom.axis.top) * L);
+ var closest = 0;
+ var best = L + 1;
+ // Find closest i,j
+ var couplings = EVzoom.couplings.data;
+ for (var c = 0; c < couplings.length; c++) {
+ var edgeDist = dist(ix, jx, couplings[c].i - 1, couplings[c].j - 1) - EVzoom.radiusFun(couplings[c].score);
+ if (edgeDist < best) {
+ best = edgeDist;
+ closest = c;
+ }
+ }
+ EVzoom.state.i = couplings[closest].i - 1;
+ EVzoom.state.j = couplings[closest].j - 1;
+ EVzoom.update();
+}
+
+EVzoom.mouseMove = function() {
+ var mouse = d3.mouse(this);
+ EVzoom.state.x = mouse[0];
+ EVzoom.state.y = mouse[1];
+ var L = EVzoom.logo.data.length;
+ var ix = Math.floor((EVzoom.state.x - EVzoom.axis.left) / (EVzoom.axis.right - EVzoom.axis.left) * L);
+ var jx = Math.floor((EVzoom.state.y - EVzoom.axis.top) / (EVzoom.axis.bottom - EVzoom.axis.top) * L);
+ EVzoom.state.i = ix;
+ EVzoom.state.j = jx;
+
+ // Snappy snapping
+ var closest = 0;
+ var best = L + 1;
+ // Find closest i,j
+ var couplings = EVzoom.couplings.data;
+ for (var c = 0; c < couplings.length; c++) {
+ var edgeDist = dist(ix, jx, couplings[c].i - 1, couplings[c].j - 1) - EVzoom.radiusFun(couplings[c].score);
+ if (edgeDist < best) {
+ best = edgeDist;
+ closest = c;
+ }
+ }
+ if (best < 0) {
+ EVzoom.state.i = couplings[closest].i - 1;
+ EVzoom.state.j = couplings[closest].j - 1;
+ }
+ // console.log([ix, jx]);
+ EVzoom.update();
+}
+
+EVzoom.buildSVG = function() {
+ var logo = EVzoom.logo.data;
+ var couplings = EVzoom.couplings.data;
+
+ // Set up canvas
+ var plot = d3.select("#evzoom-viewer")
+ .append("svg")
+ .attr("width", EVzoom.svg.width)
+ .attr("height", EVzoom.svg.height)
+ .attr("overflow", "visible")
+ .on("mousemove", EVzoom.mouseMove);
+
+ // Draw axis
+ var axis = plot.append("rect")
+ .attr("x", EVzoom.iToX(0))
+ .attr("y", EVzoom.jToY(0))
+ .attr("fill", EVzoom.axis.color)
+ .attr("stroke","white")
+ .attr("width", EVzoom.plotWidth())
+ .attr("height", EVzoom.plotHeight());
+
+ // Filter for drop shadows
+ EVzoom.shadow.filter = plot.append("defs")
+ .append("filter")
+ .attr("id", "drop-shadow")
+ .attr("x", "-50%")
+ .attr("y", "-50%")
+ .attr("width", "200%")
+ .attr("height", "200%");
+ EVzoom.shadow.filter.append("feOffset")
+ .attr("in", "SourceAlpha")
+ .attr("dx", EVzoom.shadow.dx)
+ .attr("dy", EVzoom.shadow.dy)
+ .attr("result", "offsetAlpha");
+ EVzoom.shadow.filter.append("feGaussianBlur")
+ .attr("in", "offsetAlpha")
+ .attr("stdDeviation", EVzoom.shadow.std)
+ .attr("result", "blur-out");
+ EVzoom.shadow.filter.append("feColorMatrix")
+ .attr("in", "blur-out")
+ .attr("values", "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 " + EVzoom.shadow.scale + " 0")
+ .attr("result","shadow")
+ EVzoom.shadow.filter.append("feBlend")
+ .attr("in", "SourceGraphic")
+ .attr("in2", "shadow")
+ .attr("mode", "normal");
+
+ // Draw gridlines
+ for (var i = 0; i < EVzoom.logo.data.length; i += EVzoom.grid.spacing) {
+ // Horizontal
+ plot.append("line")
+ .attr("x1", EVzoom.axis.left)
+ .attr("y1", EVzoom.jToY(i))
+ .attr("x2", EVzoom.axis.right)
+ .attr("y2", EVzoom.jToY(i))
+ .attr("stroke", EVzoom.grid.color)
+ .attr("stroke-width", EVzoom.grid.lineWidth);
+
+ // Vertical
+ plot.append("line")
+ .attr("x1", EVzoom.iToX(i))
+ .attr("y1", EVzoom.axis.top)
+ .attr("x2", EVzoom.iToX(i))
+ .attr("y2", EVzoom.axis.bottom)
+ .attr("stroke", EVzoom.grid.color)
+ .attr("stroke-width", EVzoom.grid.lineWidth);
+ }
+ // Horizontal Bottom
+ plot.append("line")
+ .attr("x1", EVzoom.axis.left)
+ .attr("x2", EVzoom.axis.right)
+ .attr("y1", EVzoom.jToY(0) + EVzoom.plotHeight())
+ .attr("y2", EVzoom.jToY(0) + EVzoom.plotHeight())
+ .attr("stroke", EVzoom.grid.color)
+ .attr("stroke-width", EVzoom.grid.lineWidth);
+ // Vertical Right
+ plot.append("line")
+ .attr("x1", EVzoom.iToX(0) + EVzoom.plotWidth())
+ .attr("x2", EVzoom.iToX(0) + EVzoom.plotWidth())
+ .attr("y1", EVzoom.axis.top)
+ .attr("y2", EVzoom.axis.bottom)
+ .attr("stroke", EVzoom.grid.color)
+ .attr("stroke-width", EVzoom.grid.lineWidth);
+ // Draw crosshairs
+ plot.append("rect")
+ .attr("id","wVert")
+ .attr("x", EVzoom.iToX(0))
+ .attr("y", EVzoom.jToY(0))
+ .attr("width", EVzoom.focusLength(2 * EVzoom.logo.zoom.radius + 1))
+ .attr("height", EVzoom.plotHeight())
+ .attr("opacity", 0)
+ .attr("fill", EVzoom.grid.crosshairs.color)
+ .attr("stroke","none");
+ plot.append("rect")
+ .attr("id","wHoriz")
+ .attr("x", EVzoom.iToX(0))
+ .attr("y", EVzoom.jToY(0))
+ .attr("width", EVzoom.plotWidth())
+ .attr("height", EVzoom.focusLength(2 * EVzoom.logo.zoom.radius + 1))
+ .attr("opacity", 0)
+ .attr("fill", EVzoom.grid.crosshairs.color)
+ .attr("stroke", "none");
+ // Text
+ var labelX = 0;
+ var labelY = 0;
+ plot.append("text")
+ .attr("id", "vZoomIndex")
+ .attr("font-family", EVzoom.grid.crosshairs.label.font)
+ .attr("font-size", EVzoom.grid.crosshairs.label.fontSize)
+ .attr("opacity", 0)
+ .attr("text-anchor", "end")
+ .attr("x", labelX)
+ .attr("y", labelY)
+ .text("0");
+ plot.append("text")
+ .attr("id", "hZoomIndex")
+ .attr("font-family", EVzoom.grid.crosshairs.label.font)
+ .attr("font-size", EVzoom.grid.crosshairs.label.fontSize)
+ .attr("opacity", 0)
+ .attr("text-anchor", "middle")
+ .attr("x", labelX)
+ .attr("y", labelY)
+ .text("0");
+
+ // Draw couplings
+ EVzoom.couplings.nodes = {};
+ EVzoom.couplings.nodes.circles = [];
+ EVzoom.couplings.maxRadius = 1.7 * EVzoom.focusLength(1);
+ console.log(EVzoom.focusLength(1))
+ for (var c = 0; c < couplings.length; c++) {
+ var node = plot.append("circle")
+ .attr("id", "c" + couplings[c].i + "-" + couplings[c].j)
+ .attr("cx", EVzoom.iToX(couplings[c].i - 1))
+ .attr("cy", EVzoom.jToY(couplings[c].j - 1))
+ .attr("fill", EVzoom.couplings.fill)
+ .attr("stroke", EVzoom.couplings.stroke)
+ .attr("stroke-width", EVzoom.couplings.strokeWidth)
+ .attr("r", 0)
+ .on("mouseover", EVzoom.focusIJ());
+ EVzoom.couplings.nodes.circles.push(node);
+ }
+
+ // Logo Lines
+ plot.append("line")
+ .attr("id", "hZoomLine")
+ .attr("x1", EVzoom.iToX(0))
+ .attr("x2", EVzoom.iToX(0))
+ .attr("y1", EVzoom.jToY(0))
+ .attr("y2", EVzoom.jToY(0))
+ .attr("stroke", EVzoom.logo.zoom.underline.color)
+ .attr("stroke-width", EVzoom.logo.zoom.underline.width)
+ .attr("opacity", 0);
+ plot.append("path")
+ .attr("id", "hZoomNotch")
+ .attr("d", "M0,0L0,0L0,0Z")
+ .attr("fill", EVzoom.logo.zoom.underline.color)
+ .attr("stroke", EVzoom.logo.zoom.underline.color)
+ .attr("stroke-width", EVzoom.logo.zoom.underline.width)
+ .attr("opacity", 0);
+ plot.append("line")
+ .attr("id", "vZoomLine")
+ .attr("x1", EVzoom.iToX(0))
+ .attr("x2", EVzoom.iToX(0))
+ .attr("y1", EVzoom.jToY(0))
+ .attr("y2", EVzoom.jToY(0))
+ .attr("stroke", EVzoom.logo.zoom.underline.color)
+ .attr("stroke-width", EVzoom.logo.zoom.underline.width)
+ .attr("opacity", 0);
+ plot.append("path")
+ .attr("id", "vZoomNotch")
+ .attr("d", "M0,0L0,0L0,0Z")
+ .attr("fill", EVzoom.logo.zoom.underline.color)
+ .attr("stroke", EVzoom.logo.zoom.underline.color)
+ .attr("stroke-width", EVzoom.logo.zoom.underline.width)
+ .attr("opacity", 0);
+
+ // Horizontal logo axis
+ var bitsToHeight = function(bits) {return EVzoom.logo.height * bits / EVzoom.logo.bitScale;}
+ plot.append("line")
+ .attr("x1", EVzoom.axis.left - EVzoom.logo.axis.pad)
+ .attr("x2", EVzoom.axis.left - EVzoom.logo.axis.pad)
+ .attr("y1", EVzoom.axis.top - EVzoom.logo.pad)
+ .attr("y2", EVzoom.axis.top - EVzoom.logo.pad - bitsToHeight(EVzoom.logo.axis.max))
+ .attr("stroke", EVzoom.logo.axis.stroke)
+ .attr("stroke-width", EVzoom.logo.axis.strokeWidth);
+ for (var i = 0; i < EVzoom.logo.axis.majorTicks.length; i++) {
+ var tickY = EVzoom.axis.top - EVzoom.logo.pad - bitsToHeight(EVzoom.logo.axis.majorTicks[i]);
+ plot.append("line")
+ .attr("x1", EVzoom.axis.left - EVzoom.logo.axis.pad)
+ .attr("x2", EVzoom.axis.left - EVzoom.logo.axis.pad - EVzoom.logo.axis.majorLength)
+ .attr("y1", tickY)
+ .attr("y2", tickY)
+ .attr("stroke", EVzoom.logo.axis.stroke)
+ .attr("stroke-width", EVzoom.logo.axis.strokeWidth);
+ }
+ var labelX = EVzoom.axis.left - EVzoom.logo.axis.pad + EVzoom.logo.axis.textX;
+ var labelY = EVzoom.axis.top - EVzoom.logo.pad;
+ plot.append("text")
+ .attr("id", "bitLabel")
+ .attr("font-family", EVzoom.legend.font)
+ .attr("font-size", EVzoom.legend.fontSize)
+ .attr("opacity", 1)
+ .attr("transform", "translate(" + labelX + "," + labelY + ") rotate(-90)")
+ .text("Bits");
+
+ // Logo building
+ EVzoom.logo.nodes = {};
+ // Draw horizontal logo
+ EVzoom.logo.nodes.hLetters = [];
+ for (var i = 0; i < logo.length; i++) {
+ var cumulative = 0;
+ EVzoom.logo.nodes.hLetters.push([]);
+ for (var j = 0; j < logo[i].length; j++) {
+ var xshift = EVzoom.iToX(i);
+ var yshift = EVzoom.axis.top - EVzoom.logo.pad - cumulative;
+ var scale = logo[i][j].bits / EVzoom.logo.bitScale;
+ var blockHeight = (logo[i][j].bits / EVzoom.logo.bitScale) * EVzoom.logo.height;
+ var node = plot.append("text")
+ .attr("id", "hL" + logo[i][j].code + i)
+ .style("fill", EVzoom.groupColors[EVzoom.aaGroups[logo[i][j].code]])
+ .style("font-size", "20px")
+ .style("font-family", EVzoom.logo.font)
+ .attr("transform", "translate(" + xshift + "," + yshift + ") rotate(0) scale(" + EVzoom.logo.fontScale + "," + scale + ")")
+ .text(logo[i][j].code);
+ cumulative = cumulative + blockHeight;
+ EVzoom.logo.nodes.hLetters[i].push(node);
+ }
+ }
+
+ // Draw horizontal blocks
+ EVzoom.logo.nodes.hBlocks = [];
+ for (var i = 0; i < logo.length; i++) {
+ var cumulative = 0;
+ EVzoom.logo.nodes.hBlocks.push([]);
+ for (var j = 0; j < logo[i].length; j++) {
+ var xshift = EVzoom.iToX(i);
+ var yshift = EVzoom.axis.top - EVzoom.logo.pad - cumulative;
+ var scale = logo[i][j].bits / EVzoom.logo.bitScale;
+ var blockHeight = (logo[i][j].bits / EVzoom.logo.bitScale) * EVzoom.logo.height;
+ var node = plot.append("rect")
+ .attr("id", "hB" + logo[i][j].code + i)
+ .style("stroke", "none")
+ .style("fill", EVzoom.groupColors[EVzoom.aaGroups[logo[i][j].code]])
+ .attr("opacity", EVzoom.logo.opacity)
+ .attr("x", xshift)
+ .attr("y", yshift - blockHeight)
+ .attr("width", EVzoom.barWidth())
+ .attr("height", blockHeight);
+ cumulative = cumulative + blockHeight;
+ EVzoom.logo.nodes.hBlocks[i].push(node);
+ }
+ }
+
+ // Draw vertical logo
+ EVzoom.logo.nodes.vLetters = [];
+ for (var i = 0; i < logo.length; i++) {
+ var cumulative = 0;
+ EVzoom.logo.nodes.vLetters.push([]);
+ for (var j = 0; j < logo[i].length; j++) {
+ var yshift = EVzoom.jToY(i);
+ var xshift = EVzoom.axis.right + EVzoom.logo.pad + cumulative;
+ var scale = logo[i][j].bits / EVzoom.logo.bitScale;
+ var blockHeight = (logo[i][j].bits / EVzoom.logo.bitScale) * EVzoom.logo.height;
+ var node = plot.append("text")
+ .attr("id", "vL" + logo[i][j].code + i)
+ .style("fill", EVzoom.groupColors[EVzoom.aaGroups[logo[i][j].code]])
+ .style("font-size", "20px")
+ .style("font-family", EVzoom.logo.font)
+ .attr("transform", "translate(" + xshift + "," + yshift + ") rotate(90) scale(" + EVzoom.logo.fontScale + "," + scale + ")")
+ .text(logo[i][j].code);
+ cumulative = cumulative + blockHeight;
+ EVzoom.logo.nodes.vLetters[i].push(node);
+ }
+ }
+ // Draw vertical blocks
+ EVzoom.logo.nodes.vBlocks = [];
+ for (var i = 0; i < logo.length; i++) {
+ var cumulative = 0;
+ EVzoom.logo.nodes.vBlocks.push([]);
+ for (var j = 0; j < logo[i].length; j++) {
+ var yshift = EVzoom.jToY(i);
+ var xshift = EVzoom.axis.right + EVzoom.logo.pad + cumulative;
+ var scale = logo[i][j].bits / EVzoom.logo.bitScale;
+ var blockHeight = (logo[i][j].bits / EVzoom.logo.bitScale) * EVzoom.logo.height;
+ var node = plot.append("rect")
+ .attr("id", "vB" + logo[i][j].code + i)
+ .style("stroke", "none")
+ .style("fill", EVzoom.groupColors[EVzoom.aaGroups[logo[i][j].code]])
+ .attr("x", xshift)
+ .attr("y", yshift)
+ .attr("width", blockHeight)
+ .attr("height", EVzoom.barWidth());
+ cumulative = cumulative + blockHeight;
+ EVzoom.logo.nodes.vBlocks[i].push(node);
+ }
+ }
+
+ // Draw Legend
+ plot.append("rect")
+ .attr("id", "legend")
+ .attr("x", EVzoom.legend.left)
+ .attr("y", EVzoom.legend.top)
+ .attr("width", EVzoom.legend.right - EVzoom.legend.left)
+ .attr("height", EVzoom.legend.bottom - EVzoom.legend.top)
+ .attr("rx", EVzoom.legend.rx)
+ .attr("ry", EVzoom.legend.ry)
+ .style("stroke", EVzoom.legend.stroke)
+ .style("fill", EVzoom.legend.fill);
+
+ var gridX = function(idx) {
+ return EVzoom.legend.left + EVzoom.legend.padX
+ + (EVzoom.legend.right - EVzoom.legend.left - 2 * EVzoom.legend.padX)
+ * (idx % EVzoom.legend.columns) / (EVzoom.legend.columns - 1);
+ }
+ var gridY = function(idx) {
+ return EVzoom.legend.top + EVzoom.legend.padY
+ + (EVzoom.legend.bottom - EVzoom.legend.top - 2 * EVzoom.legend.padY)
+ * Math.floor(idx / EVzoom.legend.columns) / (EVzoom.legend.rows - 1);
+ }
+
+ for (var i = 0; i < EVzoom.legend.glyph.content.length; i++) {
+ // Glyph
+ plot.append("rect")
+ .attr("id", "legendBox" + i)
+ .style("stroke", "none")
+ .style("fill", EVzoom.groupColors[EVzoom.legend.glyph.content[i].group])
+ .attr("x", gridX(EVzoom.legend.glyph.content[i].idx) - EVzoom.legend.glyph.width / 2)
+ .attr("y", gridY(EVzoom.legend.glyph.content[i].idx) - EVzoom.legend.glyph.height / 2)
+ .attr("width", EVzoom.legend.glyph.width)
+ .attr("height", EVzoom.legend.glyph.height);
+ // Text
+ plot.append("text")
+ .attr("id", "legendText" + i)
+ .attr("x", gridX(EVzoom.legend.glyph.content[i].idx) + EVzoom.legend.glyph.textX)
+ .attr("y", gridY(EVzoom.legend.glyph.content[i].idx) + EVzoom.legend.glyph.textY)
+ .attr("font-family", EVzoom.legend.font)
+ .attr("font-size", EVzoom.legend.fontSize)
+ .text(EVzoom.legend.glyph.content[i].label);
+ }
+ // Couplings magnitude legend
+ var magX = gridX(EVzoom.legend.magnitude.idx) + EVzoom.legend.magnitude.shiftX;
+ var magY = gridY(EVzoom.legend.magnitude.idx);
+ for (var i = 0; i < EVzoom.legend.magnitude.radii.length; i++) {
+ // - EVzoom.legend.magnitude.spread * (i/(EVzoom.legend.magnitude.radii.length - 1) - 0.5);
+ // EVzoom.legend.magnitude.radii[i]
+ plot.append("circle")
+ .attr("id", "legendMagnitudeC" + i)
+ .attr("cx", magX + EVzoom.legend.magnitude.offsets[i])
+ .attr("cy", magY)
+ .attr("fill", EVzoom.couplings.fill)
+ .attr("stroke", EVzoom.couplings.stroke)
+ .attr("r", EVzoom.legend.magnitude.radii[i]);
+ }
+ plot.append("text")
+ .attr("id", "legendMagnitude")
+ .attr("x", magX + EVzoom.legend.magnitude.textX)
+ .attr("y", magY + EVzoom.legend.magnitude.textY)
+ .attr("font-family", EVzoom.legend.font)
+ .attr("font-size", EVzoom.legend.fontSize)
+ .text("Coupling magnitude");
+
+ // Couplings colormap legend
+ var cmapX = gridX(EVzoom.legend.cmap.idx) + EVzoom.legend.cmap.shiftX;
+ var cmapY = gridY(EVzoom.legend.cmap.idx);
+ for (var i = 0; i < EVzoom.legend.cmap.blocks; i++) {
+ var colorIndex = 2 * i / (EVzoom.legend.cmap.blocks - 1) - 1;
+ var blockOffset = (i / (EVzoom.legend.cmap.blocks) - 0.5) * EVzoom.legend.cmap.width;
+ var blockWidth = EVzoom.legend.cmap.width / EVzoom.legend.cmap.blocks;
+ plot.append("rect")
+ .attr("id", "legendCmap")
+ .style("stroke", "none")
+ .style("fill", EVzoom.matrix.cscale(colorIndex))
+ .attr("x", cmapX + blockOffset)
+ .attr("y", cmapY - EVzoom.legend.cmap.height / 2)
+ .attr("width", blockWidth)
+ .attr("height", EVzoom.legend.cmap.height)
+ .attr("opacity", 0);
+ }
+ plot.append("text")
+ .attr("id", "legendCmap")
+ .attr("x", cmapX + EVzoom.legend.cmap.rightX)
+ .attr("y", cmapY + EVzoom.legend.cmap.rightY)
+ .attr("font-family", EVzoom.legend.font)
+ .attr("font-size", EVzoom.legend.fontSize)
+ .attr("opacity", 0)
+ .text("Coupling value");
+
+ // Draw Display widget
+ EVzoom.matrix.nodes = {};
+ plot.append("rect")
+ .attr("id", "matrixBG")
+ .attr("stroke", EVzoom.matrix.background.stroke)
+ .attr("fill", EVzoom.matrix.background.fill)
+ .attr("stroke-width", EVzoom.matrix.background.strokeWidth)
+ .attr("opacity", 0)
+ .attr("x", EVzoom.axis.left)
+ .attr("y", EVzoom.axis.top)
+ .attr("width", 0)
+ .attr("height", 0)
+ .attr("filter", "url(#drop-shadow)");
+ EVzoom.matrix.nodes.cells = [];
+ for (var i = 0; i < 20; i++) {
+ EVzoom.matrix.nodes.cells.push([]);
+ for (var j = 0; j < 20; j++) {
+ var node = plot.append("rect")
+ .attr("id", "disp" + i + "-" + j)
+ .style("stroke", "none")
+ .style("stroke-width", EVzoom.matrix.gridWidth)
+ .style("fill", "gray")
+ .style("opacity", 0)
+ .attr("x", EVzoom.matrix.x + i * EVzoom.matrix.cellSize)
+ .attr("y", EVzoom.matrix.y + j * EVzoom.matrix.cellSize)
+ .attr("width", EVzoom.matrix.cellSize)
+ .attr("height", EVzoom.matrix.cellSize);
+ EVzoom.matrix.nodes.cells[i].push(node);
+ }
+ }
+ EVzoom.matrix.nodes.iLabels = [];
+ for (var i = 0; i < 20; i++) {
+ var xshift = EVzoom.matrix.x + i * EVzoom.matrix.cellSize;
+ var yshift = EVzoom.matrix.y;
+ var node = plot.append("text")
+ .attr("id", "biC" + i)
+ .style("stroke", "none")
+ .style("fill", "gray")
+ .style("opacity", 0)
+ .style("font-size", EVzoom.matrix.fontSize)
+ .style("font-family", EVzoom.matrix.font)
+ .attr("transform", "translate(" + xshift + "," + yshift + ")")
+ .text(" ");
+ EVzoom.matrix.nodes.iLabels.push(node);
+ }
+ EVzoom.matrix.nodes.jLabels = [];
+ for (var j = 0; j < 20; j++) {
+ var xshift = EVzoom.matrix.x + 20 * EVzoom.matrix.cellSize;
+ var yshift = EVzoom.matrix.y + j * EVzoom.matrix.cellSize;
+ var node = plot.append("text")
+ .attr("id", "bjC" + j)
+ .style("stroke", "none")
+ .style("fill", "gray")
+ .style("opacity", 0)
+ .style("font-size", EVzoom.matrix.fontSize)
+ .style("font-family", EVzoom.matrix.font)
+ .attr("transform", "translate(" + xshift + "," + yshift + ") rotate(90)")
+ .text(" ");
+ EVzoom.matrix.nodes.jLabels.push(node);
+ }
+
+ // Animate couplings
+ for (var c = 0; c < couplings.length; c++) {
+ d3.select("#c" + (couplings[c].i) + "-" + (couplings[c].j))
+ .transition()
+ .attr("r", EVzoom.radiusFun(couplings[c].score))
+ .duration(600)
+ .delay(400 + 5 * Math.abs(couplings[c].i - couplings[c].j));
+ }
+}
+
+EVzoom.prepareLogo = function() {
+ // Process logo to sort into groups
+ var logo = EVzoom.logo.data;
+
+ // Tabulate group sizes
+ for (var i = 0; i < logo.length; i++) {
+ var groupSet = [];
+ var bitsSet = [];
+ var indexSet = [];
+ for (var j = 0; j < logo[i].length; j++) {
+ var code = logo[i][j].code;
+ var bits = logo[i][j].bits;
+ var group = EVzoom.aaGroups[code];
+ if (groupSet.indexOf(group) == -1) {
+ groupSet.push(group);
+ bitsSet.push(bits);
+ } else {
+ bitsSet[groupSet.indexOf(group)] += bits;
+ }
+ }
+
+ // Sort by smallest group to largest, internally by bits
+ logo[i].sort(function(a,b) {
+ var groupA = EVzoom.aaGroups[a.code];
+ var groupB = EVzoom.aaGroups[b.code];
+ var bitsA = bitsSet[groupSet.indexOf(groupA)];
+ var bitsB = bitsSet[groupSet.indexOf(groupB)];
+ if (a.code == b.code) {
+ return 0;
+ } else if (groupA == groupB) {
+ if (a.bits < b.bits) {
+ return -1;
+ } else if (a.bits > b.bits) {
+ return 1;
+ } else {
+ return 0;
+ }
+ } else if (bitsA < bitsB) {
+ return -1;
+ } else if (bitsA > bitsB) {
+ return 1;
+ } else {
+ return 0;
+ }
+ })
+ }
+}
+
+EVzoom.prepareCouplings = function() {
+ EVzoom.couplings.data.sort(function(a,b) {
+ if (a.score > b.score) {
+ return -1;
+ } else if (a.score < b.score) {
+ return 1;
+ } else {
+ return 0;
+ }
+ })
+ // Identify largest scale
+ var maxScale = 0;
+ for (var i = 0; i < EVzoom.couplings.data.length; i++) {
+ if (EVzoom.couplings.data[i].score > maxScale) {
+ maxScale = EVzoom.couplings.data[i].score;
+ }
+ }
+ // Normalize coupling scale
+ for (var i = 0; i < EVzoom.couplings.data.length; i++) {
+ EVzoom.couplings.data[i].score =
+ EVzoom.couplings.data[i].score / maxScale;
+ }
+ // Identify coupling magnitude
+ var maxCoupling = 0;
+ for (var i = 0; i < EVzoom.couplings.data.length; i++) {
+ for (var ai = 0; ai < EVzoom.couplings.data[i].matrix.length; ai++) {
+ for (var aj = 0; aj < EVzoom.couplings.data[i].matrix[ai].length; aj++) {
+ if (Math.abs(EVzoom.couplings.data[i].matrix[ai][aj]) > maxCoupling) {
+ maxCoupling = Math.abs(EVzoom.couplings.data[i].matrix[ai][aj]);
+ }
+ }
+ }
+ }
+ // Normalize coupling magnitude
+ for (var i = 0; i < EVzoom.couplings.data.length; i++) {
+ for (var ai = 0; ai < EVzoom.couplings.data[i].matrix.length; ai++) {
+ for (var aj = 0; aj < EVzoom.couplings.data[i].matrix[ai].length; aj++) {
+ EVzoom.couplings.data[i].matrix[ai][aj] =
+ EVzoom.couplings.data[i].matrix[ai][aj] / maxCoupling;
+ }
+ }
+ }
+}
+
+EVzoom.prepareData = function(data) {
+ EVzoom.couplings.data = data["couplings"];
+ EVzoom.logo.data = data["logo"];
+ EVzoom.map = data["map"];
+ console.log("Data loaded");
+ console.log(EVzoom.map)
+
+ EVzoom.prepareLogo();
+ EVzoom.prepareCouplings();
+ EVzoom.buildSVG();
+
+ // Loading timer
+ var LOAD_TIME = 700 + 5 * EVzoom.logo.data.length;
+ var loadTimer = d3.timer(function(elapsed) {
+ if (elapsed > LOAD_TIME) { EVzoom.state.viewerLoaded = 1; }
+ }, 0);
+
+ // Regularly update timer
+ setInterval(EVzoom.tick, EVzoom.times.globalTick);
+}
+
+// Initializer
+EVzoom.initialize = function() {
+ // Build the frame
+
+ // Load the data and then setup the plot
+ var url = "";
+
+ // Option 1) Obtain the data url from a div tag
+ var tags = d3.select("#evzoom-viewer");
+ if (!tags.empty()) {
+ url = tags.node()
+ .getAttribute("data-couplings");
+ }
+
+ // Option 2) Check for a query in the URL
+ var match = "";
+ var queries = /([^&=]+)=?([^&]*)/g;
+ var searchQuery = window.location.search.substring(1);
+ while (match = queries.exec(searchQuery)) {
+ if (match.length > 2 && match[1] == "data") {
+ url = match[2];
+ }
+ }
+
+ // Load the data
+ console.log("Loading " + url)
+ d3.json(url)
+ .on("progress", function() { if (d3.event != null && d3.event.hasAttribute("loaded")) console.log("progress", d3.event.loaded);})
+ .on("load", EVzoom.prepareData)
+ .on("error", function(error) { console.log("failure!", error); })
+ .get();
+}
+
+// Run EVzoom
+EVzoom.initialize();
\ No newline at end of file