block by timelyportfolio 5224572

fork and gist-transform from https://github.com/vlandham/co2_small_multiple

Full Screen

index.html

<!doctype html>
<!--[if lt IE 7]> <html class="no-js ie6 oldie" lang="en"> <![endif]-->
<!--[if IE 7]>    <html class="no-js ie7 oldie" lang="en"> <![endif]-->
<!--[if IE 8]>    <html class="no-js ie8 oldie" lang="en"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">

  <title>CO2 Emissions by Year - Jim Vallandingham</title>
  <meta name="description" content="An example of small multiples with detail zoom">
  <meta name="author" content="Jim Vallandingham">

  <meta name="viewport" content="width=device-width,initial-scale=1">
  <link href='//fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'>

  <!-- CSS concatenated and minified via ant build script-->
  <!-- <link rel="stylesheet" href="css/bootstrap.min.css"> -->
  <link rel="stylesheet" href="styles.css">
  <!-- end CSS-->

  <script src="modernizr-2.0.6.min.js"></script>
</head>

<body>

  <div id="container" class="container">
    <header>
    <h1>C02 Emissions of Current Top Emitters by Year</h1>
    <h2>Values in thousands of metric tons (kt)</h2>
    </header>
    <div id="main" role="main">
      <div id="vis">
        <div id="previews"></div>
        <div id="detail" class="hidden">
          <div id="detail_panel">

          </div>
        </div>
      </div>
    </div>
    <div id="legend">
    </div>
    <footer>
    <p>Created by <a href="//vallandingham.me">Jim Vallandingham</a> | <a href="//vallandingham.me/small_multiples_with_details.html">Blog Post</a> | <a href="//data.worldbank.org/indicator/EN.ATM.CO2E.KT/countries/1W?display=default">Data</a></p>
    </footer>
  </div> <!--! end of #container -->


  <!-- <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script> -->
  <script>window.jQuery || document.write('<script src="//code.jquery.com/jquery-1.7.2.min.js"><\/script>')</script>


  <script defer src="plugins.js"></script>
  <script src="coffee-script.js"></script>
  <script src="//d3js.org/d3.v2.min.js"></script>
  <script src="tooltip.js"></script>
  <script type="text/coffeescript" src="vis.coffee"></script>



  <!--[if lt IE 7 ]>
    <script src="//ajax.googleapis.com/ajax/libs/chrome-frame/1.0.3/CFInstall.min.js"></script>
    <script>window.attachEvent('onload',function(){CFInstall.check({mode:'overlay'})})</script>
  <![endif]-->
  
</body>
</html>

modernizr-2.0.6.js

/* Modernizr 2.0.6 | MIT & BSD
 * Contains: All core tests, html5shiv, yepnope, respond.js. Get your own custom build at www.modernizr.com/download/
 */
;window.Modernizr=function(a,b,c){function I(){e.input=function(a){for(var b=0,c=a.length;b<c;b++)t[a[b]]=a[b]in l;return t}("autocomplete autofocus list placeholder max min multiple pattern required step".split(" ")),e.inputtypes=function(a){for(var d=0,e,f,h,i=a.length;d<i;d++)l.setAttribute("type",f=a[d]),e=l.type!=="text",e&&(l.value=m,l.style.cssText="position:absolute;visibility:hidden;",/^range$/.test(f)&&l.style.WebkitAppearance!==c?(g.appendChild(l),h=b.defaultView,e=h.getComputedStyle&&h.getComputedStyle(l,null).WebkitAppearance!=="textfield"&&l.offsetHeight!==0,g.removeChild(l)):/^(search|tel)$/.test(f)||(/^(url|email)$/.test(f)?e=l.checkValidity&&l.checkValidity()===!1:/^color$/.test(f)?(g.appendChild(l),g.offsetWidth,e=l.value!=m,g.removeChild(l)):e=l.value!=m)),s[a[d]]=!!e;return s}("search tel url email datetime date month week time datetime-local number range color".split(" "))}function G(a,b){var c=a.charAt(0).toUpperCase()+a.substr(1),d=(a+" "+p.join(c+" ")+c).split(" ");return F(d,b)}function F(a,b){for(var d in a)if(k[a[d]]!==c)return b=="pfx"?a[d]:!0;return!1}function E(a,b){return!!~(""+a).indexOf(b)}function D(a,b){return typeof a===b}function C(a,b){return B(o.join(a+";")+(b||""))}function B(a){k.cssText=a}var d="2.0.6",e={},f=!0,g=b.documentElement,h=b.head||b.getElementsByTagName("head")[0],i="modernizr",j=b.createElement(i),k=j.style,l=b.createElement("input"),m=":)",n=Object.prototype.toString,o=" -webkit- -moz- -o- -ms- -khtml- ".split(" "),p="Webkit Moz O ms Khtml".split(" "),q={svg:"http://www.w3.org/2000/svg"},r={},s={},t={},u=[],v=function(a,c,d,e){var f,h,j,k=b.createElement("div");if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:i+(d+1),k.appendChild(j);f=["&shy;","<style>",a,"</style>"].join(""),k.id=i,k.innerHTML+=f,g.appendChild(k),h=c(k,a),k.parentNode.removeChild(k);return!!h},w=function(b){if(a.matchMedia)return matchMedia(b).matches;var c;v("@media "+b+" { #"+i+" { position: absolute; } }",function(b){c=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle).position=="absolute"});return c},x=function(){function d(d,e){e=e||b.createElement(a[d]||"div"),d="on"+d;var f=d in e;f||(e.setAttribute||(e=b.createElement("div")),e.setAttribute&&e.removeAttribute&&(e.setAttribute(d,""),f=D(e[d],"function"),D(e[d],c)||(e[d]=c),e.removeAttribute(d))),e=null;return f}var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return d}(),y,z={}.hasOwnProperty,A;!D(z,c)&&!D(z.call,c)?A=function(a,b){return z.call(a,b)}:A=function(a,b){return b in a&&D(a.constructor.prototype[b],c)};var H=function(c,d){var f=c.join(""),g=d.length;v(f,function(c,d){var f=b.styleSheets[b.styleSheets.length-1],h=f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"",i=c.childNodes,j={};while(g--)j[i[g].id]=i[g];e.touch="ontouchstart"in a||j.touch.offsetTop===9,e.csstransforms3d=j.csstransforms3d.offsetLeft===9,e.generatedcontent=j.generatedcontent.offsetHeight>=1,e.fontface=/src/i.test(h)&&h.indexOf(d.split(" ")[0])===0},g,d)}(['@font-face {font-family:"font";src:url("https://")}',["@media (",o.join("touch-enabled),("),i,")","{#touch{top:9px;position:absolute}}"].join(""),["@media (",o.join("transform-3d),("),i,")","{#csstransforms3d{left:9px;position:absolute}}"].join(""),['#generatedcontent:after{content:"',m,'";visibility:hidden}'].join("")],["fontface","touch","csstransforms3d","generatedcontent"]);r.flexbox=function(){function c(a,b,c,d){a.style.cssText=o.join(b+":"+c+";")+(d||"")}function a(a,b,c,d){b+=":",a.style.cssText=(b+o.join(c+";"+b)).slice(0,-b.length)+(d||"")}var d=b.createElement("div"),e=b.createElement("div");a(d,"display","box","width:42px;padding:0;"),c(e,"box-flex","1","width:10px;"),d.appendChild(e),g.appendChild(d);var f=e.offsetWidth===42;d.removeChild(e),g.removeChild(d);return f},r.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},r.canvastext=function(){return!!e.canvas&&!!D(b.createElement("canvas").getContext("2d").fillText,"function")},r.webgl=function(){return!!a.WebGLRenderingContext},r.touch=function(){return e.touch},r.geolocation=function(){return!!navigator.geolocation},r.postmessage=function(){return!!a.postMessage},r.websqldatabase=function(){var b=!!a.openDatabase;return b},r.indexedDB=function(){for(var b=-1,c=p.length;++b<c;)if(a[p[b].toLowerCase()+"IndexedDB"])return!0;return!!a.indexedDB},r.hashchange=function(){return x("hashchange",a)&&(b.documentMode===c||b.documentMode>7)},r.history=function(){return!!a.history&&!!history.pushState},r.draganddrop=function(){return x("dragstart")&&x("drop")},r.websockets=function(){for(var b=-1,c=p.length;++b<c;)if(a[p[b]+"WebSocket"])return!0;return"WebSocket"in a},r.rgba=function(){B("background-color:rgba(150,255,150,.5)");return E(k.backgroundColor,"rgba")},r.hsla=function(){B("background-color:hsla(120,40%,100%,.5)");return E(k.backgroundColor,"rgba")||E(k.backgroundColor,"hsla")},r.multiplebgs=function(){B("background:url(https://),url(https://),red url(https://)");return/(url\s*\(.*?){3}/.test(k.background)},r.backgroundsize=function(){return G("backgroundSize")},r.borderimage=function(){return G("borderImage")},r.borderradius=function(){return G("borderRadius")},r.boxshadow=function(){return G("boxShadow")},r.textshadow=function(){return b.createElement("div").style.textShadow===""},r.opacity=function(){C("opacity:.55");return/^0.55$/.test(k.opacity)},r.cssanimations=function(){return G("animationName")},r.csscolumns=function(){return G("columnCount")},r.cssgradients=function(){var a="background-image:",b="gradient(linear,left top,right bottom,from(#9f9),to(white));",c="linear-gradient(left top,#9f9, white);";B((a+o.join(b+a)+o.join(c+a)).slice(0,-a.length));return E(k.backgroundImage,"gradient")},r.cssreflections=function(){return G("boxReflect")},r.csstransforms=function(){return!!F(["transformProperty","WebkitTransform","MozTransform","OTransform","msTransform"])},r.csstransforms3d=function(){var a=!!F(["perspectiveProperty","WebkitPerspective","MozPerspective","OPerspective","msPerspective"]);a&&"webkitPerspective"in g.style&&(a=e.csstransforms3d);return a},r.csstransitions=function(){return G("transitionProperty")},r.fontface=function(){return e.fontface},r.generatedcontent=function(){return e.generatedcontent},r.video=function(){var a=b.createElement("video"),c=!1;try{if(c=!!a.canPlayType){c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"');var d='video/mp4; codecs="avc1.42E01E';c.h264=a.canPlayType(d+'"')||a.canPlayType(d+', mp4a.40.2"'),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"')}}catch(e){}return c},r.audio=function(){var a=b.createElement("audio"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"'),c.mp3=a.canPlayType("audio/mpeg;"),c.wav=a.canPlayType('audio/wav; codecs="1"'),c.m4a=a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")}catch(d){}return c},r.localstorage=function(){try{return!!localStorage.getItem}catch(a){return!1}},r.sessionstorage=function(){try{return!!sessionStorage.getItem}catch(a){return!1}},r.webworkers=function(){return!!a.Worker},r.applicationcache=function(){return!!a.applicationCache},r.svg=function(){return!!b.createElementNS&&!!b.createElementNS(q.svg,"svg").createSVGRect},r.inlinesvg=function(){var a=b.createElement("div");a.innerHTML="<svg/>";return(a.firstChild&&a.firstChild.namespaceURI)==q.svg},r.smil=function(){return!!b.createElementNS&&/SVG/.test(n.call(b.createElementNS(q.svg,"animate")))},r.svgclippaths=function(){return!!b.createElementNS&&/SVG/.test(n.call(b.createElementNS(q.svg,"clipPath")))};for(var J in r)A(r,J)&&(y=J.toLowerCase(),e[y]=r[J](),u.push((e[y]?"":"no-")+y));e.input||I(),e.addTest=function(a,b){if(typeof a=="object")for(var d in a)A(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return;b=typeof b=="boolean"?b:!!b(),g.className+=" "+(b?"":"no-")+a,e[a]=b}return e},B(""),j=l=null,a.attachEvent&&function(){var a=b.createElement("div");a.innerHTML="<elem></elem>";return a.childNodes.length!==1}()&&function(a,b){function s(a){var b=-1;while(++b<g)a.createElement(f[b])}a.iepp=a.iepp||{};var d=a.iepp,e=d.html5elements||"abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",f=e.split("|"),g=f.length,h=new RegExp("(^|\\s)("+e+")","gi"),i=new RegExp("<(/*)("+e+")","gi"),j=/^\s*[\{\}]\s*$/,k=new RegExp("(^|[^\\n]*?\\s)("+e+")([^\\n]*)({[\\n\\w\\W]*?})","gi"),l=b.createDocumentFragment(),m=b.documentElement,n=m.firstChild,o=b.createElement("body"),p=b.createElement("style"),q=/print|all/,r;d.getCSS=function(a,b){if(a+""===c)return"";var e=-1,f=a.length,g,h=[];while(++e<f){g=a[e];if(g.disabled)continue;b=g.media||b,q.test(b)&&h.push(d.getCSS(g.imports,b),g.cssText),b="all"}return h.join("")},d.parseCSS=function(a){var b=[],c;while((c=k.exec(a))!=null)b.push(((j.exec(c[1])?"\n":c[1])+c[2]+c[3]).replace(h,"$1.iepp_$2")+c[4]);return b.join("\n")},d.writeHTML=function(){var a=-1;r=r||b.body;while(++a<g){var c=b.getElementsByTagName(f[a]),d=c.length,e=-1;while(++e<d)c[e].className.indexOf("iepp_")<0&&(c[e].className+=" iepp_"+f[a])}l.appendChild(r),m.appendChild(o),o.className=r.className,o.id=r.id,o.innerHTML=r.innerHTML.replace(i,"<$1font")},d._beforePrint=function(){p.styleSheet.cssText=d.parseCSS(d.getCSS(b.styleSheets,"all")),d.writeHTML()},d.restoreHTML=function(){o.innerHTML="",m.removeChild(o),m.appendChild(r)},d._afterPrint=function(){d.restoreHTML(),p.styleSheet.cssText=""},s(b),s(l);d.disablePP||(n.insertBefore(p,n.firstChild),p.media="print",p.className="iepp-printshim",a.attachEvent("onbeforeprint",d._beforePrint),a.attachEvent("onafterprint",d._afterPrint))}(a,b),e._version=d,e._prefixes=o,e._domPrefixes=p,e.mq=w,e.hasEvent=x,e.testProp=function(a){return F([a])},e.testAllProps=G,e.testStyles=v,e.prefixed=function(a){return G(a,"pfx")},g.className=g.className.replace(/\bno-js\b/,"")+(f?" js "+u.join(" "):"");return e}(this,this.document),function(a,b){function u(){r(!0)}a.respond={},respond.update=function(){},respond.mediaQueriesSupported=b;if(!b){var c=a.document,d=c.documentElement,e=[],f=[],g=[],h={},i=30,j=c.getElementsByTagName("head")[0]||d,k=j.getElementsByTagName("link"),l=[],m=function(){var b=k,c=b.length,d=0,e,f,g,i;for(;d<c;d++)e=b[d],f=e.href,g=e.media,i=e.rel&&e.rel.toLowerCase()==="stylesheet",!!f&&i&&!h[f]&&(!/^([a-zA-Z]+?:(\/\/)?(www\.)?)/.test(f)||f.replace(RegExp.$1,"").split("/")[0]===a.location.host?l.push({href:f,media:g}):h[f]=!0);n()},n=function(){if(l.length){var a=l.shift();s(a.href,function(b){o(b,a.href,a.media),h[a.href]=!0,n()})}},o=function(a,b,c){var d=a.match(/@media[^\{]+\{([^\{\}]+\{[^\}\{]+\})+/gi),g=d&&d.length||0,b=b.substring(0,b.lastIndexOf("/")),h=function(a){return a.replace(/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,"$1"+b+"$2$3")},i=!g&&c,j=0,k,l,m,n,o;b.length&&(b+="/"),i&&(g=1);for(;j<g;j++){k=0,i?(l=c,f.push(h(a))):(l=d[j].match(/@media ([^\{]+)\{([\S\s]+?)$/)&&RegExp.$1,f.push(RegExp.$2&&h(RegExp.$2))),n=l.split(","),o=n.length;for(;k<o;k++)m=n[k],e.push({media:m.match(/(only\s+)?([a-zA-Z]+)(\sand)?/)&&RegExp.$2,rules:f.length-1,minw:m.match(/\(min\-width:[\s]*([\s]*[0-9]+)px[\s]*\)/)&&parseFloat(RegExp.$1),maxw:m.match(/\(max\-width:[\s]*([\s]*[0-9]+)px[\s]*\)/)&&parseFloat(RegExp.$1)})}r()},p,q,r=function(a){var b="clientWidth",h=d[b],l=c.compatMode==="CSS1Compat"&&h||c.body[b]||h,m={},n=c.createDocumentFragment(),o=k[k.length-1],s=(new Date).getTime();if(a&&p&&s-p<i)clearTimeout(q),q=setTimeout(r,i);else{p=s;for(var t in e){var u=e[t];if(!u.minw&&!u.maxw||(!u.minw||u.minw&&l>=u.minw)&&(!u.maxw||u.maxw&&l<=u.maxw))m[u.media]||(m[u.media]=[]),m[u.media].push(f[u.rules])}for(var t in g)g[t]&&g[t].parentNode===j&&j.removeChild(g[t]);for(var t in m){var v=c.createElement("style"),w=m[t].join("\n");v.type="text/css",v.media=t,v.styleSheet?v.styleSheet.cssText=w:v.appendChild(c.createTextNode(w)),n.appendChild(v),g.push(v)}j.insertBefore(n,o.nextSibling)}},s=function(a,b){var c=t();if(!!c){c.open("GET",a,!0),c.onreadystatechange=function(){c.readyState==4&&(c.status==200||c.status==304)&&b(c.responseText)};if(c.readyState==4)return;c.send()}},t=function(){var a=!1,b=[function(){return new ActiveXObject("Microsoft.XMLHTTP")},function(){return new XMLHttpRequest}],c=b.length;while(c--){try{a=b[c]()}catch(d){continue}break}return function(){return a}}();m(),respond.update=m,a.addEventListener?a.addEventListener("resize",u,!1):a.attachEvent&&a.attachEvent("onresize",u)}}(this,Modernizr.mq("only all")),function(a,b,c){function k(a){return!a||a=="loaded"||a=="complete"}function j(){var a=1,b=-1;while(p.length- ++b)if(p[b].s&&!(a=p[b].r))break;a&&g()}function i(a){var c=b.createElement("script"),d;c.src=a.s,c.onreadystatechange=c.onload=function(){!d&&k(c.readyState)&&(d=1,j(),c.onload=c.onreadystatechange=null)},m(function(){d||(d=1,j())},H.errorTimeout),a.e?c.onload():n.parentNode.insertBefore(c,n)}function h(a){var c=b.createElement("link"),d;c.href=a.s,c.rel="stylesheet",c.type="text/css";if(!a.e&&(w||r)){var e=function(a){m(function(){if(!d)try{a.sheet.cssRules.length?(d=1,j()):e(a)}catch(b){b.code==1e3||b.message=="security"||b.message=="denied"?(d=1,m(function(){j()},0)):e(a)}},0)};e(c)}else c.onload=function(){d||(d=1,m(function(){j()},0))},a.e&&c.onload();m(function(){d||(d=1,j())},H.errorTimeout),!a.e&&n.parentNode.insertBefore(c,n)}function g(){var a=p.shift();q=1,a?a.t?m(function(){a.t=="c"?h(a):i(a)},0):(a(),j()):q=0}function f(a,c,d,e,f,h){function i(){!o&&k(l.readyState)&&(r.r=o=1,!q&&j(),l.onload=l.onreadystatechange=null,m(function(){u.removeChild(l)},0))}var l=b.createElement(a),o=0,r={t:d,s:c,e:h};l.src=l.data=c,!s&&(l.style.display="none"),l.width=l.height="0",a!="object"&&(l.type=d),l.onload=l.onreadystatechange=i,a=="img"?l.onerror=i:a=="script"&&(l.onerror=function(){r.e=r.r=1,g()}),p.splice(e,0,r),u.insertBefore(l,s?null:n),m(function(){o||(u.removeChild(l),r.r=r.e=o=1,j())},H.errorTimeout)}function e(a,b,c){var d=b=="c"?z:y;q=0,b=b||"j",C(a)?f(d,a,b,this.i++,l,c):(p.splice(this.i++,0,a),p.length==1&&g());return this}function d(){var a=H;a.loader={load:e,i:0};return a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=r&&!s,u=s?l:n.parentNode,v=a.opera&&o.call(a.opera)=="[object Opera]",w="webkitAppearance"in l.style,x=w&&"async"in b.createElement("script"),y=r?"object":v||x?"img":"script",z=w?"img":y,A=Array.isArray||function(a){return o.call(a)=="[object Array]"},B=function(a){return Object(a)===a},C=function(a){return typeof a=="string"},D=function(a){return o.call(a)=="[object Function]"},E=[],F={},G,H;H=function(a){function f(a){var b=a.split("!"),c=E.length,d=b.pop(),e=b.length,f={url:d,origUrl:d,prefixes:b},g,h;for(h=0;h<e;h++)g=F[b[h]],g&&(f=g(f));for(h=0;h<c;h++)f=E[h](f);return f}function e(a,b,e,g,h){var i=f(a),j=i.autoCallback;if(!i.bypass){b&&(b=D(b)?b:b[a]||b[g]||b[a.split("/").pop().split("?")[0]]);if(i.instead)return i.instead(a,b,e,g,h);e.load(i.url,i.forceCSS||!i.forceJS&&/css$/.test(i.url)?"c":c,i.noexec),(D(b)||D(j))&&e.load(function(){d(),b&&b(i.origUrl,h,g),j&&j(i.origUrl,h,g)})}}function b(a,b){function c(a){if(C(a))e(a,h,b,0,d);else if(B(a))for(i in a)a.hasOwnProperty(i)&&e(a[i],h,b,i,d)}var d=!!a.test,f=d?a.yep:a.nope,g=a.load||a.both,h=a.callback,i;c(f),c(g),a.complete&&b.load(a.complete)}var g,h,i=this.yepnope.loader;if(C(a))e(a,0,i,0);else if(A(a))for(g=0;g<a.length;g++)h=a[g],C(h)?e(h,0,i,0):A(h)?H(h):B(h)&&b(h,i);else B(a)&&b(a,i)},H.addPrefix=function(a,b){F[a]=b},H.addFilter=function(a){E.push(a)},H.errorTimeout=1e4,b.readyState==null&&b.addEventListener&&(b.readyState="loading",b.addEventListener("DOMContentLoaded",G=function(){b.removeEventListener("DOMContentLoaded",G,0),b.readyState="complete"},0)),a.yepnope=d()}(this,this.document),Modernizr.load=function(){yepnope.apply(window,[].slice.call(arguments,0))};

plugins.js

window.log=function(){log.history=log.history||[];log.history.push(arguments);if(this.console){arguments.callee=arguments.callee.caller;var a=[].slice.call(arguments);(typeof console.log==="object"?log.apply.call(console.log,console,a):console.log.apply(console,a))}};
(function(b){function c(){}for(var d="assert,count,debug,dir,dirxml,error,exception,group,groupCollapsed,groupEnd,info,log,timeStamp,profile,profileEnd,time,timeEnd,trace,warn".split(","),a;a=d.pop();){b[a]=b[a]||c}})((function(){try
{console.log();return window.console;}catch(err){return window.console={};}})());


styles.css

body {
  font-family: 'Open Sans', sans-serif;
  font-weight: 400;
  background: url("https://github.com/vlandham/co2_small_multiple/blob/gh-pages/img/subtle_dots.png") white repeat;
}

a, a:visited {
  color: #555;
}

header {
  position: fixed;
  width: 100%;
  top: 0px;
  left: 0px;
  height: 90px;
  box-shadow: 0px -10px 50px #0E0C08;
  z-index: 100000;
  background: url("https://github.com/vlandham/co2_small_multiple/blob/gh-pages/img/subtle_dots.png") white repeat;
  text-align: center;
}

h1,h2 {
  padding:0 0 0 10px;
  margin:0;
}

h2 {
  color: #555;
}


#vis {
  position: relative;
  width: 800px;
  margin: 0 auto;
  top: 120px;
}

#previews, #detail {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1000;
  padding-bottom: 45px;
}

.preview {
  position: relative;
  float: left;
}

#detail {
  position: fixed;
  top: 128px;
  width: 100%;
  background-color:rgba(255,255,255,0.5);
}

#detail_panel {
  margin: 0px auto;
  width: 800px;
  position: relative;
}

#detail_view {
  width: 800px;
}

.hidden {
  opacity: 0;
  transition: opacity 500ms ease-in;
  -webkit-transition: opacity 500ms ease-in;
  -moz-transition: opacity 500ms ease-in;
  z-index: 0 !important;
}

.visible {
  opacity: 1;
  transition: opacity 500ms ease-in;
  -webkit-transition: opacity 500ms ease-in;
  -moz-transition: opacity 500ms ease-in;
}

.title {
  font-family: 'Open Sans', sans-serif;
  font-weight: 600;
}

.background {
  fill: #e3eded;
}

.mouse_preview {
  pointer-events: all;
  cursor: pointer;
  fill: none;
}

#legend {
  position: fixed;
  top: 150px;
  right: 0px;
  width: 100px;
  height: 300px;
  z-index: 100000;
  overflow: visible;
}

footer {
  background-color: white;
  padding-top: 5px;
  position: fixed;
  text-align: center;
  width: 100%;
  bottom: 0px;
  left: 0px;
  height: 20px;
  box-shadow: 0px 10px 20px #0E0C08;
  z-index: 10000;
  color: #AAAA9A;
  font-size: 15px;
}

footer p {
  margin:0;
  padding:0;
}

tooltip.js

function Tooltip(tooltipId, width){
  var tooltipId = tooltipId;
  $("body").append("<div class='tooltip' id='"+tooltipId+"'></div>");

  if(width){
    $("#"+tooltipId).css("width", width);
  }

  hideTooltip();

  function showTooltip(content, event) {
    $("#"+tooltipId).html(content);
    $("#"+tooltipId).show();

    updatePosition(event);
  }

  function hideTooltip(){
    $("#"+tooltipId).hide();
  }

  function updatePosition(event){
    var ttid = "#"+tooltipId;
    var xOffset = 20;
    var yOffset = 10;

    var toolTipW = $(ttid).width();
    var toolTipeH = $(ttid).height();
    var windowY = $(window).scrollTop();
    var windowX = $(window).scrollLeft();
    var windowW = $(window).width();
    var curX = event.pageX;
    var curY = event.pageY;
    var ttleft = ((curX) < $(window).width() / 2) ? curX - toolTipW - xOffset*2 : curX + xOffset;
    if (ttleft < windowX + xOffset) {
      ttleft = windowX + xOffset;
    } 
    if (ttleft + toolTipW > (windowW - xOffset)) {
      ttleft = windowW - (xOffset*2 + toolTipW);
    }
    var tttop = ((curY - windowY + yOffset*2 + toolTipeH) > $(window).height()) ? curY - toolTipeH - yOffset*2 : curY + yOffset;
    if (tttop < windowY + yOffset){
      tttop = curY + yOffset;
    } 
    $(ttid).css('top', tttop + 'px').css('left', ttleft + 'px');
  }

  return {
    showTooltip: showTooltip,
    hideTooltip: hideTooltip,
    updatePosition: updatePosition
  }
}

vis.coffee

# ---
# Using the 'reusable charts' style closure for 
# encapsulating the visualization code
# ---
SmallMults = () ->
  # ---
  # Variables availible to all of SmallMults
  # ---
  
  # size of the svg's that hold the small multiples 
  width = 200
  height = 160
  # size of the drawing area inside the svg's to make
  # the bar charts
  graphWidth = 180
  graphHeight = 140
  # padding used underneath the bars to make space
  # for the names of the countries
  yPadding = 12
  # placeholder for the data
  data = []

  # using an ordinal scale for X as our
  # data is categorical (the names of countries)
  xScale = d3.scale.ordinal()
    .rangeRoundBands([0, graphWidth], 0.1)

  # names will also be used to color the bars
  colorScale = d3.scale.ordinal()
    .range(["#ff7f0e", "#1f77b4", "#2ca02c", "#d62728", "#8c564b", "#9467bd"])

  # yPadding is removed to make room for country names
  yScale = d3.scale.linear()
    .range([0, graphHeight - yPadding])

  # This is the amount by which we will enlarge the small chart 
  # when displaying it in detail display
  scaleFactor = 4

  # ---
  # Main entry point for our visualization.
  # SVG elements for each small chart are created
  # as well as graph inside each SVG.
  # ---
  chart = (selection) ->
    selection.each (rawData) ->
      # store our data and set the scale domains
      data = rawData
      setScales()
      createLegend()

      # bind data to svg elements so there will be a svg for
      # each year
      pre = d3.select(this).select("#previews")
        .selectAll(".preview").data(data)

      # create the svg elements
      pre.enter()
        .append("div")
        .attr("class", "preview")
        .attr("width", width)
        .attr("height", height)

      svgs = pre.append("svg")
        .attr("width", width)
        .attr("height", height)

      # create a group for displaying the barchart in
      previews = svgs.append("g")
       
      # draw the graphs for each data element.
      # This will call 'drawChart' for each element
      # of the data and will pass in the data as well
      # as the associated group element where the 
      # chart is to be drawn
      previews.each(drawChart)

      # create a rect overlay that will intercept
      # mouse clicks and show detail view of clicked
      # graph
      previews.append("rect")
        .attr("width", graphWidth)
        .attr("height", graphHeight)
        .attr("class", "mouse_preview")
        .on("click", showDetail)

  # ---
  # Code for drawing a single barchart
  # ---
  drawChart = (d,i) ->
    # the 'this' element is the group
    # element which the barchart will
    # live in
    base = d3.select(this)
    base.append("rect")
      .attr("width", graphWidth)
      .attr("height", graphHeight)
      .attr("class", "background")

    # create the bars
    graph = base.append("g")
    graph.selectAll(".bar")
      .data((d) -> d.values)
      .enter().append("rect")
      .attr("x", (d) -> xScale(d.name))
      .attr("y", (d) -> (graphHeight - yScale(d.value) - yPadding))
      .attr("width", xScale.rangeBand())
      .attr("height", (d) ->  yScale(d.value))
      .attr("fill", (d) -> colorScale(d.name))
      .on("mouseover", showAnnotation)
      .on("mouseout", hideAnnotation)

    # add the year title
    graph.append("text")
      .text((d) -> d.year)
      .attr("class", "title")
      .attr("text-anchor", "middle")
      .attr("x", graphWidth / 2)
      .attr("dy", "1.3em")

  # ---
  # This creates the additional text displayed for
  # the detail view.
  # ---
  drawDetails = (d,i) ->
    # like in 'drawChart', 'this'
    # is the group element to draw
    # the details in
    graph = d3.select(this)

    # add names under bars
    graph.selectAll(".name")
      .data(d.values).enter()
      .append("text")
      .attr("class", "name")
      .text((d) -> d.name)
      .attr("text-anchor", "middle")
      .attr("y", graphHeight - yPadding)
      .attr("dy", "1.3em")
      .attr("x", (d) -> xScale(d.name) + xScale.rangeBand() / 2)
      .attr("font-size", 8)

    # add values above bars
    graph.selectAll(".amount")
      .data(d.values).enter()
      .append("text")
      .attr("class", "amount")
      .text((d) -> if d.value == 0 then "No Data" else shortenNumber(d.value))
      .attr("text-anchor", "middle")
      .attr("y", (d) -> (graphHeight - yScale(d.value) - yPadding))
      .attr("dy", (d) -> if yScale(d.value) < 10 then "-0.3em" else "1.1em")
      .attr("x", (d) -> xScale(d.name) + xScale.rangeBand() / 2)
      .attr("font-size", 5)

  # ---
  # Shows the detail view for a given element
  # This works by appending a copy of the graph
  # to the 'detail' svg while switching the
  # detail section to visible
  # ---
  showDetail = (d,i) ->
    # switch the css on which divs are hidden
    toggleHidden(true)
    
    detailView = d3.select("#detail_panel")

    # clear any existing detail view
    detailView.selectAll('svg').remove()

    # bind the single element to be detailed to the 
    # detail view's group
    detailG = detailView.selectAll('svg').data([d,data[data.length-1]]).enter()

    # create a new group to display the graph in
    main = detailG.append("svg")
        .attr("width", 800 )
        .attr("height", 800 )
            .append("g")
            .attr("class", "main")
            .attr("id",(d,i) -> "detail"+i)
            .style('opacity',0)
            

    # draw graph just like in the initial creation
    # of the small multiples
    main.each(drawChart)

    # add details specific to the detail view
    main.each(drawDetails)

    # setup click handler to hide detail view once
    # graph or detail panel is clicked
    main.on("click", () -> hideDetail(d,i))
    d3.select("#detail").on("click", () -> hideDetail(d,i))
   
    # Here is the code responsible for the lovely zoom
    # affect of the detail view
    
    # getPosition is a helper function to
    # return the relative location of the graph
    # to be viewed in the detail view
    pos = getPosition(i)
    # scrollTop returns the number of pixels
    # hidden on the top of the window because of
    # the window being scrolled down
    # http://api.jquery.com/scrollTop/
    scrollTop = $(window).scrollTop()

    # first we move our (small) detail graph to be positioned over
    # its preview version
    d3.select("#detail0")
        .attr('transform', "translate(#{pos.left},#{pos.top - scrollTop})")
        .style('opacity',100)

    # then we use a transition to center the detailed graph and scale it
    # up to be bigger
    main.transition()
      .delay(500)
      .duration(500)
      .attr('transform', "translate(#{40},#{0}) scale(#{scaleFactor/2.2})")

    detailView.selectAll('svg').transition()
        .delay(1000)
        .attr("width", width * scaleFactor / 2 )
        .attr("height", height * scaleFactor / 2 )

    main.transition()
        .delay(1200)
        .style('opacity',100)


  # ---
  # This function shrinks the detail view back from whence it came
  # ---
  hideDetail = (d,i) ->
    # see showDetail for... details
    pos = getPosition(i)
    scrollTop = $(window).scrollTop()

    d3.selectAll('#detail1').style("opacity",0)

    d3.select("#detail_panel").selectAll('svg')
        .attr("width", 800 )
        .attr("height", 800 )
   
    # Use transition to move the detail panel back 
    # down to its preview's location
    # The view also shrinks back to its preview size
    # because d3's transition can tween between the 
    # scale it had, and the lack of scale here.
    d3.selectAll('#detail0').transition()
      .duration(500)
      .attr('transform', "translate(#{pos.left},#{pos.top - scrollTop})")
      .each 'end', () ->
        toggleHidden(false)

  # ---
  # Toggles hidden css between the previews and detail view divs
  # if show is true, the detail view is shown
  # ---
  toggleHidden = (show) ->
    d3.select("#previews").classed("hidden", show).classed("visible", !show)
    d3.select("#detail").classed("hidden", !show).classed("visible", show)

  # ---
  # Add subtitle that indicates what percantage of
  # world wide emissions the country is at that year
  # Serves as example of simple additional interactions
  # in detail view
  # ---
  showAnnotation = (d,i) ->
    d3.selectAll(".main").selectAll(".subtitle").remove()
    
    makesubtitle = (a) ->
      graph = d3.select("#detail" + a)

      g = data.filter((e) -> e.year==Number(d3.select("#detail" + a +  " .title").text()))[0].values.filter((f) -> f.code==d.code)[0]

      graph.selectAll(".subtitle").data([g]).enter()
        .append("text")
        .text("#{formatNumber(g.percent_world * 100)}% of Worldwide Emissions")
        .attr("class", "subtitle")
        .attr("fill", (d) -> colorScale(d.name))
        .attr("text-anchor", "middle")
        .attr("dy", "3.8em")
        .attr("x", (d) -> graphWidth / 2)
        .attr("font-size", 8)
  
    makesubtitle a for a in [0,1]

  # ---
  # remove subtitle
  # ---
  hideAnnotation = (d) ->
    graph = d3.selectAll("#detail_panel .main")
    graph.selectAll(".subtitle").remove()

  # ---
  # Updates domains for scales used in bar charts
  # expects 'data' to be accessible and set to our
  # data.
  # ---
  setScales = () ->
    yMax = d3.max(data, (d) -> d3.max(d.values, (e) -> e.value))
    # this scale is expanded past its max to provide some white space
    # on the top of the bars
    yScale.domain([0,yMax + 500000])

    names = data[0].values.map (d) -> d.name
    xScale.domain(names)
    colorScale.domain(names)

  # ---
  # Helper function to return the position
  # of a preview graph at index i
  # ---
  getPosition = (i) ->
    el = $('.preview')[i]
    # http://api.jquery.com/position/
    pos = $(el).position()
    pos

  createLegend = () ->
    legend = d3.select("#legend")
      .append("svg")
      .attr("width", 100)
      .attr("height", 300)

    keys = legend.selectAll("g")
      .data(data[0].values)
      .enter().append("g")
      .attr("transform", (d,i) -> "translate(#{0},#{40 * (i + 1)})")

    keys.append("rect")
      .attr("width", 30)
      .attr("height", 30)
      .attr("fill", (d) -> colorScale(d.name))

    keys.append("text")
      .text((d) -> d.name)
      .attr("text-anchor", "left")
      .attr("dx", "2.2em")
      .attr("dy", "1.2em")

  return chart

# ---
# General helper functions
# to assist with formatting numbers
# ---

# ---
# converts number to string and
# adds commas
# ---
addCommas = (number) ->
  number += ''
  values = number.split('.')
  num = values[0]
  dec = if values.length > 1 then '.' + values[1] else ''
  rgx = /(\d+)(\d{3})/
  while rgx.test(num)
    num = num.replace(rgx, '$1' + ',' + '$2')
  num + dec

# ---
# round to a specific decimal
# ---
roundNumber = (number, decimals) ->
  Math.round(number * Math.pow(10, decimals)) / Math.pow(10, decimals)

# ---
# add commas and round number
# ---
formatNumber = (number) ->
  addCommas(roundNumber(number,0))

# ---
# Millions -> M
# Thousands -> K
# ---
shortenNumber = (number) ->
  if number > 1000000
    addCommas(roundNumber(number / 1000000,1)) + "M"
  else if number > 1000
    addCommas(roundNumber(number / 1000,0)) + "K"
  else
    addCommas(roundNumber(number,0))

# ---
# Given the div, data, and plot
# this function calls the plot in the
# fashion of the reusable chart example
# http://bost.ocks.org/mike/chart/
# ---
plotData = (selector, data, plot) ->
  d3.select(selector)
    .datum(data)
    .call(plot)

# Document is ready. Lets do this.
$ ->
  plot = SmallMults()
  display = (data) ->
    plotData("#vis", data, plot)

  d3.json("co2_kt_data.json", display)